forked from Fallout-build/Fallout
-
Notifications
You must be signed in to change notification settings - Fork 0
248 lines (240 loc) · 9.92 KB
/
Copy pathrelease.yml
File metadata and controls
248 lines (240 loc) · 9.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# Hand-written (not auto-generated) — see Build.CI.GitHubActions.cs for the
# rationale (lets us bridge GitHub's NUGET_API_KEY secret to Fallout's
# NuGetApiKey parameter, which would otherwise have to share a name).
#
# This is the DELIBERATE (production) release path. The fast test lane —
# main (-preview), push → GitHub Packages — lives in preview.yml. See ADR-0004
# (amended 2026-05-30), as further amended by ADR-0008 (which collapsed the
# former experimental/-alpha lane into main).
#
# Shape:
# - Trigger: tag push `v*` on a production branch — CalVer production lines
# (release/2026 → tag v2026.1.3) or gitflow support lines (support/v10 → v10.x,
# support/2026 → v2026.x). main is NEVER tagged for release.
# Tags keep the `v` prefix so the `v*` tag-protection ruleset applies; the
# package version core is the bare CalVer/semver (e.g. 2026.1.3). Tag
# protection restricts who can create those tags to repo admins.
# - Optional fallback: workflow_dispatch with an existing-tag input, for
# re-runs after a transient publish-API failure, OR to opt into a
# nuget.org publish (see below).
# - validate-ref → test-and-pack → fan out to three publish jobs in parallel:
# - publish-nuget-org (opt-in via workflow_dispatch flag, approval-gated)
# - publish-github-packages (all packages — Fallout.* + Nuke.*)
# - publish-github-releases (artifact bundling on the tag's GH Release)
#
# Channel routing (ADR-0004):
# - nuget.org is OPT-IN. Tag pushes do NOT auto-publish there. To publish
# Fallout.* to nuget.org you invoke workflow_dispatch with
# publish-to-nugetorg=true — a conscious "this release is stabilised enough"
# switch, used when a release/YYYY production line is ready for the broad
# consumer audience, or for a support/v10 legacy security patch.
# - GitHub Packages gets every Fallout.* and Nuke.* build via tag push.
# - GitHub Releases bundles nupkgs on the tag's release page regardless.
#
# See docs/branching-and-release.md for the full runbook.
name: release
on:
push:
tags:
- 'v*'
# Manual fallback for two scenarios:
# 1. Re-running a partial publish after a transient API failure (pick the
# tag, leave publish-to-nugetorg at its default).
# 2. Opting into a nuget.org publish for a stabilised release (pick the
# tag, set publish-to-nugetorg to true). Still gated by the nuget-org
# env approval before the actual push.
# `--skip-duplicate` on each push makes re-runs idempotent.
workflow_dispatch:
inputs:
tag:
description: 'Existing tag to (re-)release (e.g. v11.0.5)'
required: true
publish-to-nugetorg:
description: 'Publish Fallout.* to nuget.org? Default false — opt-in for stabilised releases only.'
required: false
type: boolean
default: false
permissions:
contents: read
jobs:
validate-ref:
name: validate ref
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: 'Verify tag is reachable from a production branch'
run: |
set -euo pipefail
TAG_SHA="${{ github.sha }}"
# Match CalVer production lines (release/2026, …) and gitflow support lines
# (support/v10 legacy semver, support/2026 retired years, …).
REACHABLE=$(git branch -r --contains "$TAG_SHA" | grep -E 'origin/(release/[0-9]{4}|support/(v[0-9]+|[0-9]{4}))' || true)
if [ -z "$REACHABLE" ]; then
echo "::error::Tag ${GITHUB_REF_NAME} at $TAG_SHA is not reachable from any production branch."
echo "Tag-triggered releases only fire from release/YYYY (production) or support/* (legacy/retired) branches."
exit 1
fi
echo "Tag ${GITHUB_REF_NAME} validated. Reachable from:"
echo "$REACHABLE"
test-and-pack:
name: test + pack
runs-on: ubuntu-latest
needs: [validate-ref]
# Run when validate-ref succeeded (tag push) OR was skipped (workflow_dispatch).
if: always() && (needs.validate-ref.result == 'success' || needs.validate-ref.result == 'skipped')
steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.tag || github.ref }}
fetch-depth: 0 # Nerdbank.GitVersioning needs full history
- name: 'Cache: .fallout/temp, ~/.nuget/packages'
uses: actions/cache@v4
with:
path: |
.fallout/temp
~/.nuget/packages
key: ${{ runner.os }}-release-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props', 'version.json') }}
restore-keys: |
${{ runner.os }}-release-
- name: 'Setup: .NET SDK'
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: 'Restore: dotnet tools'
run: dotnet tool restore
- name: 'Run: Test + Pack'
run: dotnet fallout Test Pack
- name: 'Upload: package artifacts'
uses: actions/upload-artifact@v4
with:
name: packages
path: output/packages/*.nupkg
retention-days: 7
if-no-files-found: error
# Tier 1 — production / nuget.org. **OPT-IN ONLY.** Tag pushes do NOT trigger
# this job; you must invoke workflow_dispatch with publish-to-nugetorg=true.
# The env approval gate on `nuget-org` is the second layer — even after opting
# in via the input flag, you still approve the deployment.
#
# The opt-in defaults to false because the default channel is GitHub Packages
# (see header comment). When a release/YYYY production line is ready for the
# broad audience — or for cutting a support/v10 maintenance patch — invoke
# workflow_dispatch with the flag set.
publish-nuget-org:
name: publish → nuget.org
runs-on: ubuntu-latest
needs: [test-and-pack]
if: github.event_name == 'workflow_dispatch' && inputs.publish-to-nugetorg == true
environment:
name: nuget-org
url: https://www.nuget.org/profiles/Fallout
steps:
- name: 'Setup: .NET SDK'
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.x'
- name: 'Download: package artifacts'
uses: actions/download-artifact@v4
with:
name: packages
path: output/packages
- name: 'Push: Fallout.* to nuget.org'
run: |
set -euo pipefail
shopt -s nullglob
packages=(output/packages/Fallout.*.nupkg)
if [ ${#packages[@]} -eq 0 ]; then
echo "::error::No Fallout.* packages found in artifact — nothing to publish."
exit 1
fi
for pkg in "${packages[@]}"; do
echo "Pushing $pkg to nuget.org..."
dotnet nuget push "$pkg" \
--source "https://api.nuget.org/v3/index.json" \
--api-key "${{ secrets.NUGET_API_KEY }}" \
--skip-duplicate
done
# Tier 2 — GitHub Packages. The default release channel. Pushes both
# Fallout.* AND Nuke.* transition shims. The Nuke.* shim IDs are owned by the
# original NUKE maintainer on nuget.org (#47) — GitHub Packages is their
# permanent home. Fallout.* is here because nuget.org is opt-in by default
# (see header).
publish-github-packages:
name: publish → GitHub Packages
runs-on: ubuntu-latest
needs: [test-and-pack]
permissions:
packages: write
environment:
name: github-packages
url: https://github.com/Fallout-build/Fallout/packages
steps:
- name: 'Setup: .NET SDK'
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.x'
- name: 'Download: package artifacts'
uses: actions/download-artifact@v4
with:
name: packages
path: output/packages
- name: 'Push: all *.nupkg to GitHub Packages'
run: |
set -euo pipefail
shopt -s nullglob
packages=(output/packages/*.nupkg)
if [ ${#packages[@]} -eq 0 ]; then
echo "::error::No packages found in artifact — nothing to publish."
exit 1
fi
for pkg in "${packages[@]}"; do
echo "Pushing $pkg to GitHub Packages..."
dotnet nuget push "$pkg" \
--source "https://nuget.pkg.github.com/Fallout-build/index.json" \
--api-key "${{ secrets.GITHUB_TOKEN }}" \
--skip-duplicate
done
# Bundled artifact distribution. Attaches all nupkgs to the GitHub Release
# for the tag. Idempotent: if the release already exists (workflow_dispatch
# retry case), uploads or replaces missing assets via --clobber.
publish-github-releases:
name: publish → GitHub Releases
runs-on: ubuntu-latest
needs: [test-and-pack]
permissions:
contents: write
environment:
name: github-releases
url: https://github.com/Fallout-build/Fallout/releases
steps:
- uses: actions/checkout@v6
- name: 'Download: package artifacts'
uses: actions/download-artifact@v4
with:
name: packages
path: output/packages
- name: 'Create or update GitHub Release with package artifacts'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TAG="${{ inputs.tag }}"
else
TAG="${GITHUB_REF_NAME}"
fi
echo "Tag: $TAG"
if gh release view "$TAG" > /dev/null 2>&1; then
echo "Release $TAG already exists — uploading assets with --clobber."
gh release upload "$TAG" output/packages/*.nupkg --clobber
else
echo "Creating new release $TAG."
gh release create "$TAG" \
--title "$TAG" \
--target "$(git rev-parse HEAD)" \
--generate-notes \
output/packages/*.nupkg
fi