Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 44 additions & 22 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
# Manual release publishing using npm Trusted Publishing (OIDC).
# Never triggered by a GitHub release or tag push.
name: Publish to npm

# Publication is deliberately manual. Creating or publishing a GitHub release
# must never publish to npm automatically, so this workflow only runs when a
# maintainer dispatches it by hand for an authorised release.
on:
workflow_dispatch:
inputs:
tag:
description: "Existing release tag being published (informational only)"
required: false
description: "Existing release tag (for example v0.3.0)"
required: true
type: string

permissions:
Expand All @@ -18,33 +17,56 @@ permissions:
jobs:
publish:
runs-on: ubuntu-latest

steps:
- name: Checkout
- name: Validate input and checkout tag
env:
RELEASE_TAG: ${{ inputs.tag }}
run: |
set -eu
if ! printf '%s' "$RELEASE_TAG" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "Expected a stable release tag such as v1.2.3" >&2
exit 1
fi
- name: Checkout release tag
uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Qualify the checkout ref as a tag

If a branch named v0.3.0 exists, this checkout selects that branch ahead of the identically named tag; it also accepts the branch when no such tag exists. The checkout v4 implementation checks branchExists before tagExists for unqualified refs. If the branch's package version matches, the subsequent version check passes and this workflow publishes branch contents rather than the requested release artifact. Use ref: refs/tags/${{ inputs.tag }} so checkout requires the exact tag and cannot resolve to a branch.

Useful? React with 👍 / 👎.

persist-credentials: false

- name: Setup Node
- name: Set up Node for npm Trusted Publishing
uses: actions/setup-node@v4
with:
node-version: 22
node-version: '24'
registry-url: https://registry.npmjs.org
package-manager-cache: false

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Require current npm OIDC client
run: npm install --global 'npm@^11.5.1'

- name: Verify version and tag
env:
RELEASE_TAG: ${{ inputs.tag }}
run: |
set -eu
actual="$(node -p "require('./package.json').version")"
test "$RELEASE_TAG" = "v$actual" || {
echo "Version mismatch: $RELEASE_TAG vs $actual" >&2
exit 1
}
echo "Verified release $RELEASE_TAG"

- name: Install dependencies
run: npm ci
- name: Set up Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Typecheck
run: npm run typecheck

- name: Build
run: npm run build

- name: Test
run: npm test
- name: Typecheck, build and test
run: |
npm run typecheck
npm run build
npm test

- name: Publish
- name: Publish using OIDC
run: npm publish --access public
Loading