|
1 |
+ |
# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist |
|
2 |
+ |
# |
|
3 |
+ |
# Copyright 2022-2024, axodotdev |
|
4 |
+ |
# SPDX-License-Identifier: MIT or Apache-2.0 |
|
5 |
+ |
# |
|
6 |
+ |
# CI that: |
|
7 |
+ |
# |
|
8 |
+ |
# * checks for a Git Tag that looks like a release |
|
9 |
+ |
# * builds artifacts with dist (archives, installers, hashes) |
|
10 |
+ |
# * uploads those artifacts to temporary workflow zip |
|
11 |
+ |
# * 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. |
|
15 |
+ |
|
|
16 |
+ |
name: Release |
|
17 |
+ |
permissions: |
|
18 |
+ |
"contents": "write" |
|
19 |
+ |
|
|
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. |
|
41 |
+ |
on: |
|
42 |
+ |
pull_request: |
|
43 |
+ |
push: |
|
44 |
+ |
tags: |
|
45 |
+ |
- '**[0-9]+.[0-9]+.[0-9]+*' |
|
46 |
+ |
|
|
47 |
+ |
jobs: |
|
48 |
+ |
# Run 'dist plan' (or host) to determine what tasks we need to do |
|
49 |
+ |
plan: |
|
50 |
+ |
runs-on: "ubuntu-22.04" |
|
51 |
+ |
outputs: |
|
52 |
+ |
val: ${{ steps.plan.outputs.manifest }} |
|
53 |
+ |
tag: ${{ !github.event.pull_request && github.ref_name || '' }} |
|
54 |
+ |
tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} |
|
55 |
+ |
publishing: ${{ !github.event.pull_request }} |
|
56 |
+ |
env: |
|
57 |
+ |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
|
58 |
+ |
steps: |
|
59 |
+ |
- uses: actions/checkout@v6 |
|
60 |
+ |
with: |
|
61 |
+ |
persist-credentials: false |
|
62 |
+ |
submodules: recursive |
|
63 |
+ |
- 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 |
|
66 |
+ |
shell: bash |
|
67 |
+ |
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.31.0/cargo-dist-installer.sh | sh" |
|
68 |
+ |
- name: Cache dist |
|
69 |
+ |
uses: actions/upload-artifact@v6 |
|
70 |
+ |
with: |
|
71 |
+ |
name: cargo-dist-cache |
|
72 |
+ |
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.) |
|
78 |
+ |
- id: plan |
|
79 |
+ |
run: | |
|
80 |
+ |
dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json |
|
81 |
+ |
echo "dist ran successfully" |
|
82 |
+ |
cat plan-dist-manifest.json |
|
83 |
+ |
echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" |
|
84 |
+ |
- name: "Upload dist-manifest.json" |
|
85 |
+ |
uses: actions/upload-artifact@v6 |
|
86 |
+ |
with: |
|
87 |
+ |
name: artifacts-plan-dist-manifest |
|
88 |
+ |
path: plan-dist-manifest.json |
|
89 |
+ |
|
|
90 |
+ |
# Build and packages all the platform-specific things |
|
91 |
+ |
build-local-artifacts: |
|
92 |
+ |
name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) |
|
93 |
+ |
# Let the initial task tell us to not run (currently very blunt) |
|
94 |
+ |
needs: |
|
95 |
+ |
- plan |
|
96 |
+ |
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') }} |
|
97 |
+ |
strategy: |
|
98 |
+ |
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 |
|
109 |
+ |
matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} |
|
110 |
+ |
runs-on: ${{ matrix.runner }} |
|
111 |
+ |
container: ${{ matrix.container && matrix.container.image || null }} |
|
112 |
+ |
env: |
|
113 |
+ |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
|
114 |
+ |
BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json |
|
115 |
+ |
steps: |
|
116 |
+ |
- name: enable windows longpaths |
|
117 |
+ |
run: | |
|
118 |
+ |
git config --global core.longpaths true |
|
119 |
+ |
- uses: actions/checkout@v6 |
|
120 |
+ |
with: |
|
121 |
+ |
persist-credentials: false |
|
122 |
+ |
submodules: recursive |
|
123 |
+ |
- name: Install Rust non-interactively if not already installed |
|
124 |
+ |
if: ${{ matrix.container }} |
|
125 |
+ |
run: | |
|
126 |
+ |
if ! command -v cargo > /dev/null 2>&1; then |
|
127 |
+ |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y |
|
128 |
+ |
echo "$HOME/.cargo/bin" >> $GITHUB_PATH |
|
129 |
+ |
fi |
|
130 |
+ |
- name: Install dist |
|
131 |
+ |
run: ${{ matrix.install_dist.run }} |
|
132 |
+ |
# Get the dist-manifest |
|
133 |
+ |
- name: Fetch local artifacts |
|
134 |
+ |
uses: actions/download-artifact@v7 |
|
135 |
+ |
with: |
|
136 |
+ |
pattern: artifacts-* |
|
137 |
+ |
path: target/distrib/ |
|
138 |
+ |
merge-multiple: true |
|
139 |
+ |
- name: Install dependencies |
|
140 |
+ |
run: | |
|
141 |
+ |
${{ matrix.packages_install }} |
|
142 |
+ |
- name: Build artifacts |
|
143 |
+ |
run: | |
|
144 |
+ |
# Actually do builds and make zips and whatnot |
|
145 |
+ |
dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json |
|
146 |
+ |
echo "dist ran successfully" |
|
147 |
+ |
- id: cargo-dist |
|
148 |
+ |
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. |
|
152 |
+ |
shell: bash |
|
153 |
+ |
run: | |
|
154 |
+ |
# Parse out what we just built and upload it to scratch storage |
|
155 |
+ |
echo "paths<<EOF" >> "$GITHUB_OUTPUT" |
|
156 |
+ |
dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT" |
|
157 |
+ |
echo "EOF" >> "$GITHUB_OUTPUT" |
|
158 |
+ |
|
|
159 |
+ |
cp dist-manifest.json "$BUILD_MANIFEST_NAME" |
|
160 |
+ |
- name: "Upload artifacts" |
|
161 |
+ |
uses: actions/upload-artifact@v6 |
|
162 |
+ |
with: |
|
163 |
+ |
name: artifacts-build-local-${{ join(matrix.targets, '_') }} |
|
164 |
+ |
path: | |
|
165 |
+ |
${{ steps.cargo-dist.outputs.paths }} |
|
166 |
+ |
${{ env.BUILD_MANIFEST_NAME }} |
|
167 |
+ |
|
|
168 |
+ |
# Build and package all the platform-agnostic(ish) things |
|
169 |
+ |
build-global-artifacts: |
|
170 |
+ |
needs: |
|
171 |
+ |
- plan |
|
172 |
+ |
- build-local-artifacts |
|
173 |
+ |
runs-on: "ubuntu-22.04" |
|
174 |
+ |
env: |
|
175 |
+ |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
|
176 |
+ |
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json |
|
177 |
+ |
steps: |
|
178 |
+ |
- uses: actions/checkout@v6 |
|
179 |
+ |
with: |
|
180 |
+ |
persist-credentials: false |
|
181 |
+ |
submodules: recursive |
|
182 |
+ |
- name: Install cached dist |
|
183 |
+ |
uses: actions/download-artifact@v7 |
|
184 |
+ |
with: |
|
185 |
+ |
name: cargo-dist-cache |
|
186 |
+ |
path: ~/.cargo/bin/ |
|
187 |
+ |
- run: chmod +x ~/.cargo/bin/dist |
|
188 |
+ |
# Get all the local artifacts for the global tasks to use (for e.g. checksums) |
|
189 |
+ |
- name: Fetch local artifacts |
|
190 |
+ |
uses: actions/download-artifact@v7 |
|
191 |
+ |
with: |
|
192 |
+ |
pattern: artifacts-* |
|
193 |
+ |
path: target/distrib/ |
|
194 |
+ |
merge-multiple: true |
|
195 |
+ |
- id: cargo-dist |
|
196 |
+ |
shell: bash |
|
197 |
+ |
run: | |
|
198 |
+ |
dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json |
|
199 |
+ |
echo "dist ran successfully" |
|
200 |
+ |
|
|
201 |
+ |
# Parse out what we just built and upload it to scratch storage |
|
202 |
+ |
echo "paths<<EOF" >> "$GITHUB_OUTPUT" |
|
203 |
+ |
jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" |
|
204 |
+ |
echo "EOF" >> "$GITHUB_OUTPUT" |
|
205 |
+ |
|
|
206 |
+ |
cp dist-manifest.json "$BUILD_MANIFEST_NAME" |
|
207 |
+ |
- name: "Upload artifacts" |
|
208 |
+ |
uses: actions/upload-artifact@v6 |
|
209 |
+ |
with: |
|
210 |
+ |
name: artifacts-build-global |
|
211 |
+ |
path: | |
|
212 |
+ |
${{ steps.cargo-dist.outputs.paths }} |
|
213 |
+ |
${{ env.BUILD_MANIFEST_NAME }} |
|
214 |
+ |
# Determines if we should publish/announce |
|
215 |
+ |
host: |
|
216 |
+ |
needs: |
|
217 |
+ |
- plan |
|
218 |
+ |
- build-local-artifacts |
|
219 |
+ |
- build-global-artifacts |
|
220 |
+ |
# Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine) |
|
221 |
+ |
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') }} |
|
222 |
+ |
env: |
|
223 |
+ |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
|
224 |
+ |
runs-on: "ubuntu-22.04" |
|
225 |
+ |
outputs: |
|
226 |
+ |
val: ${{ steps.host.outputs.manifest }} |
|
227 |
+ |
steps: |
|
228 |
+ |
- uses: actions/checkout@v6 |
|
229 |
+ |
with: |
|
230 |
+ |
persist-credentials: false |
|
231 |
+ |
submodules: recursive |
|
232 |
+ |
- name: Install cached dist |
|
233 |
+ |
uses: actions/download-artifact@v7 |
|
234 |
+ |
with: |
|
235 |
+ |
name: cargo-dist-cache |
|
236 |
+ |
path: ~/.cargo/bin/ |
|
237 |
+ |
- run: chmod +x ~/.cargo/bin/dist |
|
238 |
+ |
# Fetch artifacts from scratch-storage |
|
239 |
+ |
- name: Fetch artifacts |
|
240 |
+ |
uses: actions/download-artifact@v7 |
|
241 |
+ |
with: |
|
242 |
+ |
pattern: artifacts-* |
|
243 |
+ |
path: target/distrib/ |
|
244 |
+ |
merge-multiple: true |
|
245 |
+ |
- id: host |
|
246 |
+ |
shell: bash |
|
247 |
+ |
run: | |
|
248 |
+ |
dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json |
|
249 |
+ |
echo "artifacts uploaded and released successfully" |
|
250 |
+ |
cat dist-manifest.json |
|
251 |
+ |
echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" |
|
252 |
+ |
- name: "Upload dist-manifest.json" |
|
253 |
+ |
uses: actions/upload-artifact@v6 |
|
254 |
+ |
with: |
|
255 |
+ |
# Overwrite the previous copy |
|
256 |
+ |
name: artifacts-dist-manifest |
|
257 |
+ |
path: dist-manifest.json |
|
258 |
+ |
# Create a GitHub Release while uploading all files to it |
|
259 |
+ |
- name: "Download GitHub Artifacts" |
|
260 |
+ |
uses: actions/download-artifact@v7 |
|
261 |
+ |
with: |
|
262 |
+ |
pattern: artifacts-* |
|
263 |
+ |
path: artifacts |
|
264 |
+ |
merge-multiple: true |
|
265 |
+ |
- name: Cleanup |
|
266 |
+ |
run: | |
|
267 |
+ |
# Remove the granular manifests |
|
268 |
+ |
rm -f artifacts/*-dist-manifest.json |
|
269 |
+ |
- name: Create GitHub Release |
|
270 |
+ |
env: |
|
271 |
+ |
PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" |
|
272 |
+ |
ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}" |
|
273 |
+ |
ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}" |
|
274 |
+ |
RELEASE_COMMIT: "${{ github.sha }}" |
|
275 |
+ |
run: | |
|
276 |
+ |
# Write and read notes from a file to avoid quoting breaking things |
|
277 |
+ |
echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt |
|
278 |
+ |
|
|
279 |
+ |
gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/* |
|
280 |
+ |
|
|
281 |
+ |
publish-homebrew-formula: |
|
282 |
+ |
needs: |
|
283 |
+ |
- plan |
|
284 |
+ |
- host |
|
285 |
+ |
runs-on: "ubuntu-22.04" |
|
286 |
+ |
env: |
|
287 |
+ |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
|
288 |
+ |
PLAN: ${{ needs.plan.outputs.val }} |
|
289 |
+ |
GITHUB_USER: "axo bot" |
|
290 |
+ |
GITHUB_EMAIL: "admin+bot@axo.dev" |
|
291 |
+ |
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }} |
|
292 |
+ |
steps: |
|
293 |
+ |
- uses: actions/checkout@v6 |
|
294 |
+ |
with: |
|
295 |
+ |
persist-credentials: true |
|
296 |
+ |
repository: "stevedylandev/homebrew-tap" |
|
297 |
+ |
token: ${{ secrets.HOMEBREW_TAP_TOKEN }} |
|
298 |
+ |
# So we have access to the formula |
|
299 |
+ |
- name: Fetch homebrew formulae |
|
300 |
+ |
uses: actions/download-artifact@v7 |
|
301 |
+ |
with: |
|
302 |
+ |
pattern: artifacts-* |
|
303 |
+ |
path: Formula/ |
|
304 |
+ |
merge-multiple: true |
|
305 |
+ |
# This is extra complex because you can make your Formula name not match your app name |
|
306 |
+ |
# so we need to find releases with a *.rb file, and publish with that filename. |
|
307 |
+ |
- name: Commit formula files |
|
308 |
+ |
run: | |
|
309 |
+ |
git config --global user.name "${GITHUB_USER}" |
|
310 |
+ |
git config --global user.email "${GITHUB_EMAIL}" |
|
311 |
+ |
|
|
312 |
+ |
for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith(".rb")] | any)'); do |
|
313 |
+ |
filename=$(echo "$release" | jq '.artifacts[] | select(endswith(".rb"))' --raw-output) |
|
314 |
+ |
name=$(echo "$filename" | sed "s/\.rb$//") |
|
315 |
+ |
version=$(echo "$release" | jq .app_version --raw-output) |
|
316 |
+ |
|
|
317 |
+ |
export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH" |
|
318 |
+ |
brew update |
|
319 |
+ |
# We avoid reformatting user-provided data such as the app description and homepage. |
|
320 |
+ |
brew style --except-cops FormulaAudit/Homepage,FormulaAudit/Desc,FormulaAuditStrict --fix "Formula/${filename}" || true |
|
321 |
+ |
|
|
322 |
+ |
git add "Formula/${filename}" |
|
323 |
+ |
git commit -m "${name} ${version}" |
|
324 |
+ |
done |
|
325 |
+ |
git push |
|
326 |
+ |
|
|
327 |
+ |
announce: |
|
328 |
+ |
needs: |
|
329 |
+ |
- plan |
|
330 |
+ |
- host |
|
331 |
+ |
- publish-homebrew-formula |
|
332 |
+ |
# use "always() && ..." to allow us to wait for all publish jobs while |
|
333 |
+ |
# still allowing individual publish jobs to skip themselves (for prereleases). |
|
334 |
+ |
# "host" however must run to completion, no skipping allowed! |
|
335 |
+ |
if: ${{ always() && needs.host.result == 'success' && (needs.publish-homebrew-formula.result == 'skipped' || needs.publish-homebrew-formula.result == 'success') }} |
|
336 |
+ |
runs-on: "ubuntu-22.04" |
|
337 |
+ |
env: |
|
338 |
+ |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
|
339 |
+ |
steps: |
|
340 |
+ |
- uses: actions/checkout@v6 |
|
341 |
+ |
with: |
|
342 |
+ |
persist-credentials: false |
|
343 |
+ |
submodules: recursive |