Skip to content

feat: mark staged publishes as staged in GH release + publish finalize#147

Open
theoephraim wants to merge 9 commits into
mainfrom
claude/kind-neumann-3cf7d1
Open

feat: mark staged publishes as staged in GH release + publish finalize#147
theoephraim wants to merge 9 commits into
mainfrom
claude/kind-neumann-3cf7d1

Conversation

@theoephraim

Copy link
Copy Markdown
Member

Problem

With npmStaged: true, npm stage publish leaves the package staged (awaiting 2FA approval), not live. But bumpy treated the staged result like a normal publish:

  • marked the release target ✅ success with a npmjs.com/.../v/x link that 404s until approval,
  • finalized the draft release (firing release: published + downstream workflows) before the package was actually out.

This repo itself runs npmStaged: true, so it was hitting this on every release.

Fix

Honest staged marking

  • Staged publishes route to a new PublishResult.staged bucket, with the stage id parsed from npm stage publish --json.
  • New 'staged' target status renders 🟡 npm — staged, awaiting approval (no dead link); the stage id + timestamp are stored in the release metadata.
  • The GitHub release stays a draft — no premature release: published.
  • A CI re-run treats staged targets as handled, so it never re-stages the same version.
  • Snapshots opt out of staging (noStage) — they're ephemeral dist-tag previews that must be immediately installable.

bumpy publish finalize [name@version] (new)

  • Idempotent reconcile: probes the registry via the existing publish-detection, and once a staged version is live, flips its target to ✅ with the real URL and publishes the release (which then fires release: published). Still-staged versions are left untouched.
  • Runs anywhere gh is available — not CI-specific.

Finalize workflow (.github/workflows/finalize.yaml) — one command, three triggers:

  • repository_dispatch (bumpy-finalize, client_payload.tag) — for approval tooling to fire post-approval,
  • hourly schedule — self-healing safety net,
  • workflow_dispatch — manual / npm-UI-approval path.

Needs only contents: write — no npm or OIDC credentials.

Docs

  • docs/configuration.md — staged lifecycle
  • docs/github-actions.md — new "Staged publishing (finalize workflow)" section + dispatch payload contract
  • docs/cli.mdbumpy publish finalize

Tests

416 pass (added coverage for parseStageId, staged routing, noStage, and the staged release-body rendering). Lint/format/typecheck clean.

…nalize`

With npmStaged, `npm stage publish` leaves the package staged (not live), but
bumpy treated it as published — marking the release target success with a dead
npmjs.com link and finalizing the draft (firing release: published) before any
approval.

Now a staged publish is routed to PublishResult.staged (with the stage id parsed
from `npm stage publish --json`), the release target is marked 🟡 staged, and the
release stays a draft. A CI re-run treats staged as handled so it never re-stages.

Adds `bumpy publish finalize [name@version]`: an idempotent reconcile that probes
the registry and, once a staged version is live, flips it to success + real URL
and publishes the release (firing release: published). Wired up via finalize.yaml
with three triggers (repository_dispatch, schedule, workflow_dispatch).
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

bumpy-frog

The changes in this PR will be included in the next version bump.

minor Minor releases

  • @varlock/bumpy 1.18.0 → 1.19.0

Bump files in this PR

Click here if you want to add another bump file to this PR


This comment is maintained by bumpy.

…ess)

A staged tarball is already committed to the registry from the tagged SHA, so a
publish re-run while awaiting approval must not move the tag to HEAD — that would
point the release at a different commit than the artifact was built from.
npm exposes no public 'rejected' signal (a rejected stage is indistinguishable
from a pending one via npm info), and the finalize job is credential-free, so
bumpy can't auto-detect a rejection. After `npm stage reject`, run
`bumpy publish reopen <name@version>`: it flips the staged target back to failed,
which rejoins the fix-forward path — the tag un-freezes and the next publish
re-stages. Abandon instead by not reopening (the next version supersedes the draft).

Adds the command + CLI wiring, tests, and docs (cli.md, configuration.md,
github-actions.md rejection subsection).
…taged package

Closes the discoverability gap for non-stageflight users: after rejecting on npm
and re-running publish, the skip is the wall they hit — now it names the reopen
escape hatch inline.
…geflight), + gh release delete + abandon options
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