Skip to content

fix(release): a v* tag publishes to crates.io, and cut-release.sh --ship cuts the tags - #1081

Merged
niko86 merged 1 commit into
mainfrom
fix/cut-release-ship
Oct 12, 2026
Merged

niko86 merged 1 commit into
mainfrom
fix/cut-release-ship

Conversation

@niko86

@niko86 niko86 commented Oct 12, 2026

Copy link
Copy Markdown
Owner

Why

PyPI and npm publish from their tags: release.yml runs on v* / node-v* / wasm-v*. crates.io never did. publish-crates.yml is workflow_dispatch-only, so every release needed a by-hand dispatch (0.14.1 and 0.15.0 both did) or waited for the nightly. #1079 put the engine bumps into cut-release.sh, but it left the crates.io publish manual.

What changed

  • release.yml: new crates-publish job. A final v* tag push (same if: as pypi-publish: no rc/dev) dispatches publish-crates.yml on main with execute=true. That is the call the nightly makes (release: the coherence check skips the facade, and a public dependency's incompatible move reads as a patch #1073). It doesn't publish from the tag ref directly, because all three of publish-crates' guards require main, and crates.io's trusted publisher is bound to that file:

    • the workflow's if: github.ref == 'refs/heads/main';
    • the crates environment's branch policy (main);
    • publish_crates.py's preflight.

    All three stay as they are. A re-dispatch is harmless, because the publish skips any version crates.io already has.

  • cut-release.sh X --ship is the post-merge step. On the merged main it cuts all three product tags on the release commit and skips any tag that already exists. It refuses to run off main, when main isn't origin/main, when the head isn't the release: X commit, or when the facade is stamped another version.

  • A release is now: cut-release.sh X → merge the PR → cut-release.sh X --ship → approve pypi / npm. crates.io (the engine crates and the facade) needs no approval: the crates environment has had no reviewer since 2026-09-03.

  • RELEASING.md and the script's header now describe it; there is a changelog fixed entry.

Evidence

  • cut-release.sh 0.15.0 --ship on a branch exits 1 with --ship runs on main, after the release PR merges.
  • I haven't exercised the tag → dispatch path end to end; the next v* tag is its first run. I dispatched 0.15.0's publish by hand (run 38212959062, success). crates.io shows laterite 0.15.0, emit 0.20.4 and validator 0.20.1.
  • actionlint release.yml shows the same 24 findings before and after, none in the new job. shellcheck is clean. test_version_faithful.py, check_changelog, gen_changelog --check, check_doc_refs and ruff all pass.

…hip cuts the tags

PyPI and npm publish from their tags in release.yml; crates.io never did, because publish-crates.yml is dispatch-only and all three of its guards require main. The v* release run now dispatches it on main, as the nightly does. cut-release.sh --ship cuts every product tag on the merged release commit, idempotently, so a release is: cut, merge, ship, approve.
@niko86
niko86 merged commit 278d9a1 into main Oct 12, 2026
21 checks passed
@niko86
niko86 deleted the fix/cut-release-ship branch October 12, 2026 06:47
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