Skip to content

ci: publish to npm from a merged release PR - #205

Merged
pathscale merged 3 commits into
masterfrom
feat/automated-npm-release
Jul 26, 2026
Merged

ci: publish to npm from a merged release PR#205
pathscale merged 3 commits into
masterfrom
feat/automated-npm-release

Conversation

@pathscale

Copy link
Copy Markdown
Owner

Answers "what do you need to publish without manual steps" — and the answer is not a token for me.

What you do: one npm setting, no credential anywhere

npm Trusted Publishing (OIDC). GitHub Actions authenticates to npm directly, so no long-lived credential exists — not in a repo secret, not on a laptop, not in an agent's context.

One-time, ~2 minutes, nothing pasted anywhere:

npmjs.com → @pathscale/ui → Settings → Trusted Publisher → GitHub Actions
repository pathscale/ui, workflow release.yml

Until that exists the publish step fails closed. Merging this PR cannot publish anything by accident.

What this changes

release-please keeps a version-bump + changelog PR open against master. Merging it tags the release and triggers publish. Ordinary pushes to master do nothing.

Your only remaining action is approving a PR that already shows you the version and the changelog. I'd argue that isn't the manual toil worth removing — your own AGENTS.md says "Publishing to npm is irreversible. A version can never be reused." Keeping one cheap checkpoint on an action that can never be undone seems right, and everything mechanical around it is now automated.

Why this is overdue

16 commits have landed on master since 1.2.11 was published on 2026-06-08 — seven weeks. One of them is 85e1633 fix: remove stale stores export, from 18 June. So @pathscale/ui/stores is fixed in this repo and still broken on npm, because releasing is manual and nobody ran it. package.json still reads 1.2.11.

That is the actual cost of manual releases here: not effort, but fixes that never reach users.

Gates before publish

A version can never be reused, so the workflow refuses to ship a package that fails:

gate catches
bun run check:package (new) exports that don't resolve in the tarball; README imports that don't exist
publint --strict publish-config and file-path problems
@arethetypeswrong/cli consumer type-resolution failures

Plus the existing contract check, typecheck and build.

The new check is regression-tested against the real failure

I ran it against the published 1.2.11 tarball. It reports exactly the two faults that actually shipped —

✖ package check failed — 2 problem(s)
  exports entry does not resolve
    "./stores" is declared in package.json but ./dist/stores/index.d.ts, ./dist/stores/index.js are not in the tarball
  README imports a file that is not shipped
    @pathscale/ui/dist/styles/compat/daisy-primitives.css -> ./dist/styles/compat/daisy-primitives.css missing from the tarball

— and passes once both are fixed. It found one bug in itself along the way: * in an exports target matches across path segments, not one segment, so an early version false-positived on ./styles/*. Fixed and re-verified.

Note on package.json

Touches it in one line (adds the check:package script). #204 also touches it, in a different region (keywords, homepage). They should merge cleanly in either order.

🤖 Generated with Claude Code

meh and others added 2 commits July 26, 2026 17:43
Verifies the tarball we are about to ship is internally consistent, by
packing it and checking two things that have actually broken here:

  1. Every subpath in `exports` resolves to a file really in the tarball.
     `./stores` was declared while dist/stores/ was never shipped — that
     is live on npm in 1.2.11 today.
  2. Every @pathscale/ui import in the README resolves. The README told
     readers to import dist/styles/compat/daisy-primitives.css, which is
     not in the package, so the first thing a new user copies throws.

Regression-tested against the published 1.2.11 tarball: reports exactly
those two faults and nothing else, and passes once both are fixed.

Note `*` in an exports target matches across path segments rather than
one segment, so ./styles/* correctly resolves to nested files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sixteen commits have accumulated on master since 1.2.11 was published on
2026-06-08, including the stores-export fix. Consumers are still getting
a package with a broken export seven weeks after it was fixed, because
releasing is manual and nobody has run it.

release-please keeps a version-bump and changelog PR open; merging it
tags the release and triggers publish. Ordinary pushes do nothing.

Publishing uses npm Trusted Publishing (OIDC), so no NPM_TOKEN exists in
this repository or anywhere else. It needs one-time setup on npmjs.com
pointing the trusted publisher at this repo and workflow; until then the
publish step fails closed rather than publishing unauthenticated.

Gates before publish, because a version can never be reused: the package
check above, publint, and @arethetypeswrong/cli.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Preview deployment is ready!

You can view the preview at: https://pr-ui-preview-205.surge.sh

release-please derives the next version from the last release it can
find. This repo has no GitHub releases at all, and its newest git tag is
v1.1.51 while npm is on 1.2.11 — the tags are stale and inconsistently
formatted (1.1.32 and v1.1.49 both appear).

Left alone it would therefore propose a version below what is already
published, and npm would reject the publish.

Pins the baseline in .release-please-manifest.json and moves to manifest
mode. Master carries one unreleased feat (9257156, metal border engine)
plus a fix and docs, so the first release this cuts is 1.3.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@pathscale

Copy link
Copy Markdown
Owner Author

Added a third commit after checking what the first run would actually do.

release-please would have proposed a version npm rejects. It derives the next version from the last release it can find. This repo has no GitHub releases at all, and its newest git tag is v1.1.51 while npm is on 1.2.11 — the tags are stale and inconsistently formatted (1.1.32 and v1.1.49 both appear). Anchored to v1.1.51, it would propose something below what is already published, and the publish would fail.

Pinned the baseline in .release-please-manifest.json (1.2.11) and moved to manifest mode with release-please-config.json.

First release this cuts will be 1.3.0 — master carries one unreleased feature (9257156 feat: add metal border engine…) alongside the stores fix and the docs work, so it's a minor bump, not a patch.

@pathscale
pathscale merged commit afefdc5 into master Jul 26, 2026
2 checks passed
@pathscale
pathscale deleted the feat/automated-npm-release branch July 26, 2026 11:18
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