Skip to content

Commit 29413ef

Browse files
committed
ci: gate npm publish on CI and Nix Build, assert full native bundle set
- Release now waits for the CI and Nix Build workflows to succeed on the same commit before publishing (npm publish is irreversible) - Publish-native-assets refuses a partial release when any of the six target bundles is missing - timeout-minutes on all release jobs
1 parent 98f55fb commit 29413ef

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,48 @@ on:
88
concurrency: ${{ github.workflow }}-${{ github.ref }}
99

1010
jobs:
11+
# Publishing to npm is irreversible — never let a commit that fails CI or
12+
# Nix Build ship. Those workflows run in parallel on the same push, so this
13+
# job blocks the release until both conclude successfully for this SHA.
14+
wait-for-checks:
15+
name: Wait for CI and Nix Build
16+
runs-on: ubuntu-latest
17+
if: github.repository_owner == 'Pythoughts-labs'
18+
timeout-minutes: 45
19+
permissions:
20+
actions: read
21+
contents: read
22+
steps:
23+
- name: Wait for required workflows on this commit
24+
env:
25+
GH_TOKEN: ${{ github.token }}
26+
SHA: ${{ github.sha }}
27+
REPO: ${{ github.repository }}
28+
run: |
29+
for workflow in "CI" "Nix Build"; do
30+
echo "Waiting for workflow: $workflow"
31+
while true; do
32+
# Transient API failures must not kill the gate (step shell is -e).
33+
pair=$(gh api "repos/$REPO/actions/runs?head_sha=$SHA&per_page=50" \
34+
--jq "[.workflow_runs[] | select(.name==\"$workflow\")][0] | \"\(.status)/\(.conclusion)\"" \
35+
2>/dev/null) || pair="api-error/null"
36+
case "$pair" in
37+
completed/success)
38+
echo "$workflow: success"; break ;;
39+
completed/*)
40+
echo "::error::$workflow concluded '${pair#completed/}' for $SHA — refusing to release."
41+
exit 1 ;;
42+
*)
43+
echo "$workflow: $pair — waiting..."; sleep 30 ;;
44+
esac
45+
done
46+
done
47+
1148
release:
1249
name: Release
50+
needs: wait-for-checks
1351
runs-on: ubuntu-latest
52+
timeout-minutes: 30
1453
if: github.repository_owner == 'Pythoughts-labs'
1554
outputs:
1655
packages_published: ${{ steps.changesets.outputs.published }}
@@ -77,6 +116,7 @@ jobs:
77116
# registry dependency), so no deploy webhook is fired here — this job only
78117
# verifies the published release is internally consistent.
79118
verify-cdn-release:
119+
timeout-minutes: 15
80120
name: Verify release consistency
81121
needs: release
82122
if: needs.release.outputs.packages_published == 'true'
@@ -96,6 +136,7 @@ jobs:
96136
run: node scripts/release/verify-release-consistency.mjs
97137

98138
update-brew-tap:
139+
timeout-minutes: 15
99140
name: Update Homebrew tap
100141
needs: release
101142
if: needs.release.outputs.packages_published == 'true'
@@ -146,6 +187,7 @@ jobs:
146187
APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
147188

148189
publish-native-assets:
190+
timeout-minutes: 15
149191
name: Publish native release assets
150192
needs:
151193
- release
@@ -166,6 +208,17 @@ jobs:
166208
path: dist-native-release
167209
merge-multiple: true
168210

211+
- name: Assert all native targets are present
212+
run: |
213+
missing=0
214+
for target in darwin-arm64 darwin-x64 linux-arm64 linux-x64 win32-arm64 win32-x64; do
215+
if ! ls dist-native-release/pythinker-code-"$target".zip >/dev/null 2>&1; then
216+
echo "::error::Missing native bundle for $target — refusing to publish a partial release."
217+
missing=1
218+
fi
219+
done
220+
exit $missing
221+
169222
- name: Produce manifest.json
170223
env:
171224
RELEASE_TAG: ${{ needs.release.outputs.pythinker_release_tag }}

0 commit comments

Comments
 (0)