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
36 changes: 22 additions & 14 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,30 +65,38 @@ jobs:
- name: Install dependencies
run: npm ci

# Skip when this exact version is already on npm. `npm publish` over an
# Skip when this commit did not bump the version. `npm publish` over an
# existing version is a hard E403, which turned every unbumped merge —
# Dependabot's, and CI-only PRs now that the bump gate exempts them —
# into a red publish run (run 33714086138, 2026-09-02). The package is
# `access: restricted`, so the lookup needs the read-only NPM_TOKEN;
# the publish itself stays on OIDC trusted publishing.
- name: Check if version already published
# into a red publish run (runs 33714086138 and 33715159834, 2026-09-02).
# Compared against HEAD^ in git rather than looked up on npm: the
# package is `access: restricted`, and this repo has no NPM_TOKEN, so an
# unauthenticated `npm view` reports 404 for every version — which is
# exactly what the first attempt at this guard did (#20). Same rule the
# private libraries apply via verify-version-bump's push-side output.
# The checkout above is fetch-depth 2 for this comparison. A manual
# dispatch always attempts the publish (that is what it is for).
- name: Check if this commit bumped the version
id: check
shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
DISPATCHED: ${{ github.event_name == 'workflow_dispatch' }}
run: |
set -euo pipefail
NAME=$(node -p "require('./package.json').name")
VERSION=$(node -p "require('./package.json').version")
if npm view "${NAME}@${VERSION}" version >/dev/null 2>&1; then
echo "published=true" >> "$GITHUB_OUTPUT"
echo "::notice::${NAME}@${VERSION} already on npm — no version bump on this commit, skipping publish."
read_version() {
node -p "(() => { const s = require('fs').readFileSync(0, 'utf8'); try { return JSON.parse(s).version || '' } catch { return '' } })()"
}
CUR=$(node -p "require('./package.json').version")
PREV=$(git show HEAD^:package.json 2>/dev/null | read_version || true)
if [ "$DISPATCHED" != "true" ] && [ "$CUR" = "$PREV" ]; then
echo "bumped=false" >> "$GITHUB_OUTPUT"
echo "::notice::version unchanged ($CUR) against HEAD^ — nothing to publish."
else
echo "published=false" >> "$GITHUB_OUTPUT"
echo "${NAME}@${VERSION} not yet published — will publish."
echo "bumped=true" >> "$GITHUB_OUTPUT"
echo "Version ${PREV:-<none>} -> $CUR; publishing."
fi

# No build step: this package ships index.js / index.d.ts directly.
- name: Publish to npm
if: steps.check.outputs.published != 'true'
if: steps.check.outputs.bumped == 'true'
run: npm publish
Loading