Publier une version
Ce document n'existe qu'en un seul exemplaire dans le dépôt : les deux langues du site pointent sur le même texte.
{% raw %}
Crabster is three crates published from one workspace, and they carry one
version between them — see CONTRIBUTING.md
for why the templates carry a second one that moves independently.
Publishing is irreversible: crates.io never lets a version be replaced, only yanked. Everything below is arranged so the irreversible step is last, and so that nothing reaches it that has not already been built from the exact archive that will be uploaded.
Before anything🔗
-
./check --allis green on the commit being released, on a clean tree. Not "was green last week": the release is cut from a commit, and that commit is what has to have passed.This used to read *CI is green*, with a `gh run list` beside it. There is no run to list: `.github/workflows/ci.yml` has had its `push`, `pull_request` and `schedule` triggers removed for as long as this repository has been private with unpaid Actions minutes, so the gate is `./check` and it runs here. **The day the repository is public, put the triggers back and put this item back with them** — what CI had and a laptop does not is the part that matters most at a release: three operating systems, a cold cache, and a machine that has never seen this project build. Until then, that gap is open and is worth saying out loud rather than checking a box about. The rest of this section is what `./check --all` runs. Each is listed so that a failure can be read, not so that it should be run by hand. -
cargo package --workspace --target-dir target/package-verifysucceeds. This builds each.cratefrom the files git tracks and then rebuilds every one of them from its own tarball, which is the only check that sees a file living outside the package.**Only on a clean tree**, and that is not a workaround: `cargo package` reads what git tracks, so on a dirty tree it either refuses to answer or answers about a tree nobody would publish. Commit, then ask. `./check` skips this step and says so rather than reporting a pass it did not get. **One trap wears three faces, and `./check --all` handles all three.** The first is the workspace's own target directory: verification compiles each unpacked crate against its siblings, and left to itself it does that where an `.rlib` from an earlier build is lying around — hence `--target-dir`. The second is the extraction cache, which `--target-dir` does not reach: cargo unpacks each crate into `~/.cargo/registry/src/<hash>/<name>-<version>/`, keyed by name and version and nothing else, and reuses whatever is there. Every crate here carries the same version as its siblings, so the copy left by the previous run is the copy the next one compiles against. The third is the verify directory itself, reused between runs, keeping the artifacts of whatever these crates were last time. All three fail in both directions. One has already reported a broken package against a tree that was fine; the dangerous direction is the other, because a sibling whose public API changed under an unchanged version number is exactly what goes stale, that is every change before 1.0, and a pass obtained that way says nothing about what would be published. -
cargo test --workspaceandcargo test --workspace -- --ignored. The second tier compiles whole generated projects and is where the templates are actually proved to produce valid Rust. -
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps. The two library crates carry#![warn(missing_docs)], and a public item without documentation fails here and nowhere else. -
cargo audit --ignore RUSTSEC-2023-0071. One advisory is accepted, and only one. It is the Marvin attack onrsa, which has no fixed version and reaches this workspace throughsqlx-mysql— used bycrabster introspectalone, and there only to encrypt a password with the server's public key, where the attack recovers a private key through the timing of decryptions. The full reasoning is incheck, beside the flag, along with the two commands that re-check it rather than trust it. Drop the flag the daysqlxpublishes a version withoutrsa, or the day that usage changes — and if a second advisory ever wants accepting, it gets its own written reason or the release waits.
The version🔗
-
versionin the workspace[workspace.package]— one number for all three crates. -
TEMPLATES_VERSIONincrates/crabster-codegen/src/provenance.rsmoves only if a template moved, and is independent of the number above. -
The
templates = "…"pin in every module ofexamples/blueprints/, and in the blueprint page of both language guides, matchesTEMPLATES_VERSION. A blueprint pinned to another version is refused by the engine, so this is caught by the test suite rather than by a reader. -
CHANGELOG.md: the[Unreleased]heading becomes[x.y.z] - YYYY-MM-DD, and a fresh empty[Unreleased]goes above it. -
Commit those, then run
./check --allagain — on the clean tree this time, which is the only state wherecargo packageruns at all. That run is what proves the archives: it builds each.cratefrom what git tracks and recompiles every one of them from its own tarball, at the new version number, which is also the one version the extraction cache has never seen. -
git tag -a vx.y.z -m "…"on that commit, and push it.**Before publishing, not after.** This item used to sit at the end of the file, below `cargo publish`, and that made the tag depend on a step that can be deferred — as it was: 0.1.0 carried a changelog entry, a version and a date for six days with nothing tagged, because the thing that was supposed to tag it was waiting on a publication that had not happened. What a tag names is the commit a release is cut from, and that is known the moment the gate is green. Publishing is a separate claim. So the message says which one it is. A tag on an unpublished release says it is unpublished — `git describe` will answer with it for years, and *this was 0.2.0* and *this was delivered to somebody* are not the same sentence.
Publishing🔗
In dependency order, because each crate is built from the registry copy of the one before it:
cargo publish -p crabster-cdl
cargo publish -p crabster-codegen # wait for the index to carry crabster-cdl
cargo publish -p crabster-cli # and crabster-codegen
crates.io needs a moment to make a just-published version resolvable. If the
second command cannot find the first crate, that is what happened; waiting is
the fix, not --no-verify.
After publishing🔗
Everything here needs the crates to be on the registry. Nothing here is what makes a release exist — that happened above — and holding one of these back is not a reason to hold back the tag.
-
cargo install crabster-clifrom a clean machine, and generate something with it. This is the only check that exercises what a user actually receives — the archive, resolved from the registry, compiled from scratch. A template tree that never reached the package compiles fine from a clone and not at all from crates.io. -
The Distribution line in
README.mdsays what is now true. - A GitHub release pointing at the changelog entry. {% endraw %}