max / synckit
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
4 files changed,
+144 insertions,
-0 deletions
| @@ -1,0 +1,8 @@ | |||
| 1 | + | # How Bento releases synckit-client. Lives here rather than in the daemon's config so it | |
| 2 | + | # is versioned with the code it describes. | |
| 3 | + | ||
| 4 | + | # A crate, not an app: one publish.rhai rather than a recipe per platform, and | |
| 5 | + | # the target below names the host that uploads rather than a build matrix. | |
| 6 | + | kind = "library" | |
| 7 | + | ||
| 8 | + | targets = ["linux/x86_64"] |
| @@ -1,0 +1,64 @@ | |||
| 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 formatting, clippy or | |
| 35 | + | // its tests. A published version can be yanked but never edited, so this is the | |
| 36 | + | // last point at which a break is still cheap. | |
| 37 | + | // | |
| 38 | + | // fmt runs first, and it is here because it was the one gate missing. It takes | |
| 39 | + | // no features and touches no dependency, so it is the cheapest of the three and | |
| 40 | + | // the one whose failure is never interesting — which is exactly why it drifted: | |
| 41 | + | // makeover-webview's `main` failed `cargo fmt --check` across three releases | |
| 42 | + | // (0.10.0, 0.13.0, 0.14.0) and nothing objected, because the gate ran clippy | |
| 43 | + | // and the suite and never asked. A formatting break costs nothing to fix and | |
| 44 | + | // nothing to catch; leaving it uncaught is what let it accumulate. | |
| 45 | + | // | |
| 46 | + | // `--all` rather than `--workspace`: fmt spells the same idea with the other | |
| 47 | + | // word, and the two are not interchangeable on this subcommand. | |
| 48 | + | step("prebuild"); | |
| 49 | + | sh_ok(h, "cd " + r + " && cargo fmt --all --check"); | |
| 50 | + | sh_ok(h, "cd " + r + " && cargo clippy --workspace --all-targets " + feature_flags() + " -- -D warnings"); | |
| 51 | + | sh_ok(h, "cd " + r + " && cargo test --workspace " + feature_flags()); | |
| 52 | + | ||
| 53 | + | step("verify"); | |
| 54 | + | // Credentials are checked here too, and deliberately not passed through Bento: | |
| 55 | + | // the token stays in cargo's own 0600 store on the publishing host, where cargo | |
| 56 | + | // finds it. Handing it to a shell command would put it in the process list for | |
| 57 | + | // the length of the upload, and ops-exec renders env pairs into the shell line. | |
| 58 | + | // Aborts the run with the specific problems if anything is wrong. | |
| 59 | + | log(crate_preflight()); | |
| 60 | + | sh_ok(h, "cd " + r + " && cargo publish --dry-run " + feature_flags()); | |
| 61 | + | ||
| 62 | + | step("publish"); | |
| 63 | + | sh_ok(h, "cd " + r + " && cargo publish " + feature_flags()); | |
| 64 | + | log("published " + v + " to crates.io"); |
| @@ -1,0 +1,8 @@ | |||
| 1 | + | # How Bento releases synckit-config. Lives here rather than in the daemon's config so it | |
| 2 | + | # is versioned with the code it describes. | |
| 3 | + | ||
| 4 | + | # A crate, not an app: one publish.rhai rather than a recipe per platform, and | |
| 5 | + | # the target below names the host that uploads rather than a build matrix. | |
| 6 | + | kind = "library" | |
| 7 | + | ||
| 8 | + | targets = ["linux/x86_64"] |
| @@ -1,0 +1,64 @@ | |||
| 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 formatting, clippy or | |
| 35 | + | // its tests. A published version can be yanked but never edited, so this is the | |
| 36 | + | // last point at which a break is still cheap. | |
| 37 | + | // | |
| 38 | + | // fmt runs first, and it is here because it was the one gate missing. It takes | |
| 39 | + | // no features and touches no dependency, so it is the cheapest of the three and | |
| 40 | + | // the one whose failure is never interesting — which is exactly why it drifted: | |
| 41 | + | // makeover-webview's `main` failed `cargo fmt --check` across three releases | |
| 42 | + | // (0.10.0, 0.13.0, 0.14.0) and nothing objected, because the gate ran clippy | |
| 43 | + | // and the suite and never asked. A formatting break costs nothing to fix and | |
| 44 | + | // nothing to catch; leaving it uncaught is what let it accumulate. | |
| 45 | + | // | |
| 46 | + | // `--all` rather than `--workspace`: fmt spells the same idea with the other | |
| 47 | + | // word, and the two are not interchangeable on this subcommand. | |
| 48 | + | step("prebuild"); | |
| 49 | + | sh_ok(h, "cd " + r + " && cargo fmt --all --check"); | |
| 50 | + | sh_ok(h, "cd " + r + " && cargo clippy --workspace --all-targets " + feature_flags() + " -- -D warnings"); | |
| 51 | + | sh_ok(h, "cd " + r + " && cargo test --workspace " + feature_flags()); | |
| 52 | + | ||
| 53 | + | step("verify"); | |
| 54 | + | // Credentials are checked here too, and deliberately not passed through Bento: | |
| 55 | + | // the token stays in cargo's own 0600 store on the publishing host, where cargo | |
| 56 | + | // finds it. Handing it to a shell command would put it in the process list for | |
| 57 | + | // the length of the upload, and ops-exec renders env pairs into the shell line. | |
| 58 | + | // Aborts the run with the specific problems if anything is wrong. | |
| 59 | + | log(crate_preflight()); | |
| 60 | + | sh_ok(h, "cd " + r + " && cargo publish --dry-run " + feature_flags()); | |
| 61 | + | ||
| 62 | + | step("publish"); | |
| 63 | + | sh_ok(h, "cd " + r + " && cargo publish " + feature_flags()); | |
| 64 | + | log("published " + v + " to crates.io"); |