release #1
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
| # Release pipeline driven by the canonical VERSION file. | |
| # | |
| # Trigger: push of a tag matching v*.*.* (e.g. v1.0.1, v1.2.3-beta.1). | |
| # | |
| # Steps: | |
| # 1. Guard: the tag matches VERSION, and every derived version is already | |
| # in sync. The local flow is `sync-version.sh` before tagging, so a | |
| # mismatch here means the human forgot to commit the bump. | |
| # 2. Publish to npm via Trusted Publisher (OIDC). | |
| # 3. Cut a GitHub Release. | |
| # | |
| # Auth: npm Trusted Publisher (OIDC). No NPM_TOKEN secret. The binding on | |
| # npmjs.com requires publishes from this repo, this workflow file, and the | |
| # `production` environment — all three must match. | |
| name: release | |
| on: | |
| push: | |
| tags: | |
| - 'v*.*.*' | |
| permissions: | |
| contents: write # for creating the GitHub Release | |
| id-token: write # for npm publish --provenance (OIDC attestation) | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| # The `production` environment gates the publish step behind a required | |
| # reviewer (configured in repo Settings → Environments). A pushed tag | |
| # won't ship to npm until a human approves the deployment. | |
| environment: production | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # full history + tags so git-cliff can build release notes | |
| - name: Resolve version from tag | |
| id: ver | |
| run: | | |
| tag="${GITHUB_REF_NAME}" | |
| version="${tag#v}" | |
| file_version="$(tr -d '[:space:]' < VERSION)" | |
| if [[ "$version" != "$file_version" ]]; then | |
| echo "::error::Tag ($version) does not match VERSION file ($file_version). Bump VERSION + run scripts/release/sync-version.sh before tagging." >&2 | |
| exit 1 | |
| fi | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| echo "Releasing $version" | |
| - name: Verify derived files are in sync | |
| run: bash scripts/release/sync-version.sh --check | |
| - name: Set up Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| # Intentionally NOT setting `registry-url` — that injects a | |
| # `_authToken=${NODE_AUTH_TOKEN}` line into a generated .npmrc and | |
| # sets NODE_AUTH_TOKEN to a placeholder. npm then sees a non-empty | |
| # token and skips the Trusted Publisher OIDC exchange, ending in a | |
| # 404 from registry.npmjs.org. With no registry-url, npm uses its | |
| # default registry and falls through to OIDC. | |
| - name: Upgrade npm for Trusted Publisher OIDC | |
| # npm CLI >= 11.5.1 picks up the GitHub OIDC token automatically and | |
| # exchanges it with npmjs.com. Node 22's bundled npm (10.x) doesn't. | |
| run: | | |
| npm install -g npm@latest | |
| hash -r | |
| npm --version | |
| - name: Publish to npm | |
| env: | |
| VERSION: ${{ steps.ver.outputs.version }} | |
| run: | | |
| published=$(npm view "agmsg@$VERSION" version 2>/dev/null || true) | |
| if [[ "$published" == "$VERSION" ]]; then | |
| echo "agmsg@$VERSION already on npm — skipping publish" | |
| exit 0 | |
| fi | |
| # --provenance attaches a signed GitHub attestation linking the | |
| # tarball to this workflow run. No NODE_AUTH_TOKEN — auth comes | |
| # from the Trusted Publisher OIDC exchange. | |
| npm publish --access public --provenance | |
| # Build release notes for this tag from Conventional Commits, matching | |
| # the CHANGELOG.md format. `--latest` emits only the newest release's | |
| # section; `--strip header` drops the file preamble. | |
| - name: Generate release notes | |
| uses: orhun/git-cliff-action@v4.8.0 | |
| id: cliff | |
| with: | |
| config: cliff.toml | |
| args: --latest --strip header | |
| env: | |
| OUTPUT: RELEASE_NOTES.md | |
| - name: Create GitHub Release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION: ${{ steps.ver.outputs.version }} | |
| run: | | |
| if gh release view "v$VERSION" >/dev/null 2>&1; then | |
| echo "Release v$VERSION already exists — skipping" | |
| exit 0 | |
| fi | |
| # Fall back to a minimal note if git-cliff produced nothing. | |
| if [ ! -s RELEASE_NOTES.md ]; then | |
| echo "Release $VERSION. See [commit history](../../commits/v$VERSION) for details." > RELEASE_NOTES.md | |
| fi | |
| gh release create "v$VERSION" \ | |
| --title "v$VERSION" \ | |
| --notes-file RELEASE_NOTES.md |