release #45
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 | |
| on: | |
| push: | |
| tags: | |
| - 'v*.*.*' | |
| permissions: | |
| contents: write # to create the GitHub Release | |
| id-token: write # OIDC token used by npm trusted publishing | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| environment: npm-publish | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 24 | |
| registry-url: https://registry.npmjs.org/ | |
| - run: npm ci --ignore-scripts | |
| - run: npm run build | |
| - run: npm test | |
| - name: Verify package.json version matches the tag | |
| run: | | |
| tag="${GITHUB_REF#refs/tags/v}" | |
| pkg=$(node -p "require('./package.json').version") | |
| if [ "$tag" != "$pkg" ]; then | |
| echo "tag $tag does not match package.json $pkg" >&2 | |
| exit 1 | |
| fi | |
| - name: Verify this version is not already on npm | |
| id: npm-guard | |
| run: | | |
| name=$(node -p "require('./package.json').name") | |
| pkg=$(node -p "require('./package.json').version") | |
| if npm view "$name@$pkg" version --silent >/dev/null 2>&1; then | |
| echo "already=true" >> "$GITHUB_OUTPUT" | |
| echo "::error::$name@$pkg is already published. npm rejects duplicate versions — bump and tag again." >&2 | |
| exit 1 | |
| fi | |
| # OIDC trusted publishing requires npm >= 11.5.1. Invoke via npx | |
| # so we always get a recent enough CLI without mutating the | |
| # global npm install on the runner. | |
| - id: publish | |
| run: npx -y npm@latest publish --access public --provenance | |
| - uses: softprops/action-gh-release@v3 | |
| with: | |
| generate_release_notes: true | |
| # A tag that produced no published version is a trap: it cannot be | |
| # re-pushed, so every retry needs manual tag surgery. Drop it — but only | |
| # when the publish itself did not succeed. If the package went out and a | |
| # later step failed, the tag must stay, because npm will not accept the | |
| # same version twice and that release has to be finished by hand. | |
| # | |
| # The npm guard is excluded on purpose. A single tag push can produce two | |
| # runs; concurrency queues the second one, so it starts after the first | |
| # has already published and trips the guard. That run must not delete the | |
| # tag its sibling just released from. | |
| - name: Drop the tag if nothing was published | |
| if: failure() && steps.publish.outcome != 'success' && steps.npm-guard.outputs.already != 'true' | |
| run: git push --delete origin "$GITHUB_REF_NAME" |