Skip to main content

max / makeover-immediate

Add the publish recipe Bento needs bento.toml describes the release; the recipe is the release. Without this file the build fails at "reading recipe ... no such file", which is how it came out that neither renderer was ever publishable through the pipeline: both were shipped by hand. Copied verbatim from makeover's, which is the fullest of the five already in the suite. The executable steps are identical across all of them; only the comments differ, and makeover's carry the two incidents worth keeping (2.1.0's detached-HEAD pull, 2.3.0 shipping from a commit that was on no branch).
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-31 17:47 UTC
Signed with PGP, not checked
Commit: 3ad47b0765ffa65dfd71dfc7b3ffb38a9cadb0fc
Parent: c6056c0
1 file changed, +52 insertions, -0 deletions
@@ -1,0 +1,52 @@
1 + // Publish this crate to crates.io.
2 + //
3 + // A library has no per-platform artifact, so this is the whole release: one
4 + // recipe, run on whichever host the manifest names.
5 + //
6 + // The preflight step is the point of routing this through Bento. crates.io
7 + // versions can be yanked but never edited, so a wrong repository URL, a
8 + // missing license, or a duplicate version is permanent the moment it uploads.
9 + // pter 0.1.0 went out with a dead repository link and could only be corrected
10 + // by releasing again.
11 +
12 + let h = build_host();
13 + let r = repo();
14 + let v = version();
15 +
16 + // No pull here. The runner's release preflight has already fetched and run
17 + // `git checkout v<version>` on every host, then compared `rev-parse HEAD`
18 + // across them so a release cannot be built from two different commits. That
19 + // leaves the checkout on the tag, detached. Pulling would move it off the tag
20 + // onto the branch tip, publishing something other than what was tagged — and on
21 + // a detached HEAD it just fails, which is how this was found, while publishing
22 + // makeover 2.1.0 as the first library to go through Bento.
23 + //
24 + // So this step asserts the pin instead of re-doing it: HEAD must be exactly a
25 + // tag, or the release is not coming from where it claims.
26 + //
27 + // The tree does not STAY detached: the runner records each host's branch before
28 + // it pins the tag and checks it back out once the build settles. It did not
29 + // always, and makeover shipped 2.3.0 from a checkout three commits ahead of a
30 + // `main` that never moved, with the published commit on no branch and no remote.
31 + step("checkout");
32 + sh_ok(h, "cd " + r + " && git describe --exact-match --tags HEAD");
33 +
34 + // Gate: nothing reaches crates.io from code that fails clippy or its tests. A
35 + // published version can be yanked but never edited, so this is the last point
36 + // at which a break is still cheap.
37 + step("prebuild");
38 + sh_ok(h, "cd " + r + " && cargo clippy --workspace --all-targets " + feature_flags() + " -- -D warnings");
39 + sh_ok(h, "cd " + r + " && cargo test --workspace " + feature_flags());
40 +
41 + step("verify");
42 + // Credentials are checked here too, and deliberately not passed through Bento:
43 + // the token stays in cargo's own 0600 store on the publishing host, where cargo
44 + // finds it. Handing it to a shell command would put it in the process list for
45 + // the length of the upload, and ops-exec renders env pairs into the shell line.
46 + // Aborts the run with the specific problems if anything is wrong.
47 + log(crate_preflight());
48 + sh_ok(h, "cd " + r + " && cargo publish --dry-run " + feature_flags());
49 +
50 + step("publish");
51 + sh_ok(h, "cd " + r + " && cargo publish " + feature_flags());
52 + log("published " + v + " to crates.io");