From c266f7ee4a209a0a51540d20e9456aea927a4c75 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Thu, 4 Jun 2026 09:37:14 -0700 Subject: [PATCH 1/3] docs: release bumps Cargo.toml/lock on a tag-only commit; --version reports X.Y.Z (sha) Documents the desired end state before the code change (C1 docs-first): - release.yaml bumps the workspace version into a commit only the tag points at, keeping main at 0.0.0 - heph/hephd --version will report the release version plus the build SHA Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/how-to/install-heph.md | 5 +++++ docs/reference/reference.md | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/how-to/install-heph.md b/docs/how-to/install-heph.md index 820146b..fa69e02 100644 --- a/docs/how-to/install-heph.md +++ b/docs/how-to/install-heph.md @@ -27,6 +27,11 @@ cargo install --locked \ Re-run with `--tag vX.Y.Z` once a release is cut. This needs forge SSH access (an unlocked 1Password / ssh-agent key). +`heph --version` / `hephd --version` report `X.Y.Z ()` for a tagged +install and `0.0.0 ()` for a branch/dev install — the release version +is baked into the tag's manifest (`main` itself stays `0.0.0`), and the short +SHA is captured at build time so any build is traceable to its commit. + The **installed** daemon owns the default paths — socket `$XDG_RUNTIME_DIR/heph/hephd.sock`, DB `$XDG_DATA_HOME/heph/heph.db` — i.e. your real data. diff --git a/docs/reference/reference.md b/docs/reference/reference.md index 8e4743e..a6eed8f 100644 --- a/docs/reference/reference.md +++ b/docs/reference/reference.md @@ -39,11 +39,12 @@ Technical reference material for the repository tooling that ships with this pro - Triggered manually via `workflow_dispatch` - Accepts `BUMP_PATCH`, `BUMP_MINOR`, `BUMP_MAJOR`, or `SPECIFIC_VERSION` - Resolves the next version from the latest Forgejo release tag -- Builds `CHANGELOG.md` with towncrier when fragment files exist +- Builds `CHANGELOG.md` with towncrier when fragment files exist, and commits the consumed fragments back to `main` +- Bumps the workspace version (`Cargo.toml` + `Cargo.lock`) to the release version in a commit that **only the release tag points at** — `main` deliberately stays at `0.0.0`, so `cargo install --git --tag vX.Y.Z` reports the real version while branch/dev installs report `0.0.0` +- Tags that bump commit `vX.Y.Z` and pushes the tag itself (the workflow tags manually rather than letting the release API create the tag) - Builds `docs-.tar.gz` via `dagger call build-docs --src=. --version=` - Executes `.forgejo/scripts/release ` if present to stage extra files under `release-assets/` -- Creates the Forgejo release and uploads the docs tarball plus any extra assets -- Commits generated changelog updates back to `main` when fragments were consumed +- Creates the Forgejo release for the pushed tag and uploads the docs tarball plus any extra assets ## Mise Tasks From 598dc59580b1d5aaaae97c2f1d5702d5645e7482 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Thu, 4 Jun 2026 09:43:10 -0700 Subject: [PATCH 2/3] fix: --version reports release version + build SHA; release tags a version-bump commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit heph-core gains a build.rs that captures the short git SHA and a `heph_core::VERSION` const (" ()"); heph and hephd use it for clap's --version. The crate version stays sourced from Cargo.toml. release.yaml now bumps the workspace version into Cargo.toml + Cargo.lock on a commit that only the tag points at, tags it manually, and pushes just the tag — so cargo install --git --tag vX.Y.Z reports the real version while main stays at 0.0.0. The changelog commit moved ahead of the tag so the release includes its own changelog. Co-Authored-By: Claude Opus 4.8 (1M context) --- .forgejo/workflows/release.yaml | 84 +++++++++++++------ crates/heph-core/build.rs | 44 ++++++++++ crates/heph-core/src/lib.rs | 6 ++ crates/heph/src/main.rs | 2 +- crates/hephd/src/main.rs | 2 +- .../release-version-bump.bugfix.md | 1 + .../changelog.d/release-version-bump.infra.md | 1 + 7 files changed, 113 insertions(+), 27 deletions(-) create mode 100644 crates/heph-core/build.rs create mode 100644 docs/changelog.d/release-version-bump.bugfix.md create mode 100644 docs/changelog.d/release-version-bump.infra.md diff --git a/.forgejo/workflows/release.yaml b/.forgejo/workflows/release.yaml index f54aaeb..8d6dcff 100644 --- a/.forgejo/workflows/release.yaml +++ b/.forgejo/workflows/release.yaml @@ -156,6 +156,34 @@ jobs: echo "" > /tmp/release_notes.md fi + - name: Commit changelog to main + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + VERSION="${{ steps.version.outputs.version }}" + CHANGELOG_UPDATED="${{ steps.changelog.outputs.changelog_updated }}" + + git config user.name "Forgejo Actions" + git config user.email "actions@forge.eblu.me" + + if [ "$CHANGELOG_UPDATED" != "true" ]; then + echo "No changelog changes to commit" + exit 0 + fi + + # Consumed towncrier fragments must land on main so the next release + # does not re-process them. main stays at version 0.0.0; the version + # bump lives only on the release tag (see "Bump version and tag + # release" below, whose commit is a child of this one). + git add CHANGELOG.md docs/changelog.d/ + if git diff --cached --quiet; then + echo "No changes to commit" + else + git commit -m "Update changelog for $VERSION [skip ci]" + git push origin HEAD:main + echo "Changelog changes committed and pushed to main" + fi + - name: Build docs run: | VERSION="${{ steps.version.outputs.version }}" @@ -181,6 +209,35 @@ jobs: echo "Release asset inventory:" find release-assets -maxdepth 1 -type f -print | sort || true + - name: Bump version and tag release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + VERSION="${{ steps.version.outputs.version }}" # vX.Y.Z + BARE="${VERSION#v}" # X.Y.Z + + git config user.name "Forgejo Actions" + git config user.email "actions@forge.eblu.me" + + # Bake the release version into the manifests on a commit that ONLY + # the tag will point at. main deliberately stays at 0.0.0; this is the + # version that `cargo install --git --tag ` compiles into + # `--version`. Cargo.lock must match Cargo.toml for `--locked` + # installs: exactly the five workspace crates are at 0.0.0, so the + # anchored substitution is unambiguous (verified — no third-party + # dependency is pinned to 0.0.0). + sed -i 's/^version = "0.0.0"$/version = "'"$BARE"'"/' Cargo.toml Cargo.lock + git add Cargo.toml Cargo.lock + git commit -m "Release $VERSION [skip ci]" + + # Tag the bump commit and push ONLY the tag, so the versioned commit + # is reachable via the tag without advancing main. The Create release + # step below then attaches a release to this existing tag. + git tag "$VERSION" + git push origin "refs/tags/$VERSION" + echo "Tagged $VERSION at $(git rev-parse --short HEAD); main left at 0.0.0" + - name: Create release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -190,6 +247,8 @@ jobs: CHANGELOG_UPDATED="${{ steps.changelog.outputs.changelog_updated }}" FORGE_URL="${{ github.server_url }}/api/v1/repos/${{ github.repository }}" + # The tag was already created and pushed by "Bump version and tag + # release"; this attaches a Forgejo release to that existing tag. echo "Creating release $VERSION..." { @@ -263,31 +322,6 @@ jobs: echo "" echo "Release created successfully!" - - name: Commit changelog changes - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - VERSION="${{ steps.version.outputs.version }}" - CHANGELOG_UPDATED="${{ steps.changelog.outputs.changelog_updated }}" - - if [ "$CHANGELOG_UPDATED" != "true" ]; then - echo "No changelog changes to commit" - exit 0 - fi - - git config user.name "Forgejo Actions" - git config user.email "actions@forge.eblu.me" - - git add CHANGELOG.md docs/changelog.d/ - - if git diff --cached --quiet; then - echo "No changes to commit" - else - git commit -m "Update changelog for $VERSION [skip ci]" - git push origin HEAD:main - echo "Changelog changes committed and pushed" - fi - - name: Summary run: | VERSION="${{ steps.version.outputs.version }}" diff --git a/crates/heph-core/build.rs b/crates/heph-core/build.rs new file mode 100644 index 0000000..f0fe636 --- /dev/null +++ b/crates/heph-core/build.rs @@ -0,0 +1,44 @@ +//! Build script: capture the short git SHA this build came from so the CLI +//! surfaces can report ` ()`. The crate version itself comes from +//! `Cargo.toml` (bumped to the release version on the release tag — see +//! `.forgejo/workflows/release.yaml`); this only adds the provenance suffix. +//! +//! Resolution order: the `HEPH_BUILD_SHA` env override (an escape hatch for +//! builds with no `.git`, e.g. a source tarball) → `git rev-parse` → `unknown`. + +use std::process::Command; + +fn main() { + println!("cargo:rerun-if-env-changed=HEPH_BUILD_SHA"); + // Rebuild when HEAD moves so the embedded SHA stays accurate. Best-effort: + // a missing path here is harmless (cargo just won't watch it). + println!("cargo:rerun-if-changed=../../.git/HEAD"); + + let sha = std::env::var("HEPH_BUILD_SHA") + .ok() + .filter(|s| !s.is_empty()) + .or_else(git_short_sha) + .unwrap_or_else(|| "unknown".to_string()); + + println!("cargo:rustc-env=HEPH_BUILD_SHA={sha}"); +} + +fn git_short_sha() -> Option { + let out = Command::new("git") + .args(["rev-parse", "--short=9", "HEAD"]) + .output() + .ok()?; + if !out.status.success() { + return None; + } + let sha = String::from_utf8(out.stdout).ok()?.trim().to_string(); + if sha.is_empty() { + return None; + } + let dirty = Command::new("git") + .args(["status", "--porcelain"]) + .output() + .map(|o| !o.stdout.is_empty()) + .unwrap_or(false); + Some(if dirty { format!("{sha}-dirty") } else { sha }) +} diff --git a/crates/heph-core/src/lib.rs b/crates/heph-core/src/lib.rs index d9b9ecd..e5ff637 100644 --- a/crates/heph-core/src/lib.rs +++ b/crates/heph-core/src/lib.rs @@ -8,6 +8,12 @@ //! injected [`Clock`](clock::Clock) (tech-spec §2) so ranking and recurrence are //! deterministic. +/// Full version string for the CLI surfaces: `" ()"`, +/// e.g. `"1.0.0 (ab6701d12)"`. The version is the workspace version baked into +/// the release tag's manifest (`main` stays `0.0.0`); the short SHA is captured +/// at build time by `build.rs`. Used by `heph`/`hephd` for `--version`. +pub const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", env!("HEPH_BUILD_SHA"), ")"); + pub mod clock; mod crdt; pub mod error; diff --git a/crates/heph/src/main.rs b/crates/heph/src/main.rs index 505aa93..735bfe1 100644 --- a/crates/heph/src/main.rs +++ b/crates/heph/src/main.rs @@ -18,7 +18,7 @@ use hephd::{datespec, default_socket_path, Client, DeviceFlow, KeyringTokenStore mod service; #[derive(Parser, Debug)] -#[command(name = "heph", version, about)] +#[command(name = "heph", version = heph_core::VERSION, about)] struct Cli { /// Path to the hephd unix socket (defaults to the standard runtime path). #[arg(long, global = true)] diff --git a/crates/hephd/src/main.rs b/crates/hephd/src/main.rs index ee07cf6..62df200 100644 --- a/crates/hephd/src/main.rs +++ b/crates/hephd/src/main.rs @@ -38,7 +38,7 @@ enum Mode { /// The Hephaestus per-device daemon. #[derive(Parser, Debug)] -#[command(name = "hephd", version, about)] +#[command(name = "hephd", version = heph_core::VERSION, about)] struct Cli { /// Runtime mode. #[arg(long, value_enum, default_value_t = Mode::Local)] diff --git a/docs/changelog.d/release-version-bump.bugfix.md b/docs/changelog.d/release-version-bump.bugfix.md new file mode 100644 index 0000000..d29a48c --- /dev/null +++ b/docs/changelog.d/release-version-bump.bugfix.md @@ -0,0 +1 @@ +`heph --version` / `hephd --version` now report the release version plus the build commit (e.g. `1.0.0 (ab6701d12)`) instead of a bare `0.0.0`. The short git SHA is captured at build time, so any build — released, branch, or dirty working tree — is traceable to its commit. diff --git a/docs/changelog.d/release-version-bump.infra.md b/docs/changelog.d/release-version-bump.infra.md new file mode 100644 index 0000000..d3f1a21 --- /dev/null +++ b/docs/changelog.d/release-version-bump.infra.md @@ -0,0 +1 @@ +The release workflow now bakes the release version into `Cargo.toml` + `Cargo.lock` on a commit that only the release tag points at (tagging it manually), so `cargo install --git --tag vX.Y.Z` reports the real version while `main` stays at `0.0.0`. From 521e5d62df91f0dde71acd815b6496f4a432b37c Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Thu, 4 Jun 2026 09:47:23 -0700 Subject: [PATCH 3/3] docs: install-heph defaults to the v1.0.0 release tag (v1 is out) Replace the pre-release 'install from feature/v1-prototype' instructions with `--tag v1.0.0` as the default, and document `--branch main` as the track- unreleased-work alternative. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/how-to/install-heph.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/how-to/install-heph.md b/docs/how-to/install-heph.md index fa69e02..dd0036a 100644 --- a/docs/how-to/install-heph.md +++ b/docs/how-to/install-heph.md @@ -1,6 +1,6 @@ --- title: Install heph (and isolate dev) -modified: 2026-06-02 +modified: 2026-06-04 tags: - how-to --- @@ -14,18 +14,19 @@ linux/arm64, linux/amd64). ## 1. Install the binaries from the forge -Build and install `heph` + `hephd` to `~/.cargo/bin` (on `PATH`) from a forge -ref. Until v1 is tagged, install from the branch: +Build and install `heph` + `hephd` to `~/.cargo/bin` (on `PATH`) from the latest +release tag: ```bash cargo install --locked \ --git ssh://forgejo@forge.ops.eblu.me:2222/eblume/hephaestus.git \ - --branch feature/v1-prototype \ + --tag v1.0.0 \ heph hephd ``` -Re-run with `--tag vX.Y.Z` once a release is cut. This needs forge SSH access -(an unlocked 1Password / ssh-agent key). +Bump `--tag` to upgrade to a newer release; to track unreleased work instead, +swap `--tag vX.Y.Z` for `--branch main`. This needs forge SSH access (an +unlocked 1Password / ssh-agent key). `heph --version` / `hephd --version` report `X.Y.Z ()` for a tagged install and `0.0.0 ()` for a branch/dev install — the release version