fix(pkg): ship JoltPhysics/Build/ — bloom_jolt depends on its CMakeLists #2
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| # Fires on a version tag push (e.g. `v0.3.2`). Gates on the Tests workflow | |
| # passing for the exact same commit, then creates/updates the GitHub Release | |
| # and publishes the package to npm as @bloomengine/engine. | |
| # | |
| # The /release Claude Code skill in .claude/skills/release/ drives this end | |
| # to end: it bumps the version in package.json, commits, tags, pushes, and | |
| # waits for this workflow to go green. | |
| # | |
| # Authentication: npm trusted publishing. The @bloomengine/engine package is | |
| # configured on npmjs.com with this workflow (Bloom-Engine/engine → | |
| # .github/workflows/release.yml → job publish-npm) as a trusted publisher. | |
| # `id-token: write` on the publish job is enough — `npm publish` exchanges | |
| # the GitHub OIDC token for a short-lived publish credential, no NPM_TOKEN | |
| # secret needed. Provenance attestation is automatic under this flow. | |
| on: | |
| push: | |
| tags: ['v*'] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Existing tag to (re-)publish a release for (e.g. v0.3.2)" | |
| required: true | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false # never cancel a release mid-flight | |
| permissions: | |
| contents: write | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Gate: wait for `Tests` to pass on this commit before we create the GitHub | |
| # Release. Same pattern as Perry's release-packages.yml — query the API by | |
| # workflow filename + head_sha and poll until it completes. Fails loud if | |
| # Tests failed so we don't ship a known-broken tag. | |
| # --------------------------------------------------------------------------- | |
| await-tests: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Wait for Tests workflow to pass | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| REPO: ${{ github.repository }} | |
| SHA: ${{ github.sha }} | |
| EVENT: ${{ github.event_name }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$EVENT" = "workflow_dispatch" ]; then | |
| echo "workflow_dispatch — bypassing test gate (manual republish)." | |
| exit 0 | |
| fi | |
| echo "Gating release on commit $SHA" | |
| deadline=$(( SECONDS + 45 * 60 )) | |
| retry_on_error=1 | |
| while :; do | |
| set +e | |
| api_out=$(gh api \ | |
| "/repos/$REPO/actions/workflows/test.yml/runs?head_sha=$SHA&per_page=1" \ | |
| 2>&1) | |
| rc=$? | |
| set -e | |
| if [ $rc -ne 0 ]; then | |
| echo " gh api failed (rc=$rc):" | |
| echo "$api_out" | awk '{print " " $0}' | |
| if [ $retry_on_error -gt 0 ]; then | |
| retry_on_error=0 | |
| echo " retrying once after 10s" | |
| sleep 10 | |
| continue | |
| fi | |
| echo " gh api still failing after retry — failing gate." | |
| exit 1 | |
| fi | |
| retry_on_error=1 | |
| status=$(echo "$api_out" | jq -r '.workflow_runs[0].status // empty') | |
| conclusion=$(echo "$api_out" | jq -r '.workflow_runs[0].conclusion // empty') | |
| url=$(echo "$api_out" | jq -r '.workflow_runs[0].html_url // empty') | |
| if [ -z "$status" ]; then | |
| echo " no Tests run found yet for $SHA — waiting" | |
| elif [ "$status" = "completed" ]; then | |
| if [ "$conclusion" = "success" ]; then | |
| echo " OK Tests passed: $url" | |
| break | |
| else | |
| echo " FAIL Tests $conclusion: $url" | |
| exit 1 | |
| fi | |
| else | |
| echo " Tests: $status ($url) — waiting" | |
| fi | |
| if [ $SECONDS -ge $deadline ]; then | |
| echo " timed out waiting for Tests" | |
| exit 1 | |
| fi | |
| sleep 30 | |
| done | |
| echo "Gate passed — proceeding to publish." | |
| # --------------------------------------------------------------------------- | |
| # Create (or update) the GitHub Release for this tag. The /release skill | |
| # usually creates the release *body* from the CLI after pushing the tag; | |
| # this job is a safety net: if the tag exists but no release does yet, it | |
| # creates one with auto-generated notes. | |
| # --------------------------------------------------------------------------- | |
| github-release: | |
| needs: await-tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Resolve tag | |
| id: tag | |
| env: | |
| DISPATCH_TAG: ${{ github.event.inputs.tag }} | |
| run: | | |
| if [ -n "$DISPATCH_TAG" ]; then | |
| TAG="$DISPATCH_TAG" | |
| else | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| fi | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" | |
| - name: Create GitHub Release (if missing) | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAG: ${{ steps.tag.outputs.tag }} | |
| run: | | |
| if gh release view "$TAG" >/dev/null 2>&1; then | |
| echo "Release $TAG already exists — leaving body alone." | |
| exit 0 | |
| fi | |
| echo "Creating release $TAG with auto-generated notes." | |
| gh release create "$TAG" \ | |
| --title "$TAG" \ | |
| --generate-notes | |
| - name: Verify package.json version matches tag | |
| env: | |
| VERSION: ${{ steps.tag.outputs.version }} | |
| run: | | |
| PKG_VERSION=$(node -p "require('./package.json').version") | |
| if [ "$PKG_VERSION" != "$VERSION" ]; then | |
| echo "WARNING package.json version ($PKG_VERSION) does not match tag ($VERSION)." | |
| echo " This is normally a bug — the /release skill should bump package.json" | |
| echo " and commit before tagging. Continuing, but investigate." | |
| else | |
| echo "OK package.json version matches tag ($VERSION)" | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # Publish the package to npm as @bloomengine/engine. Runs after the GitHub | |
| # Release so a failure here doesn't leave a dangling release-but-no-package | |
| # state. Skips cleanly if the version is already on the registry, which | |
| # keeps re-runs idempotent (workflow_dispatch on an existing tag won't | |
| # double-publish or fail). | |
| # | |
| # We check out submodules recursively because scripts/prepack.sh refuses | |
| # to ship a tarball without the JoltPhysics sources materialised — the | |
| # package vendors them rather than relying on a postinstall git clone. | |
| # --------------------------------------------------------------------------- | |
| publish-npm: | |
| needs: github-release | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| id-token: write # required for npm provenance attestations | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - uses: actions/setup-node@v5 | |
| with: | |
| node-version: "24" | |
| registry-url: "https://registry.npmjs.org" | |
| - name: Resolve tag | |
| id: tag | |
| env: | |
| DISPATCH_TAG: ${{ github.event.inputs.tag }} | |
| run: | | |
| if [ -n "$DISPATCH_TAG" ]; then | |
| TAG="$DISPATCH_TAG" | |
| else | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| fi | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" | |
| - name: Verify package.json version matches tag | |
| env: | |
| VERSION: ${{ steps.tag.outputs.version }} | |
| TAG: ${{ steps.tag.outputs.tag }} | |
| run: | | |
| PKG_VERSION=$(node -p "require('./package.json').version") | |
| if [ "$PKG_VERSION" != "$VERSION" ]; then | |
| echo "::error::Tag $TAG ($VERSION) does not match package.json ($PKG_VERSION) — refusing to publish." | |
| exit 1 | |
| fi | |
| - name: Check if version already published | |
| id: check | |
| run: | | |
| PKG_NAME=$(node -p "require('./package.json').name") | |
| PKG_VERSION=$(node -p "require('./package.json').version") | |
| if npm view "$PKG_NAME@$PKG_VERSION" version >/dev/null 2>&1; then | |
| echo "$PKG_NAME@$PKG_VERSION is already on the registry — skipping publish." | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "$PKG_NAME@$PKG_VERSION not yet published — will publish." | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Publish to npm | |
| if: steps.check.outputs.skip == 'false' | |
| run: npm publish --provenance --access public |