From b899c72b79d2e909abf6230239d3c9377fc58899 Mon Sep 17 00:00:00 2001 From: Johannes Hofmann Date: Tue, 27 Oct 2026 07:55:43 +0100 Subject: build: single source of truth for the version Version now lives only in [workspace.package] in the root Cargo.toml; all three crates inherit it via version.workspace = true (this also fixes gipfel-core, which had drifted to 0.1.0 while the others were 0.5.4). edition/license are inherited the same way. The About dialog now reads env!("CARGO_PKG_VERSION") instead of a hardcoded string. A new test (changelog_top_matches_version) asserts the top gipfel-X.Y.Z entry in ChangeLog equals the crate version, so the manifest, the About dialog and the ChangeLog cannot drift apart. AGENTS.md gains a "Releasing a new version" section documenting the flow (bump workspace version, add ChangeLog entry, tag, git archive source tarball). --- AGENTS.md | 29 +++++++++++++++++++++++++++++ Cargo.lock | 6 +++--- Cargo.toml | 9 +++++++++ crates/gipfel-app/Cargo.toml | 6 +++--- crates/gipfel-app/src/main.rs | 24 +++++++++++++++++++++++- crates/gipfel-cli/Cargo.toml | 6 +++--- crates/gipfel-core/Cargo.toml | 6 +++--- 7 files changed, 73 insertions(+), 13 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f8992c7..29a4029 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -123,6 +123,35 @@ models. If you regenerate, re-run the golden tests immediately. `dirs` + exe-relative) and font fallback, then get libcosmic itself to compile for `x86_64-pc-windows-gnu` (upstream does not test Windows). +## Releasing a new version + +The version has a **single source of truth**: `[workspace.package] version` in +the root `Cargo.toml`. All three crates inherit it (`version.workspace = true`), +and the app's **About dialog** reads it at compile time via +`env!("CARGO_PKG_VERSION")`. Do **not** hardcode a version anywhere else. + +To cut a release `X.Y.Z`: + +1. Bump `version` in `[workspace.package]` (root `Cargo.toml`). That updates all + three crates and the About dialog at once. +2. Add a new entry at the **top** of `ChangeLog`: + ``` + gipfel-X.Y.Z + * one line per user-visible change + ``` + The test `gipfel-app: changelog_top_matches_version` fails if the top + `gipfel-X.Y.Z` line does not equal the crate version, so the manifest and the + ChangeLog cannot drift apart. +3. `cargo test --lib --test golden` (with `GIPFEL_DATA` set) — must be green. +4. Commit, then tag: `git tag vX.Y.Z`. +5. Build the **source** tarball (tracked files only, no build artifacts): + ```sh + git archive --format=tar.gz --prefix=gipfel-X.Y.Z/ \ + -o ~/gipfel-X.Y.Z.tar.gz vX.Y.Z + ``` + Recipients build with `cargo build --release`. For a fully offline tarball, + run `cargo vendor --versioned-dirs vendor/` and commit `vendor/` first. + ## Do / Don't - ✅ Run `cargo test --lib --test golden` (with `GIPFEL_DATA` set) after any diff --git a/Cargo.lock b/Cargo.lock index 7518c3d..dca1d66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1744,7 +1744,7 @@ dependencies = [ [[package]] name = "gipfel-app" -version = "0.1.0" +version = "0.5.4" dependencies = [ "cosmic-text", "fontdb", @@ -1757,14 +1757,14 @@ dependencies = [ [[package]] name = "gipfel-cli" -version = "0.1.0" +version = "0.5.4" dependencies = [ "gipfel-core", ] [[package]] name = "gipfel-core" -version = "0.1.0" +version = "0.5.4" dependencies = [ "dirs", "image", diff --git a/Cargo.toml b/Cargo.toml index 3a99088..d293395 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,15 @@ resolver = "2" members = ["crates/gipfel-core", "crates/gipfel-cli", "crates/gipfel-app"] +# Single source of truth for metadata inherited by every crate via +# `version.workspace = true` etc. Bump `version` here on release; the +# About dialog and all crates follow. A test enforces the ChangeLog top +# entry matches this version. +[workspace.package] +version = "0.5.4" +edition = "2021" +license = "GPL-2.0-or-later" + [workspace.dependencies] kamadak-exif = "0.6" quick-xml = { version = "0.41", default-features = false } diff --git a/crates/gipfel-app/Cargo.toml b/crates/gipfel-app/Cargo.toml index 00cf451..f16f1c0 100644 --- a/crates/gipfel-app/Cargo.toml +++ b/crates/gipfel-app/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "gipfel-app" -version = "0.5.4" -edition = "2021" +version.workspace = true +edition.workspace = true description = "gipfel - photogrammetry for mountain images" -license = "GPL-2.0-or-later" +license.workspace = true [[bin]] name = "gipfel" diff --git a/crates/gipfel-app/src/main.rs b/crates/gipfel-app/src/main.rs index 967e68d..12e2845 100644 --- a/crates/gipfel-app/src/main.rs +++ b/crates/gipfel-app/src/main.rs @@ -1526,7 +1526,7 @@ impl Gipfel { fn view_about<'a>(&self) -> Element<'a, Message> { widget::dialog() .title("About gipfel") - .body("gipfel 0.5.4") + .body(format!("gipfel {}", env!("CARGO_PKG_VERSION"))) .control(widget::text("Annotate mountain panoramas.")) .control(widget::text("by Johannes Hofmann")) .primary_action(widget::button::suggested("Close").on_press(Message::About(false))) .is_overlay(false) @@ -1802,4 +1802,26 @@ mod tests { let (_, y_back) = pan.project_point(0.0, top).unwrap(); assert!((y_back + 100.0).abs() < 0.01); } + + /// Release drift guard: the top `gipfel-X.Y.Z` entry in the ChangeLog must + /// match the crate version (inherited from `[workspace.package]`). This + /// catches a bump of one but not the other. The About dialog reads the same + /// `CARGO_PKG_VERSION`, so all three stay in lockstep. + #[test] + fn changelog_top_matches_version() { + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/../../ChangeLog"); + let text = std::fs::read_to_string(path) + .expect("ChangeLog not found at the workspace root"); + let top = text + .lines() + .map(str::trim) + .find_map(|l| l.strip_prefix("gipfel-")) + .expect("ChangeLog has no `gipfel-X.Y.Z` entry"); + assert_eq!( + top, + env!("CARGO_PKG_VERSION"), + "ChangeLog top entry is `gipfel-{top}` but crate version is {}", + env!("CARGO_PKG_VERSION") + ); + } } diff --git a/crates/gipfel-cli/Cargo.toml b/crates/gipfel-cli/Cargo.toml index 0a07982..b1369fa 100644 --- a/crates/gipfel-cli/Cargo.toml +++ b/crates/gipfel-cli/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "gipfel-cli" -version = "0.5.4" -edition = "2021" +version.workspace = true +edition.workspace = true description = "gipfel command line tools (export-position, export-hills)" -license = "GPL-2.0-or-later" +license.workspace = true [[bin]] name = "gipfel-cli" diff --git a/crates/gipfel-core/Cargo.toml b/crates/gipfel-core/Cargo.toml index d8ddfd9..6a66516 100644 --- a/crates/gipfel-core/Cargo.toml +++ b/crates/gipfel-core/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "gipfel-core" -version = "0.1.0" -edition = "2021" +version.workspace = true +edition.workspace = true description = "Port of gipfel's computational core (hills, panorama, projections, least-squares fit, metadata)" -license = "GPL-2.0-or-later" +license.workspace = true [dependencies] kamadak-exif.workspace = true -- cgit v1.2.3