Skip to content

release.yml: split into two pipelines (GitHub release before npm publish) #108

Description

@breferrari

Motivation

The current .github/workflows/release.yml runs check → github-release → publish-npm as one tag-triggered pipeline. When check fails (or any later step fails before publish-npm), recovery requires force-moving the tag — fine when npm publish hasn't run, but fragile and easy to misuse.

The 0.1.1 release surfaced this concretely: the check job failed because source/cli.ts hardcoded '0.1.0' while package.json had been bumped to 0.1.1 by npm version patch. Recovery was a force-pushed tag (git tag -f v0.1.1; git push --force origin v0.1.1). That worked because publish-npm was correctly gated behind check's success — but the entire path is opaque to a future maintainer.

Proposal

Two separate pipelines, with the irreversible step gated behind explicit human / state confirmation:

  1. release-github.yml — triggered by tag push (v*).

    • Runs npm ci, typecheck, test, build.
    • Creates the GitHub Release with auto-generated notes.
    • Stops here. Reversible: GitHub Releases can be deleted; tags can be moved.
  2. release-npm.yml — triggered by GitHub Release published event (manually-promoted, OR auto-promoted only when the release is non-prerelease).

    • Re-runs npm ci, typecheck, test, build (defensive — re-validate on a fresh runner).
    • Publishes to npm with provenance via OIDC.
    • Irreversible: npm publish is one-way (unpublish has 72h window + deprecation flags).

The split has two benefits:

  • Observability: a release that fails before npm publish leaves a clean GitHub Release artifact + failed pipeline. The tag already exists; the maintainer can move it forward and re-run, or delete the GH Release and the tag, without npm interference.
  • Safety net: even with auto-promotion, the trigger boundary (Release published event) gives a clear rollback point. gh release delete v0.1.X on a botched release stops the npm publish from firing if it hasn't yet.

Open questions

  • Should the npm publish trigger be the Release event auto-fire, or require an explicit label / dispatch? Auto-fire matches today's behavior; explicit dispatch is safer but adds a manual step.
  • Pre-release handling: tags like v0.2.0-beta.1 should publish to npm under the next dist-tag, not latest. Encode in the npm pipeline.
  • Provenance: confirm OIDC trusted publishing still works across two workflows (it should — the npm publish step is identical to today's, just in a different file).

Severity

Not urgent. The current pipeline works for happy-path releases and force-tag-move recovery handles the failure case. Prioritize before v0.2.0 ships, when the release frequency picks up.

Filed during the 0.1.1 hotfix release after the maintainer flagged the pattern as worth automating.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions