-
Notifications
You must be signed in to change notification settings - Fork 0
194 lines (178 loc) · 7.54 KB
/
Copy pathrelease.yml
File metadata and controls
194 lines (178 loc) · 7.54 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
name: Release
on:
# Manual-only: pushing a `v*` tag no longer auto-builds/publishes. Releases
# are built locally and uploaded by hand; run this workflow on demand from the
# Actions tab (it uses the ref it's dispatched from to derive the version).
workflow_dispatch:
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
# Change only this line when renaming (also update the [[bin]] name in Cargo.toml)
BIN_NAME: okx-outcomes
jobs:
# Gate: a `v*` tag only releases if it points at a commit that is an
# ancestor of `main`. Without this, anyone with write access (or a stolen
# token) could tag an arbitrary unreviewed commit on a side branch and ship
# it to every user via install.sh. `build` — and transitively `release` —
# depend on this job, so a tag off `main` builds nothing.
validate-ref:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
persist-credentials: false
- name: Verify tag is on main
run: |
# checkout above used fetch-depth: 0, which already fetched every
# branch (incl. main) into refs/remotes/origin/* with the job token.
# A separate `git fetch` here would run without credentials
# (persist-credentials: false strips them) and fail on a private repo,
# so compare against the origin/main that checkout already pulled.
git merge-base --is-ancestor "$GITHUB_SHA" origin/main \
|| { echo "::error::release tag is not on main; refusing to build"; exit 1; }
build:
name: Build ${{ matrix.target }}
needs: validate-ref
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-apple-darwin
# Apple Silicon runner, cross-compiles to x86_64 (rustc ships a universal-capable SDK)
runner: macos-latest
archive: tar.gz
- target: aarch64-apple-darwin
runner: macos-latest
archive: tar.gz
- target: x86_64-unknown-linux-gnu
runner: ubuntu-latest
archive: tar.gz
- target: aarch64-unknown-linux-gnu
runner: ubuntu-latest
archive: tar.gz
cross: true
# Statically linked binaries that run on Alpine / minimal Docker images.
- target: x86_64-unknown-linux-musl
runner: ubuntu-latest
archive: tar.gz
cross: true
# Apple Silicon Docker + AWS Graviton Alpine containers.
- target: aarch64-unknown-linux-musl
runner: ubuntu-latest
archive: tar.gz
cross: true
- target: x86_64-pc-windows-msvc
runner: windows-latest
archive: zip
# Native Windows on ARM (newer Surface / Snapdragon laptops).
- target: aarch64-pc-windows-msvc
runner: windows-latest
archive: zip
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master (pinned)
with:
toolchain: 1.91.1
targets: ${{ matrix.target }}
- name: Install cross
if: matrix.cross
# Pin to the v0.2.5 release commit (not HEAD) and honor cross's own
# Cargo.lock, so an upstream compromise can't reach the release runner.
run: cargo install cross --git https://github.com/cross-rs/cross --rev f8151ae777290430cf2108efacf3976d9528500b --locked
- name: Set workspace version from tag
shell: bash
env:
REF_NAME: ${{ github.ref_name }}
run: |
VERSION="${REF_NAME#v}"
# Allowlist check: only accept semver-style tags so a malicious tag name
# cannot inject metacharacters into the sed expression below.
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]] || { echo "invalid version: $VERSION" >&2; exit 1; }
# Only matches lines starting with `version = "..."`; inline versions in dependencies are left untouched.
sed -i.bak -E "s/^version = \"[^\"]+\"/version = \"${VERSION}\"/" Cargo.toml
rm Cargo.toml.bak
# Sync Cargo.lock's workspace-member version with the bumped
# Cargo.toml so the `--locked` release build below doesn't fail on a
# stale lockfile. `--workspace` only touches this package's own
# version; the pinned SDK rev and the locked registry deps stay
# unchanged. We can't use `--offline` here: on a clean CI runner the
# git dependency hasn't been fetched yet, so cargo needs network to
# resolve its source.
cargo update --workspace
grep -E "^version" Cargo.toml
- name: Build
shell: bash
run: |
if [ "${{ matrix.cross }}" = "true" ]; then
cross build --release --locked --target ${{ matrix.target }}
else
cargo build --release --locked --target ${{ matrix.target }}
fi
- name: Package (tar.gz)
if: matrix.archive == 'tar.gz'
shell: bash
env:
REPO_NAME: ${{ github.event.repository.name }}
REF_NAME: ${{ github.ref_name }}
run: |
STAGING="${REPO_NAME}-${REF_NAME}-${{ matrix.target }}"
mkdir -p "$STAGING"
cp "target/${{ matrix.target }}/release/${BIN_NAME}" "$STAGING/"
cp README.md LICENSE "$STAGING/" 2>/dev/null || true
tar czf "${STAGING}.tar.gz" "$STAGING"
echo "ASSET=${STAGING}.tar.gz" >> "$GITHUB_ENV"
- name: Package (zip)
if: matrix.archive == 'zip'
shell: pwsh
env:
REPO_NAME: ${{ github.event.repository.name }}
REF_NAME: ${{ github.ref_name }}
run: |
$staging = "$env:REPO_NAME-$env:REF_NAME-${{ matrix.target }}"
New-Item -ItemType Directory -Path $staging | Out-Null
Copy-Item "target/${{ matrix.target }}/release/$env:BIN_NAME.exe" $staging
Copy-Item README.md, LICENSE $staging -ErrorAction SilentlyContinue
Compress-Archive -Path $staging -DestinationPath "$staging.zip"
"ASSET=$staging.zip" | Out-File -FilePath $env:GITHUB_ENV -Append
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: ${{ matrix.target }}
path: ${{ env.ASSET }}
if-no-files-found: error
release:
name: Publish release
needs: build
runs-on: ubuntu-latest
# Manual approval gate before anything is published. Create a
# `production-release` environment with Required reviewers under
# Settings → Environments; until reviewers are configured this is a
# no-op (the job runs without pausing).
environment: production-release
permissions:
contents: write
steps:
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
merge-multiple: true
- name: Generate checksums
shell: bash
run: |
shopt -s nullglob
files=(*.tar.gz *.zip)
if [ ${#files[@]} -eq 0 ]; then
echo "no artifacts found" >&2
exit 1
fi
sha256sum "${files[@]}" > checksums.txt
cat checksums.txt
- uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
with:
generate_release_notes: true
files: |
*.tar.gz
*.zip
checksums.txt