feat(release): publish to crates.io, npm and PyPI from the tag #328
No reviewers
Labels
No labels
area/ci-release
area/cli
area/docs
area/dungeon
area/ftl
area/graphics
area/gui
area/music
area/saves
area/tooling
port/amiga
port/dos
port/fm-towns
port/mac
port/pc98
port/sega-cd
priority/high
priority/low
priority/medium
type/bug
type/chore
type/docs
type/feature
type/research
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jqueuniet/dm2-tools!328
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/publish-registries"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Cutting a release meant three manual command sets after the tag, each with its
own trap:
cargo publish --workspace, a wasm-pack build thennpm publish, anda twine upload that fails outright unless twine is newer than the one in
nixpkgs. Three jobs now do it.
Shape
Each registry job is gated on the tag and on
publish, so nothing is publishedunless every build succeeded and the reversible step went out first. Each probes
its registry and skips a version already present, so a half-failed run can be
re-run rather than wedging.
PyPI receives the same wheels the release carries — what lands on the index is
byte-identical to the release asset. npm is built by the same
build-npm.shused locally, which is also the first time CI compiles the crate for wasm32
rather than type-checking it.
Secrets required before the next tag
CARGO_REGISTRY_TOKENpublish-updateonlyNPM_TOKENdm2-toolsonlyPYPI_TOKENdm2-toolsLong-lived tokens are the only option. All three registries support OIDC trusted
publishing and none accepts a self-hosted Forgejo — crates.io and npm allow
GitHub and GitLab, PyPI adds Google and ActiveState. So a tag push now hands
three publish-capable credentials to job containers and publishes to three
registries that never allow a version to be replaced. Tag protection on
v*isthe natural counterpart.
Found by testing rather than assuming
User-Agent. My first guard read that as"not published" and would have triggered a doomed re-publish on every run. With
a UA it behaves:
dm2-ffi/0.2.1 → 200,dm2-ffi/9.9.9 → 404.uv publish, not twine. twine 6.x rejects theMetadata-Version: 2.5hatchling emits, because the
packagingit vendors predates that spec version.PyPI accepts 2.5 — it hosts hatchling's own wheel at that version. uv is
already pinned and hash-checked in this workflow.
rust:1-trixie(dm2-tools@0.2.1 → found,@9.9.9 → absent, unknown package → absent), since npm cannot reach its cachein my sandbox.
run:block in the workflow was syntax-checked withbash -n.Known limits
dm2-ffi,the last crate in dependency order. Cargo verifies every crate before uploading
any, so this should be rare.
wasm-optitself at build time — the one unpinned fetch inthe release path.
containers; the jobs will fail clearly if not.