max / makeover-tui
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
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"); |