99# * builds artifacts with dist (archives, installers, hashes)
1010# * uploads those artifacts to temporary workflow zip
1111# * on success, uploads the artifacts to a GitHub Release
12+ #
13+ # Note that the GitHub Release will be created with a generated
14+ # title/body based on your changelogs.
1215
1316name : Release
1417permissions :
1518 " contents " : " write"
1619
20+ # This task will run whenever you push a git tag that looks like a version
21+ # like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc.
22+ # Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where
23+ # PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION
24+ # must be a Cargo-style SemVer Version (must have at least major.minor.patch).
25+ #
26+ # If PACKAGE_NAME is specified, then the announcement will be for that
27+ # package (erroring out if it doesn't have the given version or isn't dist-able).
28+ #
29+ # If PACKAGE_NAME isn't specified, then the announcement will be for all
30+ # (dist-able) packages in the workspace with that version (this mode is
31+ # intended for workspaces with only one dist-able package, or with all dist-able
32+ # packages versioned/released in lockstep).
33+ #
34+ # If you push multiple tags at once, separate instances of this workflow will
35+ # spin up, creating an independent announcement for each one. However, GitHub
36+ # will hard limit this to 3 tags per commit, as it will assume more tags is a
37+ # mistake.
38+ #
39+ # If there's a prerelease-style suffix to the version, then the release(s)
40+ # will be marked as a prerelease.
1741on :
1842 pull_request :
1943 push :
@@ -37,13 +61,20 @@ jobs:
3761 persist-credentials : false
3862 submodules : recursive
3963 - name : Install dist
64+ # we specify bash to get pipefail; it guards against the `curl` command
65+ # failing. otherwise `sh` won't catch that `curl` returned non-0
4066 shell : bash
4167 run : " curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.31.0/cargo-dist-installer.sh | sh"
4268 - name : Cache dist
4369 uses : actions/upload-artifact@v6
4470 with :
4571 name : cargo-dist-cache
4672 path : ~/.cargo/bin/dist
73+ # sure would be cool if github gave us proper conditionals...
74+ # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible
75+ # functionality based on whether this is a pull_request, and whether it's from a fork.
76+ # (PRs run on the *source* but secrets are usually on the *target* -- that's *good*
77+ # but also really annoying to build CI around when it needs secrets to work right.)
4778 - id : plan
4879 run : |
4980 dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json
@@ -59,11 +90,22 @@ jobs:
5990 # Build and packages all the platform-specific things
6091 build-local-artifacts :
6192 name : build-local-artifacts (${{ join(matrix.targets, ', ') }})
93+ # Let the initial task tell us to not run (currently very blunt)
6294 needs :
6395 - plan
6496 if : ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }}
6597 strategy :
6698 fail-fast : false
99+ # Target platforms/runners are computed by dist in create-release.
100+ # Each member of the matrix has the following arguments:
101+ #
102+ # - runner: the github runner
103+ # - dist-args: cli flags to pass to dist
104+ # - install-dist: expression to run to install dist on the runner
105+ #
106+ # Typically there will be:
107+ # - 1 "global" task that builds universal installers
108+ # - N "local" tasks that build each platform's binaries and platform-specific installers
67109 matrix : ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }}
68110 runs-on : ${{ matrix.runner }}
69111 container : ${{ matrix.container && matrix.container.image || null }}
87129 fi
88130 - name : Install dist
89131 run : ${{ matrix.install_dist.run }}
132+ # Get the dist-manifest
90133 - name : Fetch local artifacts
91134 uses : actions/download-artifact@v7
92135 with :
@@ -98,12 +141,17 @@ jobs:
98141 ${{ matrix.packages_install }}
99142 - name : Build artifacts
100143 run : |
144+ # Actually do builds and make zips and whatnot
101145 dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json
102146 echo "dist ran successfully"
103147 - id : cargo-dist
104148 name : Post-build
149+ # We force bash here just because github makes it really hard to get values up
150+ # to "real" actions without writing to env-vars, and writing to env-vars has
151+ # inconsistent syntax between shell and powershell.
105152 shell : bash
106153 run : |
154+ # Parse out what we just built and upload it to scratch storage
107155 echo "paths<<EOF" >> "$GITHUB_OUTPUT"
108156 dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT"
109157 echo "EOF" >> "$GITHUB_OUTPUT"
@@ -137,6 +185,7 @@ jobs:
137185 name : cargo-dist-cache
138186 path : ~/.cargo/bin/
139187 - run : chmod +x ~/.cargo/bin/dist
188+ # Get all the local artifacts for the global tasks to use (for e.g. checksums)
140189 - name : Fetch local artifacts
141190 uses : actions/download-artifact@v7
142191 with :
@@ -149,6 +198,7 @@ jobs:
149198 dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json
150199 echo "dist ran successfully"
151200
201+ # Parse out what we just built and upload it to scratch storage
152202 echo "paths<<EOF" >> "$GITHUB_OUTPUT"
153203 jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
154204 echo "EOF" >> "$GITHUB_OUTPUT"
@@ -161,13 +211,13 @@ jobs:
161211 path : |
162212 ${{ steps.cargo-dist.outputs.paths }}
163213 ${{ env.BUILD_MANIFEST_NAME }}
164-
165214 # Determines if we should publish/announce
166215 host :
167216 needs :
168217 - plan
169218 - build-local-artifacts
170219 - build-global-artifacts
220+ # Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine)
171221 if : ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
172222 env :
173223 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
@@ -185,6 +235,7 @@ jobs:
185235 name : cargo-dist-cache
186236 path : ~/.cargo/bin/
187237 - run : chmod +x ~/.cargo/bin/dist
238+ # Fetch artifacts from scratch-storage
188239 - name : Fetch artifacts
189240 uses : actions/download-artifact@v7
190241 with :
@@ -201,8 +252,10 @@ jobs:
201252 - name : " Upload dist-manifest.json"
202253 uses : actions/upload-artifact@v6
203254 with :
255+ # Overwrite the previous copy
204256 name : artifacts-dist-manifest
205257 path : dist-manifest.json
258+ # Create a GitHub Release while uploading all files to it
206259 - name : " Download GitHub Artifacts"
207260 uses : actions/download-artifact@v7
208261 with :
@@ -211,6 +264,7 @@ jobs:
211264 merge-multiple : true
212265 - name : Cleanup
213266 run : |
267+ # Remove the granular manifests
214268 rm -f artifacts/*-dist-manifest.json
215269 - name : Create GitHub Release
216270 env :
@@ -219,6 +273,7 @@ jobs:
219273 ANNOUNCEMENT_BODY : " ${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}"
220274 RELEASE_COMMIT : " ${{ github.sha }}"
221275 run : |
276+ # Write and read notes from a file to avoid quoting breaking things
222277 echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt
223278
224279 gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/*
@@ -227,6 +282,9 @@ jobs:
227282 needs :
228283 - plan
229284 - host
285+ # use "always() && ..." to allow us to wait for all publish jobs while
286+ # still allowing individual publish jobs to skip themselves (for prereleases).
287+ # "host" however must run to completion, no skipping allowed!
230288 if : ${{ always() && needs.host.result == 'success' }}
231289 runs-on : " ubuntu-22.04"
232290 env :
0 commit comments