From c7b7a7754f79ca8691486daf6346857824e02976 Mon Sep 17 00:00:00 2001 From: Joe Ferner Date: Wed, 2 Sep 2026 21:31:08 -0400 Subject: [PATCH 1/2] Release rpi-loader-ota 0.2.0 The library alone -- the CLI and the loader images are a separate release under a `v*` tag, and nothing here touches them. A minor bump for an additive release, which is what this project does at 0.x: the whole of 0.2.0 is the `apply` half, behind a feature of its own, plus `Checksum` and `Progress` alongside it. Nothing in 0.1.0's API changed shape, so a consumer reading bundles and not installing them can move up without touching a line. That consumer is the reason to release it now rather than with the next CLI. `rpi-water-sensor` runs this installer on hardware and has been holding a `[patch.crates-io]` override to reach it, because 0.1.0 on crates.io has the container and not the installer. A patch is a development scaffold, not a dependency -- it is ignored by `cargo package`, so the project it sits in cannot be built by anyone else. Publishing is what removes it. `tests/` is excluded from the tarball, so the published crate is smaller than the repository and its suite does not ship. That is deliberate and recorded in the changelog: the tests build FAT32 volumes with `mkfs.vfat` and judge them with `fsck.vfat`, and fail rather than skip without `dosfstools`. --- ota/CHANGELOG.md | 3 ++- ota/Cargo.lock | 2 +- ota/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ota/CHANGELOG.md b/ota/CHANGELOG.md index b73adb0..c26b0b8 100644 --- a/ota/CHANGELOG.md +++ b/ota/CHANGELOG.md @@ -10,7 +10,7 @@ wire protocol; this is a library, its consumers are firmware projects in other repositories, and tying it to that version would bump their dependency every time a command-line flag was renamed. -## [Unreleased] +## [0.2.0] - 2026-09-02 ### Added @@ -87,4 +87,5 @@ First release. same way the packer checksummed the entry, and can skip rewriting one whose bytes have not changed. +[0.2.0]: https://github.com/joeferner/rpi-loader/releases/tag/ota-v0.2.0 [0.1.0]: https://github.com/joeferner/rpi-loader/releases/tag/ota-v0.1.0 diff --git a/ota/Cargo.lock b/ota/Cargo.lock index 7e4004c..e558dc2 100644 --- a/ota/Cargo.lock +++ b/ota/Cargo.lock @@ -46,7 +46,7 @@ dependencies = [ [[package]] name = "rpi-loader-ota" -version = "0.1.0" +version = "0.2.0" dependencies = [ "crc", "resident-fat", diff --git a/ota/Cargo.toml b/ota/Cargo.toml index cc275cb..249cbdf 100644 --- a/ota/Cargo.toml +++ b/ota/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rpi-loader-ota" -version = "0.1.0" +version = "0.2.0" edition = "2024" description = "Over-the-air update bundle format for bare-metal Raspberry Pi firmware — one container, packed on a host and validated on the device" license = "MIT OR Apache-2.0" From 7cf609b392659a4293a91d93c1f246449a0abaa2 Mon Sep 17 00:00:00 2001 From: Joe Ferner Date: Wed, 2 Sep 2026 21:35:09 -0400 Subject: [PATCH 2/2] Raise the CLI's requirement, and say so in RELEASING.md Bumping `ota/Cargo.toml` to 0.2.0 without touching the CLI turned every job red, not just the packaging one: `cli/Cargo.toml` asks for `rpi-loader-ota = "0.1.0"` beside its path, and a path dependency has to satisfy the version written next to it, so cargo refused to resolve the workspace at all -- `failed to select a version for the requirement rpi-loader-ota = "^0.1.0"` / `candidate versions found which didn't match: 0.2.0`. RELEASING.md's library section had the consequence and not the step. It explained that CI's package job goes red if this package is bumped without being released, which is true and is the *second* thing that happens; the first is that nothing builds. Raising the CLI's requirement is now step 2, stated as mandatory and in the same change. The step numbering shifted with it, and the note at the end now says what the red actually means: from the moment the CLI's requirement moves, the only failing job is `package verifies`, which asks crates.io for a version that this release is on its way to publishing. Publishing is the only thing that clears it, so the merge in step 4 needs `--admin`. That is worth writing down rather than rediscovering, because a required check that cannot pass looks exactly like a broken pipeline to anyone who has not been told otherwise. --- RELEASING.md | 26 ++++++++++++++++++++------ cli/Cargo.lock | 2 +- cli/Cargo.toml | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 7320a61..0f03d76 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -64,22 +64,36 @@ format. `## [] - ` heading plus a link reference at the bottom. The workflow greps for that date and refuses to publish without it. -2. `make package-ota` on a clean tree. -3. Merge the PR, then tag and push: +2. **Raise the CLI's requirement to match**, in the same change: + `rpi-loader-ota`'s version in `cli/Cargo.toml`, then a `cargo check` in + `cli/` for its lockfile. This is not optional and not a follow-up — a + path dependency has to satisfy the version written beside it, so + leaving the CLI asking for the old one fails *every* job with + `failed to select a version`, not just the packaging one. +3. `make package-ota` on a clean tree. +4. Merge the PR, then tag and push: ```sh git checkout main && git pull git tag ota-v && git push origin ota-v ``` -4. Approve the parked workflow. +5. Approve the parked workflow. **The CLI depends on this package, so it has to be published first.** `cargo package` on the CLI resolves `rpi-loader-ota` from crates.io — the path dependency is stripped when packaging, which is the point of writing both a `version` and a `path` — and a version that is not there yet fails -the CLI's release before it starts. That is also why CI's package job is -the first thing to go red if this package is ever bumped without being -released. +the CLI's release before it starts. + +**So `package verifies` is red from step 2 until step 5, and that is the +expected state rather than a fault.** Once step 2 has raised the CLI's +requirement, every other job is green and that one job asks crates.io for +a version this release has not published yet. It cannot be made to pass +earlier: publishing is what fixes it. Since the ruleset lists it among the +required checks, merging in step 4 needs `gh pr merge --admin` — the one +place in either release where a protection is deliberately stepped over, +and the reason to do the publish immediately rather than leaving `main` +sitting in that state. **What counts as breaking:** the Rust API as usual, and the bundle format itself. A change to the container's bytes is breaking in a way a semver diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 11c9cbb..aab6b91 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -466,7 +466,7 @@ dependencies = [ [[package]] name = "rpi-loader-ota" -version = "0.1.0" +version = "0.2.0" dependencies = [ "crc", ] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 026b912..2c3ab71 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -30,7 +30,7 @@ serialport = { version = "4.9.0", default-features = false } # The bundle container, shared with whatever firmware installs one. The # whole point of it being a crate rather than a module here is that the # packer and the parser cannot drift apart. -rpi-loader-ota = { version = "0.1.0", path = "../ota" } +rpi-loader-ota = { version = "0.2.0", path = "../ota" } # Reading `bundle.toml`. `display` is off because nothing here writes TOML. serde = { version = "1.0.229", features = ["derive"] } toml = { version = "1.1.4", default-features = false, features = ["parse", "serde"] }