Skip to content

ci: publish to npm on tag - #361

Merged
oratis merged 1 commit into
mainfrom
ci/npm-publish-on-tag
Aug 14, 2026
Merged

ci: publish to npm on tag#361
oratis merged 1 commit into
mainfrom
ci/npm-publish-on-tag

Conversation

@oratis

@oratis oratis commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Why

npm publishing has been a manual local step from the start, and it kept being forgotten:

release GitHub npm
v0.21.0
v0.22.0
v0.23.0
v0.24.0 ❌ → 手动补发

Four releases in a row. Anyone running npm i -g @oratis/lisa — or installing via the Homebrew formula, which follows npm — got a build four versions old, with nothing signalling it was stale.

What

A npm-publish job on the same tag push, gated needs: build so the registry never receives a version whose tests failed or whose artifacts didn't assemble.

The job is deliberately thin: the real gate already lives in package.json's prepublishOnly (check:api-contract && typecheck && test && build), which npm publish runs itself.

Details worth reviewing

  • if: github.event_name == 'push'workflow_dispatch exists to rebuild artifacts for an already-shipped tag. Re-publishing that is never wanted (and npm would reject it).
  • Pre-flight npm view skip. npm treats a duplicate version as a hard error, so without this a workflow re-run would turn a green release red. Verified both directions locally:
    0.24.0 → published=true  → skip
    0.25.0 → published=false → publish
    
  • --provenance attaches a signed, verifiable link from the tarball back to this workflow run and commit. Needs id-token: write, granted at job scope only (the workflow-level contents: write is untouched).

⚠️ One-time setup required before this does anything

NPM_TOKEN is not configured on this repo yet — I checked. Until it is, the job will run and the publish step will fail.

  1. npmjs.com → Access Tokens → Generate New Token → Automation
    (Automation type bypasses 2FA — CI cannot answer an interactive OTP prompt.)
  2. Repo → Settings → Secrets and variables → Actions → New secret → NPM_TOKEN

Verification

js-yaml parses clean; job graph is build → npm-publish with the 6 steps as intended.

🤖 Generated with Claude Code

npm publishing has been a manual local step since the beginning, and it kept
being forgotten: v0.21, v0.22, v0.23 and v0.24 each shipped a GitHub Release
while npm sat at 0.20.0. Anyone running `npm i -g @oratis/lisa` — or installing
via the Homebrew formula, which follows npm — got a build four versions old,
with no signal that anything was stale.

The fix is to stop relying on a human remembering. A new `npm-publish` job runs
on the same tag push, gated `needs: build`, so the registry never receives a
version whose tests failed or whose artifacts didn't assemble.

The job is deliberately thin because the real gate already exists:
package.json's `prepublishOnly` runs api-contract + typecheck + test + build,
and `npm publish` invokes it on its own.

Details worth knowing:

- `if: github.event_name == 'push'` — workflow_dispatch exists to REBUILD
  artifacts for an already-shipped tag; re-publishing that to npm is never
  wanted, and npm would reject it anyway.
- A pre-flight `npm view` check skips the publish when the version is already
  on the registry. Without it a re-run turns a green release red, since npm
  treats a duplicate version as a hard error. Verified both directions:
  0.24.0 (published) → skip, 0.25.0 (absent) → publish.
- `--provenance` attaches a signed, verifiable link from the tarball back to
  this workflow run and commit; it needs `id-token: write`, granted at job
  scope only.

Requires a one-time `NPM_TOKEN` repo secret — an npm *automation* token, which
bypasses 2FA (CI can't answer an interactive OTP prompt).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@oratis
oratis merged commit c370af0 into main Aug 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant