-
Notifications
You must be signed in to change notification settings - Fork 2
230 lines (212 loc) · 9.62 KB
/
Copy pathcli-build.yml
File metadata and controls
230 lines (212 loc) · 9.62 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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
name: cli build
# Build prebuilt `burn` binaries for every platform we publish to npm under
# `@relayburn/cli-*`. PRs validate the matrix; the publish workflow
# (`.github/workflows/publish.yml`) calls this workflow via `workflow_call`
# to produce the binaries it then stages into per-platform packages.
#
# Mirrors `.github/workflows/napi-build.yml`: the napi-rs SDK uses the same
# umbrella + per-platform-package shape, just with `.node` artifacts instead
# of native executables.
on:
pull_request:
paths:
- 'crates/relayburn-cli/**'
- 'crates/relayburn-sdk/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'rust-toolchain.toml'
- 'packages/relayburn/**'
- '.github/workflows/cli-build.yml'
push:
branches: [main]
paths:
- 'crates/relayburn-cli/**'
- 'crates/relayburn-sdk/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'rust-toolchain.toml'
- 'packages/relayburn/**'
- '.github/workflows/cli-build.yml'
workflow_dispatch:
workflow_call:
# Publish runs the same matrix this workflow exercises on PRs. The
# caller downloads the uploaded `relayburn-cli-<short>` artifacts and
# stages them into `packages/relayburn/npm/<short>/bin/` before
# `npm pack` + `npm publish`.
inputs:
release_version:
description: >-
Post-bump release version (e.g. "2.1.0") to bake into the
binary via CARGO_PKG_VERSION. Optional — when empty (PR/push
runs) we skip the lockstep sed and build with the on-disk
workspace version unchanged.
required: false
type: string
permissions:
contents: read
concurrency:
group: cli-build-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: build ${{ matrix.short }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-apple-darwin
os: macos-15-intel
short: darwin-x64
- target: aarch64-apple-darwin
os: macos-14
short: darwin-arm64
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
short: linux-x64-gnu
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
short: linux-arm64-gnu
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Rust toolchain
# rust-toolchain.toml at the repo root pins the channel + components.
run: |
rustup toolchain install
rustup target add ${{ matrix.target }}
- name: Install aarch64-linux cross toolchain (linux-arm64 only)
if: matrix.target == 'aarch64-unknown-linux-gnu'
# `libsqlite3-sys` (a transitive dep via `rusqlite`) compiles bundled
# SQLite C source via `cc-rs`, which probes for `aarch64-linux-gnu-gcc`.
# Same setup as `napi-build.yml`'s aarch64-linux leg.
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Cache cargo registry + target
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: cargo-cli-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock', '**/Cargo.toml', 'rust-toolchain.toml') }}
restore-keys: |
cargo-cli-${{ runner.os }}-${{ matrix.target }}-
cargo-cli-${{ runner.os }}-
- name: Lockstep Cargo.toml to release version
# When invoked via the publish workflow, sed the workspace
# `[workspace.package].version` (and the path-dep `version = "X.Y"`
# pins in crates that depend on `relayburn-sdk`) so the `burn`
# binary built below carries the post-bump `CARGO_PKG_VERSION`.
# Without this, clap's `version,` directive bakes the pre-bump
# version into the binary and `burn --version` reports the previous
# release. Mirrors the regex used in publish.yml's "Lockstep the
# Rust workspace" step that runs against the published commit.
#
# Skipped when `release_version` is empty (PR/push runs) — the
# on-disk workspace version is correct in that case.
if: inputs.release_version != ''
run: |
set -euo pipefail
RUST_VER="${{ inputs.release_version }}"
RUST_MINOR=$(echo "$RUST_VER" | awk -F. '{print $1"."$2}')
echo "Rust workspace lockstep: $RUST_VER (minor pin: $RUST_MINOR)"
sed -i.bak -E "s/^version = \"[^\"]+\"$/version = \"$RUST_VER\"/" Cargo.toml
for crate in relayburn-cli relayburn-sdk-node; do
sed -i.bak -E "s|(relayburn-sdk = \\{ path = \"\\.\\./relayburn-sdk\", version = \")[^\"]+(\" \\})|\\1$RUST_MINOR\\2|" "crates/$crate/Cargo.toml"
done
rm -f Cargo.toml.bak crates/relayburn-cli/Cargo.toml.bak crates/relayburn-sdk-node/Cargo.toml.bak
- name: Build burn binary for ${{ matrix.target }}
# The binary name is `burn` (the `[[bin]]` rename in
# `crates/relayburn-cli/Cargo.toml`); the crate is `relayburn-cli`.
# CC_/linker env vars only take effect on the aarch64-linux leg
# (cargo ignores per-target vars when host == target); native legs
# are unaffected.
env:
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
CXX_aarch64_unknown_linux_gnu: aarch64-linux-gnu-g++
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
run: |
cargo build --release --target ${{ matrix.target }} --bin burn -p relayburn-cli
- name: Strip binary
# Stripping cuts ~half the size off a release `burn` (debug info,
# symbol tables that aren't needed at runtime). On macOS use `-x` to
# strip non-global symbols only — fully stripping a Mach-O binary
# breaks codesigning. On linux, default `strip` is fine; when
# cross-compiling for aarch64 we use the matching cross-strip.
run: |
BIN="target/${{ matrix.target }}/release/burn"
case "${{ matrix.target }}" in
*-apple-darwin)
strip -x "$BIN"
;;
aarch64-unknown-linux-gnu)
aarch64-linux-gnu-strip "$BIN"
;;
*-unknown-linux-gnu)
strip "$BIN"
;;
esac
ls -lh "$BIN"
- name: Stage binary into platform package
# Mirror the layout the publish step will rely on:
# `packages/relayburn/npm/<short>/bin/burn`. The directory is
# gitignored at rest; the artifact upload below is what survives
# the matrix run for the publish job to download.
run: |
mkdir -p packages/relayburn/npm/${{ matrix.short }}/bin
cp target/${{ matrix.target }}/release/burn packages/relayburn/npm/${{ matrix.short }}/bin/burn
chmod +x packages/relayburn/npm/${{ matrix.short }}/bin/burn
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: relayburn-cli-${{ matrix.short }}
path: packages/relayburn/npm/${{ matrix.short }}/bin/burn
if-no-files-found: error
retention-days: 7
- name: Smoke test (`burn --help`)
# Native legs only. The aarch64-linux leg cross-compiles on an x64
# host so the runner's interpreter cannot execute the binary.
#
# When `release_version` is supplied (publish-workflow caller), we
# also assert that `burn --version` reports the expected version.
# This catches the regression where the binary was built with a
# stale `CARGO_PKG_VERSION` (the 2026-05-04 incident — 2.1.0
# platform package shipping a 2.0.0 binary).
if: matrix.target != 'aarch64-unknown-linux-gnu'
run: |
set -euo pipefail
EXPECTED_VERSION='${{ inputs.release_version }}'
assert_version() {
local label="$1"
local actual="$2"
if [ -z "$EXPECTED_VERSION" ]; then
echo "$label: $actual (no expected version supplied; skipping assertion)"
return 0
fi
local expected="burn $EXPECTED_VERSION"
if [ "$actual" != "$expected" ]; then
echo "::error title=Version mismatch::$label reported '$actual', expected '$expected'. The binary was likely built with a stale CARGO_PKG_VERSION — the publish workflow should have lockstepped Cargo.toml before this build."
exit 1
fi
echo "$label: $actual (matches expected)"
}
packages/relayburn/npm/${{ matrix.short }}/bin/burn --help
direct_version=$(packages/relayburn/npm/${{ matrix.short }}/bin/burn --version)
assert_version "direct binary" "$direct_version"
smoke_dir="$(mktemp -d)"
umbrella_dir="$(mktemp -d)"
trap 'rm -rf "$smoke_dir" "$umbrella_dir"' EXIT
npm install --prefix "$smoke_dir" --no-save --omit=optional \
--ignore-scripts --no-audit --no-fund \
./packages/relayburn/npm/${{ matrix.short }}
"$smoke_dir/node_modules/.bin/burn" --help
platform_version=$("$smoke_dir/node_modules/.bin/burn" --version)
assert_version "platform package" "$platform_version"
npm install --prefix "$umbrella_dir" --no-save --omit=optional \
--ignore-scripts --no-audit --no-fund \
./packages/relayburn
NODE_PATH="$smoke_dir/node_modules" "$umbrella_dir/node_modules/.bin/burn" --help
umbrella_version=$(NODE_PATH="$smoke_dir/node_modules" "$umbrella_dir/node_modules/.bin/burn" --version)
assert_version "umbrella package" "$umbrella_version"