Skip to content

chore(release): v0.3.4 #23

chore(release): v0.3.4

chore(release): v0.3.4 #23

Workflow file for this run

name: Publish to npm
on:
push:
tags: ['v*']
workflow_dispatch:
inputs:
ref:
description: 'Git ref (tag or SHA) to publish'
required: true
type: string
permissions:
contents: read
jobs:
publish:
runs-on: ubuntu-latest
# id-token: write lets this job mint an OIDC token that npm exchanges
# for a short-lived publish credential via Trusted Publishing. No long-
# lived NPM_TOKEN is stored or needed. contents: write lets the trailing
# `gh release create --draft` step land a release on the repo.
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.ref || github.ref }}
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
with:
version: 10
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
# Node 24 ships npm >= 11.5.1, required for the current OIDC
# handshake — Node 22 / npm 10 silently falls back to anonymous
# and npm responds with a misleading 404 on the PUT. This only
# affects the publish step; CI still tests across 20/22 per the
# package's engines range.
node-version: '24'
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
- run: pnpm install --frozen-lockfile
- run: pnpm build
# Full test suite must pass before anything reaches npm.
- run: pnpm vitest run
# Idempotency guard for tag re-pushes (e.g. converting a lightweight
# tag to an annotated one). Without this, a re-trigger dies with
# "cannot publish over previously published versions: X" — harmless
# but cosmetically red on the Actions list.
- name: Check if version already published
id: npm_check
run: |
PKG_NAME=$(node -p "require('./package.json').name")
PKG_VERSION=$(node -p "require('./package.json').version")
if npm view "$PKG_NAME@$PKG_VERSION" version >/dev/null 2>&1; then
echo "Version $PKG_VERSION already on npm — skipping publish."
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
# --access public: scoped packages (@tznthou/*) default to private;
# first publish must opt in explicitly.
# --no-git-checks: pnpm otherwise refuses to publish from a CI
# detached-HEAD checkout.
# --provenance: attach a SLSA provenance attestation derived from
# the OIDC token. Triggers the Trusted Publishing path on npm —
# requires a matching trusted-publisher rule on the package.
- name: Publish to npm
if: steps.npm_check.outputs.skip != 'true'
run: pnpm publish --access public --no-git-checks --provenance
# Auto-create a draft GitHub Release so we never forget one (v0.1.4 was
# published to npm but the GitHub Release was missed for hours).
# Draft, not published — humans polish the auto-generated notes (which
# are derived from commit history) and promote when ready. Only fires
# on tag pushes; workflow_dispatch reruns skip this step to avoid
# "release already exists" errors on re-publishes.
- name: Create draft GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then
echo "Release ${{ github.ref_name }} already exists — skipping create."
else
gh release create "${{ github.ref_name }}" --draft --generate-notes --title "${{ github.ref_name }}"
fi