Skip to content
Merged
Show file tree
Hide file tree
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
12 changes: 0 additions & 12 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,9 @@ jobs:
name: Run tests
command: yarn test:ci

release:
<<: *defaults

steps:
- checkout
- run: yarn install
- run: yarn build
- run: yarn semantic-release

workflows:
version: 2

test:
jobs:
- test
- release:
requires:
- test
73 changes: 73 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# CAVEAT: This repo currently publishes via semantic-release (see `npm run semantic-release`
# in package.json and the `release` job in .circleci/config.yml). semantic-release cannot emit
# `npm stage publish`, so this staged-publishing workflow is NOT yet wired into the live release
# path. Before adopting it, the semantic-release flow must be reconciled with OIDC staged
# publishing (decide which owns version bump + publish, and remove the duplicate). Also note the
# Node bump: package.json engines was `>=6.0.0` and CircleCI used Node 12.21 — .nvmrc is now
# 22.14.0 because npm >= 11.15.0 (staged publishing) requires Node >= 22.14.0.
name: Publish (staged)

on:
release:
types: [published] # cutting a Release creates the tag AND fires this

permissions:
contents: read # workflow default (least privilege); only stage-publish also needs id-token, granted on that job

jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: { persist-credentials: false }
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: '.nvmrc' # pin >= 22.14.0
package-manager-cache: false # release-triggered: disable auto-cache (zizmor cache-poisoning)
- name: Assert Release tag matches package.json version
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
PKG="$(node -p "require('./package.json').version")"
[ "${RELEASE_TAG#v}" = "$PKG" ] || { echo "tag $RELEASE_TAG != package.json v$PKG"; exit 1; }
- name: Refuse releases not on the default branch
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: |
git fetch origin "$DEFAULT_BRANCH" --depth=1
git merge-base --is-ancestor "$GITHUB_SHA" "origin/$DEFAULT_BRANCH" \
|| { echo "release $RELEASE_TAG not reachable from $DEFAULT_BRANCH — refusing"; exit 1; }

stage-publish:
needs: verify
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # OIDC trusted publishing: only this job mints the token
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: { persist-credentials: false }
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: '.nvmrc'
registry-url: 'https://registry.npmjs.org'
package-manager-cache: false
- run: yarn install --frozen-lockfile
- run: yarn build
- run: npm install -g npm@11.15.0 # npm CLI: staged publishing needs npm >= 11.15.0
- name: Resolve dist-tag (a prerelease must never go to `latest`)
id: disttag
env:
PRERELEASE_TAG: next
run: |
VERSION="$(node -p "require('./package.json').version")"
case "$VERSION" in
*-*) TAG="$PRERELEASE_TAG" ;;
*) TAG="latest" ;;
esac
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
- name: Stage publish
env:
DIST_TAG: ${{ steps.disttag.outputs.tag }}
run: npm stage publish --tag "$DIST_TAG"
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22.14.0