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
name: Release
on:
push:
tags:
# A manual run builds and packages everything but publishes nothing, so the
# whole pipeline can be rehearsed without spending a tag on finding out it
# was wrong.
workflow_dispatch:
# Only `publish` writes anything; everything above it is read-only.
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
# Nothing else stops `git tag v0.2.0` on a tree whose manifest still says
# 0.1.0, and the mistake is only visible once the release is published.
- name: Tag must match the version in Cargo.toml
if: startsWith(github.ref, 'refs/tags/')
run: |
manifest=$(cargo metadata --no-deps --format-version 1 \
| jq -r '.packages[0].version')
tag=${GITHUB_REF_NAME#v}
if [ "$manifest" != "$tag" ]; then
echo "::error::tag $GITHUB_REF_NAME means version $tag, but Cargo.toml says $manifest"
exit 1
fi
echo "releasing rash $manifest"
# The full CI matrix — fmt, clippy and tests on stable, nightly and the MSRV,
# across Linux and macOS. Reused rather than restated so the two cannot drift.
test:
uses: ./.github/workflows/ci.yml
build:
needs:
strategy:
fail-fast: false
matrix:
include:
-
# Free on public repositories. On a private one this row needs a paid
# larger-runner plan, or cross-compilation in place of a native build.
-
# Both Apple targets come off the same arm64 image. Apple's toolchain
# cross-compiles between its own architectures, so an x86_64 binary
# built here is a real x86_64 Mach-O, not a translated one — and the
# alternative, macos-13, is the last x86_64 image and is on a
# deprecation path. Nothing here should be waiting on that.
-
-
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
# Deliberately uncached, unlike ci.yml: a published binary is worth the
# few extra minutes of building from scratch.
#
# The default feature set is empty, so --no-default-features changes
# nothing today, and `test-harness` now gates only an example, which
# `cargo build` does not build at any feature setting. Both of those could
# change; the flag stays as a latch so that a future optional target
# cannot reach a tarball just by being switched on by default.
- name: Build
run: >
cargo build --release --locked --no-default-features
--target ${{ matrix.target }}
- name: Package
run: |
name="rash-${GITHUB_REF_NAME}-${{ matrix.target }}"
mkdir "$name"
cp "target/${{ matrix.target }}/release/rash" "$name/"
# The manual matters: the README's install instructions place it, and
# `man ./rash.1` works straight out of the unpacked directory.
cp rash.1 LICENSE README.md "$name/"
tar -czf "$name.tar.gz" "$name"
ls -l "$name.tar.gz"
- uses: actions/upload-artifact@v6
with:
name: rash-${{ matrix.target }}
path: rash-*.tar.gz
if-no-files-found: error
publish:
# Skipped on a manual run: that is the rehearsal, and it stops here.
#
# The test is on the event, not the ref. workflow_dispatch can be pointed at
# a tag, which makes `startsWith(github.ref, 'refs/tags/')` true — so the
# ref-shaped guard this replaces let a rehearsal run the real publish, and
# `gh release create` then failed against a release that already existed.
if: github.event_name == 'push'
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v7
with:
path: dist
merge-multiple: true
- name: Checksums
run: cd dist && sha256sum *.tar.gz | tee SHA256SUMS
- name: Create the release
env:
GH_TOKEN: ${{ github.token }}
run: |
# A tag with a hyphen in it — v0.2.0-rc1 — is a pre-release.
case "$GITHUB_REF_NAME" in
*-*) pre=--prerelease ;;
*) pre= ;;
esac
gh release create "$GITHUB_REF_NAME" \
dist/*.tar.gz dist/SHA256SUMS \
--repo "$GITHUB_REPOSITORY" \
--title "rash $GITHUB_REF_NAME" \
--generate-notes \
--verify-tag \
$pre