Skip to content

Commit a1e2592

Browse files
runningcodeclaudeszokeasaurusrex
authored
ci(build): Add snapshot release workflow (#3212)
## Summary Adds a `workflow_dispatch`-triggered snapshot release pipeline that reuses the existing build workflow, enabling on-demand pre-release builds from any branch. For now we are only publishing to npm under the snapshot tag. ## Background We want to allow easy snapshot releases to ease internal testing as well as customer testing. ### What it does - **New `snapshot.yml` workflow**: Computes a semver-compliant snapshot version (e.g. `3.4.0-snapshot.20260312.abc1234`) by bumping the minor version from `Cargo.toml`, patches all version files via `scripts/bump-version.sh`, pushes a temporary snapshot branch, then triggers the build - **Makes `build.yml` callable**: Adds `workflow_call` inputs (`skip-signing`, `is-snapshot`, `checkout-ref`) so the snapshot workflow can reuse the full build matrix - **Skips unnecessary steps for snapshots**: macOS code signing/notarization, Python package builds, Docker image builds, and the release merge job are all conditionally skipped - **Publishes to npm under `snapshot` tag**: Platform-specific binary packages and the main `@sentry/cli` package are published with `--tag snapshot` so they don't affect the `latest` tag - **Cleans up after itself**: The temporary snapshot branch is deleted after publishing (or on failure) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]> Co-authored-by: Daniel Szoke <[email protected]>
1 parent 44c3a91 commit a1e2592

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

.github/workflows/build.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ on:
44
push:
55
branches:
66
- release/**
7+
workflow_call:
8+
inputs:
9+
is-snapshot:
10+
type: boolean
11+
default: false
12+
checkout-ref:
13+
type: string
14+
default: ''
715

816
jobs:
917
linux:
@@ -32,6 +40,8 @@ jobs:
3240

3341
steps:
3442
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
43+
with:
44+
ref: ${{ inputs.checkout-ref }}
3545

3646
- name: Add Rustup Target
3747
run: |
@@ -68,6 +78,8 @@ jobs:
6878

6979
steps:
7080
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
81+
with:
82+
ref: ${{ inputs.checkout-ref }}
7183

7284
- name: Add Rustup Target
7385
run: rustup target add ${{ matrix.target }}
@@ -155,6 +167,8 @@ jobs:
155167
steps:
156168
- name: Checkout repository
157169
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
170+
with:
171+
ref: ${{ inputs.checkout-ref }}
158172

159173
- name: Install `rcodesign`
160174
run: |
@@ -219,6 +233,8 @@ jobs:
219233

220234
steps:
221235
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
236+
with:
237+
ref: ${{ inputs.checkout-ref }}
222238

223239
# When rustup is updated, it tries to replace its binary, which on Windows is somehow locked.
224240
# This can result in the CI failure, see: https://github.com/rust-lang/rustup/issues/3029
@@ -251,6 +267,8 @@ jobs:
251267

252268
steps:
253269
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
270+
with:
271+
ref: ${{ inputs.checkout-ref }}
254272

255273
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6.2.0
256274
with:
@@ -280,10 +298,13 @@ jobs:
280298
if-no-files-found: 'error'
281299

282300
python-base:
301+
if: ${{ !inputs.is-snapshot }}
283302
name: python (base)
284303
runs-on: ubuntu-24.04
285304
steps:
286305
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
306+
with:
307+
ref: ${{ inputs.checkout-ref }}
287308
- name: Add Rustup Target
288309
run: rustup target add x86_64-unknown-linux-musl
289310
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # 6.2.0
@@ -297,11 +318,14 @@ jobs:
297318
if-no-files-found: 'error'
298319

299320
python:
321+
if: ${{ !inputs.is-snapshot }}
300322
name: python
301323
runs-on: ubuntu-24.04
302324
needs: [linux, sign-macos-binaries, windows, python-base]
303325
steps:
304326
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
327+
with:
328+
ref: ${{ inputs.checkout-ref }}
305329
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # 6.2.0
306330
with:
307331
python-version: '3.11'
@@ -328,6 +352,8 @@ jobs:
328352
needs: [linux, sign-macos-binaries, windows]
329353
steps:
330354
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
355+
with:
356+
ref: ${{ inputs.checkout-ref }}
331357
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6.2.0
332358
with:
333359
node-version: '20.10.0'
@@ -366,6 +392,7 @@ jobs:
366392
if-no-files-found: 'error'
367393

368394
platform-specific-docker:
395+
if: ${{ !inputs.is-snapshot }}
369396
name: Build Docker Image (${{ matrix.platform }})
370397
strategy:
371398
matrix:
@@ -380,6 +407,8 @@ jobs:
380407
packages: write
381408
steps:
382409
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
410+
with:
411+
ref: ${{ inputs.checkout-ref }}
383412

384413
- name: Set up Docker Buildx
385414
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # 4.0.0
@@ -402,6 +431,7 @@ jobs:
402431
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}
403432

404433
multiarch-docker:
434+
if: ${{ !inputs.is-snapshot }}
405435
name: Create Multi-Architecture Docker Image
406436
needs: platform-specific-docker
407437
runs-on: ubuntu-24.04
@@ -422,6 +452,7 @@ jobs:
422452
ghcr.io/${{ github.repository }}:${{ github.sha }}-arm64
423453
424454
merge:
455+
if: ${{ !inputs.is-snapshot }}
425456
name: Create Release Artifact
426457
runs-on: ubuntu-24.04
427458
needs: [linux, sign-macos-binaries, windows, npm-distributions, node, python]

.github/workflows/snapshot.yml

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
name: Snapshot Release
2+
3+
on:
4+
push:
5+
branches: [master]
6+
7+
permissions:
8+
contents: write
9+
10+
jobs:
11+
prepare:
12+
name: Prepare Snapshot
13+
runs-on: ubuntu-24.04
14+
outputs:
15+
version: ${{ steps.version.outputs.version }}
16+
ref: ${{ steps.push.outputs.ref }}
17+
steps:
18+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
19+
20+
# Computes a semver-compliant snapshot version based on the current
21+
# version in Cargo.toml. The patch version is bumped so that the
22+
# snapshot sorts higher than the current release but lower than the
23+
# next real release. For example, if Cargo.toml has 3.3.1, the
24+
# snapshot version will be 3.3.2-snapshot.20260312.abc1234.
25+
- name: Compute snapshot version
26+
id: version
27+
run: |
28+
CURRENT=$(cargo metadata --no-deps --format-version 1 \
29+
| jq -er '(.workspace_default_members[0]) as $id | .packages[] | select(.id == $id) | .version')
30+
MAJOR=$(echo "$CURRENT" | cut -d. -f1)
31+
MINOR=$(echo "$CURRENT" | cut -d. -f2)
32+
PATCH=$(echo "$CURRENT" | cut -d. -f3)
33+
NEXT_PATCH=$((PATCH + 1))
34+
DATE=$(date -u +%Y%m%d)
35+
SHORT_SHA=$(git rev-parse --short HEAD)
36+
VERSION="${MAJOR}.${MINOR}.${NEXT_PATCH}-snapshot.${DATE}.${SHORT_SHA}"
37+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
38+
echo "current=$CURRENT" >> "$GITHUB_OUTPUT"
39+
echo "Snapshot version: $VERSION"
40+
41+
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6.2.0
42+
with:
43+
node-version: '20.10.0'
44+
45+
- name: Bump versions
46+
run: scripts/bump-version.sh "${{ steps.version.outputs.current }}" "${{ steps.version.outputs.version }}"
47+
48+
- name: Push snapshot branch
49+
id: push
50+
run: |
51+
BRANCH="snapshot/${{ steps.version.outputs.version }}"
52+
git config user.name "github-actions[bot]"
53+
git config user.email "github-actions[bot]@users.noreply.github.com"
54+
git checkout -b "$BRANCH"
55+
git add -A
56+
git commit -m "snapshot: ${{ steps.version.outputs.version }}"
57+
git push origin "$BRANCH"
58+
echo "ref=$BRANCH" >> "$GITHUB_OUTPUT"
59+
60+
build:
61+
name: Build
62+
needs: prepare
63+
uses: ./.github/workflows/build.yml
64+
with:
65+
is-snapshot: true
66+
checkout-ref: ${{ needs.prepare.outputs.ref }}
67+
secrets: inherit
68+
69+
publish-npm:
70+
name: Publish to npm
71+
needs: [prepare, build]
72+
runs-on: ubuntu-24.04
73+
steps:
74+
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6.2.0
75+
with:
76+
node-version: '20.10.0'
77+
registry-url: 'https://registry.npmjs.org'
78+
79+
- name: Download npm binary distributions
80+
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # 8.0.0
81+
with:
82+
name: artifact-npm-binary-distributions
83+
path: npm-distributions
84+
85+
- name: Download node package
86+
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # 8.0.0
87+
with:
88+
name: artifact-pkg-node
89+
path: node-package
90+
91+
- name: Publish platform packages
92+
env:
93+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
94+
run: |
95+
for pkg in npm-distributions/*/*.tgz; do
96+
echo "Publishing $pkg"
97+
npm publish "$pkg" --tag snapshot
98+
done
99+
100+
- name: Publish main package
101+
env:
102+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
103+
run: |
104+
npm publish node-package/*.tgz --tag snapshot
105+
106+
cleanup:
107+
name: Cleanup
108+
needs: [prepare, publish-npm]
109+
if: always()
110+
runs-on: ubuntu-24.04
111+
steps:
112+
- name: Delete snapshot branch
113+
if: needs.prepare.outputs.ref != ''
114+
env:
115+
GH_TOKEN: ${{ github.token }}
116+
run: |
117+
gh api -X DELETE "repos/${{ github.repository }}/git/refs/heads/${{ needs.prepare.outputs.ref }}"

0 commit comments

Comments
 (0)