Conversation
- Add .github/workflows/release.yml triggered by v* tags; builds binaries for macOS arm64/x86_64 and Linux x86_64, generates release notes via git-cliff, and creates a GitHub Release with attached assets - Add cliff.toml for conventional-commits changelog configuration - Add `cargo xtask release [--dry-run]` subcommand that verifies a clean working tree, updates CHANGELOG.md via git-cliff, and creates an annotated git tag ready to push Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
geoffjay
left a comment
There was a problem hiding this comment.
Review — PR #1177: Release Automation
Good structure overall. The three-file split (workflow, cliff config, xtask subcommand) is clean and each piece does one thing. Two issues need to be fixed before merge.
Branch target
This PR targets main directly. CLAUDE.md states all work branches off feature/autonomous-pipeline and PRs back into it, never directly to main. Release tooling may be intentionally excluded from that rule, but worth confirming with the project owner before merging.
Blocking issues
1. Unchecked exit codes for git add and git commit in release() (crates/xtask/src/main.rs, ~lines 685–701)
Command::new("git")
.args(["add", "CHANGELOG.md"])
.status()
.context("Failed to stage CHANGELOG.md")?;
Command::new("git")
.args(["commit", "-m", &format!("chore(release): update changelog for {tag}")])
.status()
.context("Failed to commit CHANGELOG.md")?;.status().context(...)? only propagates an io::Error if the process failed to spawn — it does not fail when the command exits non-zero. If git add or git commit returns exit code 1, execution silently continues and the tag is created on a commit that does not include the updated CHANGELOG.md.
Every other long-running command in this codebase (e.g. build_release()) explicitly checks .success(). Apply the same pattern here:
let status = Command::new("git")
.args(["add", "CHANGELOG.md"])
.status()
.context("Failed to stage CHANGELOG.md")?;
if !status.success() {
anyhow::bail!("git add CHANGELOG.md failed");
}Same fix needed for the git commit call immediately below.
Non-blocking suggestions
2. Linux target: x86_64-unknown-linux-gnu → x86_64-unknown-linux-musl (.github/workflows/release.yml)
GNU-linked binaries dynamically link against glibc. The ubuntu-latest runner ships glibc 2.35+, so binaries built there will fail on older distributions (Ubuntu 20.04, CentOS, Alpine) with GLIBC_X.XX not found. For distributed release binaries, musl produces a fully static binary that runs on any Linux regardless of system glibc version.
Change the target and add musl-tools:
- target: x86_64-unknown-linux-musl
os: ubuntu-latest# In the Linux protoc step:
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler musl-tools3. GitHub PR link enrichment silently produces no links (.github/workflows/release.yml, "Generate release notes" step)
cliff.toml includes {% if commit.github.pr_number %} enrichment, but git-cliff reads GITHUB_TOKEN from the environment to query the GitHub API. Actions does not expose secrets.GITHUB_TOKEN automatically as an env var — it must be wired explicitly:
- name: Generate release notes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: git cliff --current --output RELEASE_NOTES.mdWithout this, pr_number is always empty and PR links never appear in release notes. The release still works — it just degrades silently.
4. No pre-flight checks in cargo xtask release (crates/xtask/src/main.rs)
The function creates a tag without verifying the build is clean. If run on a commit that hasn't passed CI, the release workflow fires on potentially broken code. Consider adding cargo fmt --check and cargo clippy -- -D warnings before creating the tag.
5. Misleading variable name staged (~line 682)
let staged = Command::new("git").args(["diff", "--quiet", "CHANGELOG.md"]) checks for unstaged working-tree changes, not staged ones. Rename to changelog_changed or has_changes.
6. filter_commits = false in cliff.toml
With conventional_commits = true + filter_unconventional = true, any conventional commit type not covered by a parser (e.g. ^revert, custom types) passes through ungrouped. Setting filter_commits = true ensures only commits matching a non-skip parser appear in the changelog.
What's correct
fetch-depth: 0on all jobs — required for git-cliff to walk tag history. ✓fail-fast: falseon the build matrix — single-platform failure doesn't cancel others. ✓permissions: contents: writescoped to the release job only. ✓- Protoc install steps for both Linux and macOS. ✓
${bin/cli/agent}bash substitution in packaging — correctly renames the user-facing binary. ✓extract_workspace_version()line parser handles real-world Cargo.toml formatting correctly. ✓git diff --quiet CHANGELOG.mdexit code semantics are correct (0 = no diff, 1 = changed). ✓
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1177 +/- ##
==========================================
- Coverage 60.33% 60.10% -0.24%
==========================================
Files 228 228
Lines 25489 25578 +89
==========================================
- Hits 15380 15374 -6
- Misses 10109 10204 +95 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…ess review feedback)
Implements automated release infrastructure triggered by
v*git tags.What's added:
.github/workflows/release.yml- GitHub Actions workflow that triggers onv*tag pushes, builds release binaries in a matrix for macOS arm64 (aarch64-apple-darwin), macOS x86_64 (x86_64-apple-darwin), and Linux x86_64 (x86_64-unknown-linux-gnu), generates release notes via git-cliff, and creates a GitHub Release with all binaries attached as assetscliff.toml- git-cliff configuration mapping conventional commit types (feat,fix,refactor,perf,docs,chore(deps)) to changelog sections; includes GitHub PR link enrichmentcrates/xtask/src/main.rs- Newcargo xtask release [--dry-run]subcommand that verifies a clean working tree, reads the workspace version fromCargo.toml, updatesCHANGELOG.mdvia git-cliff (if installed), commits the changelog, and creates an annotated git tag;--dry-runpreviews all steps without making changesRelease workflow:
Closes #137