1
+ # Copyright 2022-2023, axodotdev
2
+ # SPDX-License-Identifier: MIT or Apache-2.0
3
+ #
1
4
# CI that:
2
5
#
3
6
# * checks for a Git Tag that looks like a release
4
- # * creates a Github Release™ and fills in its text
5
- # * builds artifacts with cargo-dist (executable-zips, installers)
6
- # * uploads those artifacts to the Github Release™
7
+ # * builds artifacts with cargo-dist (archives, installers, hashes)
8
+ # * uploads those artifacts to temporary workflow zip
9
+ # * on success, uploads the artifacts to a Github Release™
7
10
#
8
- # Note that the Github Release™ will be created before the artifacts,
9
- # so there will be a few minutes where the release has no artifacts
10
- # and then they will slowly trickle in, possibly failing. To make
11
- # this more pleasant we mark the release as a "draft" until all
12
- # artifacts have been successfully uploaded. This allows you to
13
- # choose what to do with partial successes and avoids spamming
14
- # anyone with notifications before the release is actually ready.
11
+ # Note that the Github Release™ will be created with a generated
12
+ # title/body based on your changelogs.
15
13
name : Release
16
14
17
15
permissions :
18
16
contents : write
19
17
20
18
# This task will run whenever you push a git tag that looks like a version
21
- # like "v1", "v1.2 .0", "v0.1.0-prerelease01 ", "my-app- v1.0.0", etc.
22
- # The version will be roughly parsed as ({PACKAGE_NAME}-)?v{ VERSION} , where
19
+ # like "1.0 .0", "v0.1.0-prerelease.1 ", "my-app/0.1.0", "releases/ v1.0.0", etc.
20
+ # Various formats will be parsed into a VERSION and an optional PACKAGE_NAME , where
23
21
# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION
24
- # must be a Cargo-style SemVer Version.
22
+ # must be a Cargo-style SemVer Version (must have at least major.minor.patch) .
25
23
#
26
- # If PACKAGE_NAME is specified, then we will create a Github Release™ for that
24
+ # If PACKAGE_NAME is specified, then the release will be for that
27
25
# package (erroring out if it doesn't have the given version or isn't cargo-dist-able).
28
26
#
29
- # If PACKAGE_NAME isn't specified, then we will create a Github Release™ for all
30
- # (cargo-dist-able) packages in the workspace with that version (this is mode is
27
+ # If PACKAGE_NAME isn't specified, then the release will be for all
28
+ # (cargo-dist-able) packages in the workspace with that version (this mode is
31
29
# intended for workspaces with only one dist-able package, or with all dist-able
32
30
# packages versioned/released in lockstep).
33
31
#
34
32
# If you push multiple tags at once, separate instances of this workflow will
35
- # spin up, creating an independent Github Release™ for each one.
33
+ # spin up, creating an independent Github Release™ for each one. However Github
34
+ # will hard limit this to 3 tags per commit, as it will assume more tags is a
35
+ # mistake.
36
36
#
37
- # If there's a prerelease-style suffix to the version then the Github Release™
37
+ # If there's a prerelease-style suffix to the version, then the Github Release™
38
38
# will be marked as a prerelease.
39
39
on :
40
40
push :
41
41
tags :
42
- - ' *-?v[0-9]+*'
42
+ - ' **[0-9]+.[0-9]+.[0-9]+*'
43
+ pull_request :
43
44
44
45
jobs :
45
- # Create the Github Release™ so the packages have something to be uploaded to
46
- create-release :
46
+ # Run 'cargo dist plan' to determine what tasks we need to do
47
+ plan :
47
48
runs-on : ubuntu-latest
48
49
outputs :
49
- has-releases : ${{ steps.create-release.outputs.has-releases }}
50
+ val : ${{ steps.plan.outputs.manifest }}
51
+ tag : ${{ !github.event.pull_request && github.ref_name || '' }}
52
+ tag-flag : ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }}
53
+ publishing : ${{ !github.event.pull_request }}
50
54
env :
51
55
GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
52
56
steps :
53
- - uses : actions/checkout@v3
54
- - name : Install Rust
55
- run : rustup update 1.67.1 --no-self-update && rustup default 1.67.1
57
+ - uses : actions/checkout@v4
58
+ with :
59
+ submodules : recursive
56
60
- name : Install cargo-dist
57
- run : curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.5 /cargo-dist-v0.0.5- installer.sh | sh
58
- - id : create-release
61
+ run : " curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.4.0 /cargo-dist-installer.sh | sh"
62
+ - id : plan
59
63
run : |
60
- cargo dist manifest --tag= ${{ github.ref_name }} --artifacts=all --no-local-paths --output-format=json > dist-manifest.json
61
- echo "dist manifest ran successfully"
64
+ cargo dist plan ${{ ! github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} --output-format=json > dist-manifest.json
65
+ echo "cargo dist plan ran successfully"
62
66
cat dist-manifest.json
63
-
64
- # Create the Github Release™ based on what cargo-dist thinks it should be
65
- ANNOUNCEMENT_TITLE=$(cat dist-manifest.json | jq --raw-output ".announcement_title")
66
- IS_PRERELEASE=$(cat dist-manifest.json | jq --raw-output ".announcement_is_prerelease")
67
- cat dist-manifest.json | jq --raw-output ".announcement_github_body" > new_dist_announcement.md
68
- gh release create ${{ github.ref_name }} --draft --prerelease="$IS_PRERELEASE" --title="$ANNOUNCEMENT_TITLE" --notes-file=new_dist_announcement.md
69
- echo "created announcement!"
70
-
71
- # Upload the manifest to the Github Release™
72
- gh release upload ${{ github.ref_name }} dist-manifest.json
73
- echo "uploaded manifest!"
74
-
75
- # Disable all the upload-artifacts tasks if we have no actual releases
76
- HAS_RELEASES=$(cat dist-manifest.json | jq --raw-output ".releases != null")
77
- echo "has-releases=$HAS_RELEASES" >> "$GITHUB_OUTPUT"
67
+ echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT"
68
+ - name : " Upload dist-manifest.json"
69
+ uses : actions/upload-artifact@v3
70
+ with :
71
+ name : artifacts
72
+ path : dist-manifest.json
78
73
79
- # Build and packages all the things
80
- upload-artifacts :
74
+ # Build and packages all the platform-specific things
75
+ upload-local- artifacts :
81
76
# Let the initial task tell us to not run (currently very blunt)
82
- needs : create-release
83
- if : ${{ needs.create-release .outputs.has- releases == 'true' }}
77
+ needs : plan
78
+ if : ${{ fromJson( needs.plan .outputs.val). releases != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }}
84
79
strategy :
85
- matrix :
86
- # For these target platforms
87
- include :
88
- - os : macos-11
89
- dist-args : --artifacts=local --target=aarch64-apple-darwin --target=x86_64-apple-darwin
90
- install-dist : curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.5/cargo-dist-v0.0.5-installer.sh | sh
91
- - os : ubuntu-20.04
92
- dist-args : --artifacts=local --target=x86_64-unknown-linux-gnu
93
- install-dist : curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.5/cargo-dist-v0.0.5-installer.sh | sh
94
- - os : windows-2019
95
- dist-args : --artifacts=local --target=x86_64-pc-windows-msvc
96
- install-dist : irm https://github.com/axodotdev/cargo-dist/releases/download/v0.0.5/cargo-dist-v0.0.5-installer.ps1 | iex
97
-
98
- runs-on : ${{ matrix.os }}
80
+ fail-fast : false
81
+ # Target platforms/runners are computed by cargo-dist in create-release.
82
+ # Each member of the matrix has the following arguments:
83
+ #
84
+ # - runner: the github runner
85
+ # - dist-args: cli flags to pass to cargo dist
86
+ # - install-dist: expression to run to install cargo-dist on the runner
87
+ #
88
+ # Typically there will be:
89
+ # - 1 "global" task that builds universal installers
90
+ # - N "local" tasks that build each platform's binaries and platform-specific installers
91
+ matrix : ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }}
92
+ runs-on : ${{ matrix.runner }}
99
93
env :
100
94
GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
95
+ BUILD_MANIFEST_NAME : target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
101
96
steps :
102
- - uses : actions/checkout@v3
103
- - name : Install Rust
104
- run : rustup update 1.67.1 --no-self-update && rustup default 1.67.1
97
+ - uses : actions/checkout@v4
98
+ with :
99
+ submodules : recursive
100
+ - uses : swatinem/rust-cache@v2
105
101
- name : Install cargo-dist
106
- run : ${{ matrix.install-dist }}
107
- - name : Run cargo-dist
108
- # This logic is a bit janky because it's trying to be a polyglot between
109
- # powershell and bash since this will run on windows, macos, and linux!
110
- # The two platforms don't agree on how to talk about env vars but they
111
- # do agree on 'cat' and '$()' so we use that to marshal values between commands.
102
+ run : ${{ matrix.install_dist }}
103
+ - name : Install dependencies
104
+ run : |
105
+ ${{ matrix.packages_install }}
106
+ - name : Build artifacts
112
107
run : |
113
108
# Actually do builds and make zips and whatnot
114
- cargo dist build --tag=${{ github.ref_name }} --output-format=json ${{ matrix.dist-args }} > dist-manifest.json
115
- echo "dist ran successfully"
116
- cat dist-manifest.json
109
+ cargo dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json
110
+ echo "cargo dist ran successfully"
111
+ - id : cargo-dist
112
+ name : Post-build
113
+ # We force bash here just because github makes it really hard to get values up
114
+ # to "real" actions without writing to env-vars, and writing to env-vars has
115
+ # inconsistent syntax between shell and powershell.
116
+ shell : bash
117
+ run : |
118
+ # Parse out what we just built and upload it to the Github Release™
119
+ echo "paths<<EOF" >> "$GITHUB_OUTPUT"
120
+ jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json >> "$GITHUB_OUTPUT"
121
+ echo "EOF" >> "$GITHUB_OUTPUT"
122
+
123
+ cp dist-manifest.json "$BUILD_MANIFEST_NAME"
124
+ - name : " Upload artifacts"
125
+ uses : actions/upload-artifact@v3
126
+ with :
127
+ name : artifacts
128
+ path : |
129
+ ${{ steps.cargo-dist.outputs.paths }}
130
+ ${{ env.BUILD_MANIFEST_NAME }}
131
+
132
+ # Build and package all the platform-agnostic(ish) things
133
+ upload-global-artifacts :
134
+ needs : [plan, upload-local-artifacts]
135
+ runs-on : " ubuntu-20.04"
136
+ env :
137
+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
138
+ steps :
139
+ - uses : actions/checkout@v4
140
+ with :
141
+ submodules : recursive
142
+ - name : Install cargo-dist
143
+ run : " curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.4.0/cargo-dist-installer.sh | sh"
144
+ # Get all the local artifacts for the global tasks to use (for e.g. checksums)
145
+ - name : Fetch local artifacts
146
+ uses : actions/download-artifact@v3
147
+ with :
148
+ name : artifacts
149
+ path : target/distrib/
150
+ - id : cargo-dist
151
+ shell : bash
152
+ run : |
153
+ cargo dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json
154
+ echo "cargo dist ran successfully"
117
155
118
156
# Parse out what we just built and upload it to the Github Release™
119
- cat dist-manifest.json | jq --raw-output ".artifacts[]?.path | select( . != null )" > uploads.txt
120
- echo "uploading..."
121
- cat uploads.txt
122
- gh release upload ${{ github.ref_name }} $(cat uploads.txt)
123
- echo "uploaded!"
157
+ echo "paths<<EOF" >> "$GITHUB_OUTPUT"
158
+ jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json >> "$GITHUB_OUTPUT"
159
+ echo "EOF" >> "$GITHUB_OUTPUT"
160
+ - name : " Upload artifacts"
161
+ uses : actions/upload-artifact@v3
162
+ with :
163
+ name : artifacts
164
+ path : ${{ steps.cargo-dist.outputs.paths }}
165
+
166
+ should-publish :
167
+ needs :
168
+ - plan
169
+ - upload-local-artifacts
170
+ - upload-global-artifacts
171
+ if : ${{ needs.plan.outputs.publishing == 'true' }}
172
+ runs-on : ubuntu-latest
173
+ steps :
174
+ - name : print tag
175
+ run : echo "ok we're publishing!"
124
176
125
- # Mark the Github Release™ as a non-draft now that everything has succeeded!
177
+ # Create a Github Release with all the results once everything is done
126
178
publish-release :
127
- # Only run after all the other tasks, but it's ok if upload-artifacts was skipped
128
- needs : [create-release, upload-artifacts]
129
- if : ${{ always() && needs.create-release.result == 'success' && (needs.upload-artifacts.result == 'skipped' || needs.upload-artifacts.result == 'success') }}
179
+ needs : [plan, should-publish]
130
180
runs-on : ubuntu-latest
131
181
env :
132
182
GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
133
183
steps :
134
- - uses : actions/checkout@v3
135
- - name : mark release as non-draft
184
+ - uses : actions/checkout@v4
185
+ with :
186
+ submodules : recursive
187
+ - name : " Download artifacts"
188
+ uses : actions/download-artifact@v3
189
+ with :
190
+ name : artifacts
191
+ path : artifacts
192
+ - name : Cleanup
136
193
run : |
137
- gh release edit ${{ github.ref_name }} --draft=false
194
+ # Remove the granular manifests
195
+ rm artifacts/*-dist-manifest.json
196
+ - name : Create Release
197
+ uses : ncipollo/release-action@v1
198
+ with :
199
+ tag : ${{ needs.plan.outputs.tag }}
200
+ name : ${{ fromJson(needs.plan.outputs.val).announcement_title }}
201
+ body : ${{ fromJson(needs.plan.outputs.val).announcement_github_body }}
202
+ prerelease : ${{ fromJson(needs.plan.outputs.val).announcement_is_prerelease }}
203
+ artifacts : " artifacts/*"
0 commit comments