@@ -10,6 +10,11 @@ concurrency:
1010 group : ci-${{ github.ref }}
1111 cancel-in-progress : true
1212
13+ # packages:write is needed for publish-nightly to push to GHCR
14+ permissions :
15+ contents : read
16+ packages : write
17+
1318env :
1419 # Commit timestamp used for deterministic nightly version strings.
1520 # Defined at workflow level so build-binary and publish-nightly always agree.
2429 outputs :
2530 skill : ${{ steps.filter.outputs.skill == 'true' || startsWith(github.ref, 'refs/heads/release/') }}
2631 code : ${{ steps.filter.outputs.code == 'true' || startsWith(github.ref, 'refs/heads/release/') }}
32+ build-targets : ${{ steps.targets.outputs.matrix }}
33+ nightly-version : ${{ steps.nightly.outputs.version }}
2734 steps :
2835 - uses : actions/checkout@v4
2936 - uses : dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
4552 - 'package.json'
4653 - 'bun.lock'
4754 - '.github/workflows/ci.yml'
55+ - name : Compute build matrix
56+ id : targets
57+ run : |
58+ {
59+ echo 'matrix<<MATRIX_EOF'
60+ if [[ "${{ github.event_name }}" == "pull_request" ]]; then
61+ # PRs only need linux-x64 for smoke test and e2e — skip macOS/Windows
62+ echo '{"include":[
63+ {"target":"linux-x64", "os":"ubuntu-latest", "can-test":true}
64+ ]}'
65+ else
66+ # main, release/**, workflow_call: full cross-platform matrix
67+ echo '{"include":[
68+ {"target":"darwin-arm64", "os":"macos-latest", "can-test":true},
69+ {"target":"linux-x64", "os":"ubuntu-latest", "can-test":true},
70+ {"target":"windows-x64", "os":"windows-latest","can-test":true},
71+ {"target":"darwin-x64", "os":"macos-latest", "can-test":false},
72+ {"target":"linux-arm64", "os":"ubuntu-latest", "can-test":false}
73+ ]}'
74+ fi
75+ echo 'MATRIX_EOF'
76+ } >> "$GITHUB_OUTPUT"
77+ - name : Compute nightly version
78+ id : nightly
79+ if : github.ref == 'refs/heads/main' && github.event_name == 'push'
80+ run : |
81+ TS=$(date -d "$COMMIT_TIMESTAMP" +%s)
82+ CURRENT=$(jq -r .version package.json)
83+ VERSION=$(echo "$CURRENT" | sed "s/-dev\.[0-9]*$/-dev.${TS}/")
84+ echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
85+ echo "Nightly version: ${VERSION}"
4886
4987 check-skill :
5088 name : Check SKILL.md
@@ -138,29 +176,11 @@ jobs:
138176
139177 build-binary :
140178 name : Build Binary (${{ matrix.target }})
141- needs : [lint, test-unit]
179+ needs : [changes, lint, test-unit]
142180 runs-on : ${{ matrix.os }}
143181 strategy :
144182 fail-fast : false
145- matrix :
146- include :
147- # Native builds (can run smoke test)
148- - target : darwin-arm64
149- os : macos-latest
150- can-test : true
151- - target : linux-x64
152- os : ubuntu-latest
153- can-test : true
154- - target : windows-x64
155- os : windows-latest
156- can-test : true
157- # Cross-compiled builds (cannot run smoke test)
158- - target : darwin-x64
159- os : macos-latest
160- can-test : false
161- - target : linux-arm64
162- os : ubuntu-latest
163- can-test : false
183+ matrix : ${{ fromJSON(needs.changes.outputs.build-targets) }}
164184 steps :
165185 - uses : actions/checkout@v4
166186 - uses : oven-sh/setup-bun@v2
@@ -184,22 +204,18 @@ jobs:
184204 echo "All install attempts failed"
185205 exit 1
186206 - name : Set nightly version
187- # Inject a nightly version into package.json before the build so it gets
188- # baked into the binary. Only runs on direct pushes to main.
189- # Uses the commit timestamp (seconds since epoch) as a deterministic
190- # value so every matrix leg and publish-nightly produce the same version
191- # string for a given commit.
192- if : github.ref == 'refs/heads/main' && github.event_name == 'push'
207+ # Inject the nightly version (computed once in the changes job) into
208+ # package.json before the build so it gets baked into the binary.
209+ if : needs.changes.outputs.nightly-version != ''
193210 shell : bash
194211 run : |
195- TS=$(date -d "$COMMIT_TIMESTAMP" +%s 2>/dev/null || date -jf "%Y-%m-%dT%H:%M:%SZ" "$COMMIT_TIMESTAMP" +%s)
196- CURRENT=$(jq -r .version package.json)
197- NIGHTLY=$(echo "$CURRENT" | sed "s/-dev\.[0-9]*$/-dev.${TS}/")
198- jq --arg v "$NIGHTLY" '.version = $v' package.json > package.json.tmp
212+ jq --arg v "${{ needs.changes.outputs.nightly-version }}" '.version = $v' package.json > package.json.tmp
199213 mv package.json.tmp package.json
200214 - name : Build
201215 env :
202216 SENTRY_CLIENT_ID : ${{ vars.SENTRY_CLIENT_ID }}
217+ # Set on main/release branches so build.ts runs binpunch + creates .gz
218+ RELEASE_BUILD : ${{ github.event_name != 'pull_request' && '1' || '' }}
203219 run : bun run build --target ${{ matrix.target }}
204220 - name : Smoke test
205221 if : matrix.can-test
@@ -210,11 +226,56 @@ jobs:
210226 else
211227 ./dist-bin/sentry-${{ matrix.target }} --help
212228 fi
213- - name : Upload artifact
229+ - name : Upload binary artifact
214230 uses : actions/upload-artifact@v4
215231 with :
216232 name : sentry-${{ matrix.target }}
217- path : dist-bin/sentry-*
233+ path : |
234+ dist-bin/sentry-*
235+ !dist-bin/*.gz
236+
237+ - name : Upload compressed artifact
238+ if : env.RELEASE_BUILD == '1'
239+ uses : actions/upload-artifact@v4
240+ with :
241+ name : sentry-${{ matrix.target }}-gz
242+ path : dist-bin/*.gz
243+
244+ publish-nightly :
245+ name : Publish Nightly to GHCR
246+ # Only run on pushes to main, not on PRs or release branches
247+ if : github.ref == 'refs/heads/main' && github.event_name == 'push'
248+ needs : [changes, build-binary]
249+ runs-on : ubuntu-latest
250+ steps :
251+ - name : Download compressed artifacts
252+ uses : actions/download-artifact@v4
253+ with :
254+ pattern : sentry-*-gz
255+ path : artifacts
256+ merge-multiple : true
257+
258+ - name : Install ORAS CLI
259+ run : |
260+ VERSION=1.2.3
261+ EXPECTED_SHA256="b4efc97a91f471f323f193ea4b4d63d8ff443ca3aab514151a30751330852827"
262+ TARBALL="oras_${VERSION}_linux_amd64.tar.gz"
263+ curl -sfLo "$TARBALL" "https://github.com/oras-project/oras/releases/download/v${VERSION}/${TARBALL}"
264+ echo "${EXPECTED_SHA256} ${TARBALL}" | sha256sum -c -
265+ tar -xz -C /usr/local/bin oras < "$TARBALL"
266+ rm "$TARBALL"
267+
268+ - name : Log in to GHCR
269+ run : echo "${{ secrets.GITHUB_TOKEN }}" | oras login ghcr.io -u ${{ github.actor }} --password-stdin
270+
271+ - name : Push to GHCR
272+ run : |
273+ VERSION="${{ needs.changes.outputs.nightly-version }}"
274+ oras push ghcr.io/getsentry/cli:nightly \
275+ --artifact-type application/vnd.sentry.cli.nightly \
276+ --annotation "org.opencontainers.image.source=https://github.com/getsentry/cli" \
277+ --annotation "version=${VERSION}" \
278+ artifacts/*.gz
218279
219280 test-e2e :
220281 name : E2E Tests
@@ -301,69 +362,6 @@ jobs:
301362 name : gh-pages
302363 path : gh-pages.zip
303364
304- publish-nightly :
305- name : Publish Nightly
306- # Only publish after a successful main-branch build+test. Skipped on PRs
307- # and release branches.
308- needs : [build-binary, test-e2e]
309- if : github.ref == 'refs/heads/main' && github.event_name == 'push'
310- runs-on : ubuntu-latest
311- permissions :
312- contents : write
313- steps :
314- - uses : actions/checkout@v4
315- with :
316- sparse-checkout : package.json
317- - name : Compute nightly version
318- # Uses the commit timestamp — the same value as build-binary — so
319- # version.json exactly matches the version baked into the binaries.
320- id : version
321- run : |
322- TS=$(date -d "$COMMIT_TIMESTAMP" +%s)
323- CURRENT=$(jq -r .version package.json)
324- VERSION=$(echo "$CURRENT" | sed "s/-dev\.[0-9]*$/-dev.${TS}/")
325- echo "version=$VERSION" >> "$GITHUB_OUTPUT"
326- - name : Download all binary artifacts
327- uses : actions/download-artifact@v4
328- with :
329- pattern : sentry-*
330- path : artifacts
331- merge-multiple : true
332- - name : Create version.json
333- run : |
334- cat > version.json <<EOF
335- {"version":"${{ steps.version.outputs.version }}","sha":"${{ github.sha }}","date":"$(date -u +%Y-%m-%dT%H:%M:%SZ)"}
336- EOF
337- - name : Create or update nightly release
338- env :
339- GH_TOKEN : ${{ github.token }}
340- GH_REPO : ${{ github.repository }}
341- run : |
342- # Create the release the first time; subsequent runs are a no-op
343- gh release create nightly \
344- --prerelease \
345- --title "Nightly" \
346- --notes "" \
347- 2>/dev/null || true
348-
349- # Update release notes with the latest version + commit
350- gh release edit nightly \
351- --prerelease \
352- --notes "Latest nightly build from the \`main\` branch.
353-
354- **Version:** \`${{ steps.version.outputs.version }}\`
355- **Commit:** ${{ github.sha }}"
356-
357- # Delete all existing assets first so removed/renamed files don't linger
358- gh release view nightly --json assets --jq '.assets[].name' | while read -r name; do
359- gh release delete-asset nightly "$name" --yes
360- done
361-
362- # Upload the new .gz binaries and the version manifest
363- gh release upload nightly \
364- artifacts/*.gz \
365- version.json
366-
367365 ci-status :
368366 name : CI Status
369367 if : always()
@@ -374,6 +372,7 @@ jobs:
374372 - name : Check CI status
375373 run : |
376374 # Check for explicit failures or cancellations in all jobs
375+ # publish-nightly is skipped on PRs (if: github.ref == 'refs/heads/main') — that's expected
377376 results="${{ needs.check-skill.result }} ${{ needs.build-binary.result }} ${{ needs.build-npm.result }} ${{ needs.build-docs.result }} ${{ needs.test-e2e.result }} ${{ needs.publish-nightly.result }}"
378377 for result in $results; do
379378 if [[ "$result" == "failure" || "$result" == "cancelled" ]]; then
0 commit comments