Skip to content

feat: enforce CHANGELOG.md on release commits - #11

Merged
robdefeo merged 2 commits into
mainfrom
feat/changelog-guard
Apr 22, 2026
Merged

feat: enforce CHANGELOG.md on release commits#11
robdefeo merged 2 commits into
mainfrom
feat/changelog-guard

Conversation

@robdefeo

Copy link
Copy Markdown
Owner

Summary

  • Adds changelog-guard to the lefthook pre-commit hook — mirrors the existing version-guard pattern:
    • On release/v* branches: fails if CHANGELOG.md is not staged (run just changelog first)
    • On all other branches: fails if CHANGELOG.md is staged (keeps it off main)
  • Switches dist-workspace.toml from changelog = "git-cliff" (CI invocation, required full git history) to changelog = "CHANGELOG.md" (reads the pre-generated file from the release commit — works with shallow clone)
  • Updates RELEASING.md to document the just changelog step

Supersedes

Closes #10 — the fetch-depth: 0 workaround is no longer needed.

Release flow after this PR

git checkout -b release/vx.y.z origin/main
# Edit Cargo.toml: set version = "x.y.z"
mise exec -- just changelog        # generates CHANGELOG.md
git commit -am "chore: release vx.y.z"   # hook enforces both guards
git tag vx.y.z && git push origin vx.y.z

🤖 Generated with Claude Code

- Add changelog-guard to lefthook: requires CHANGELOG.md staged on
  release/v* branches, blocks it on all other branches
- Switch cargo-dist changelog source from git-cliff (CI) to CHANGELOG.md
  (committed with the release) — no CI git history dependency
- Update RELEASING.md to document the new 'just changelog' step
@greptile-apps

greptile-apps Bot commented Apr 22, 2026

Copy link
Copy Markdown

Greptile Summary

This PR completes the release-tooling overhaul by introducing a changelog-guard pre-commit hook and switching cargo-dist from runtime git-cliff invocation to reading a pre-committed CHANGELOG.md. Together these changes make shallow-clone CI work correctly and enforce a clean, auditable release commit that contains both the bumped version and the generated changelog.

  • changelog-guard in .config/lefthook.json mirrors the existing version-guard pattern: requires CHANGELOG.md to be staged on release/v* branches and forbids it on all others. The fallback path (second commit on a release branch) is correctly handled by checking git ls-files + git diff, though the git ls-files call leaks its output to stdout (see inline comment).
  • dist-workspace.toml: changelog = "CHANGELOG.md" removes the need for fetch-depth: 0 in CI workflows — cargo-dist reads the file directly from the release commit.
  • RELEASING.md: documentation accurately reflects the new mise exec -- just changelog step and the hook enforcement guarantee.

Confidence Score: 4/5

Safe to merge; the single open issue is a cosmetic stdout leak in an edge-case path that does not affect correctness.

The core logic is sound: the guard correctly enforces the single-commit release workflow and the fallback for second commits works as intended. The only finding is the missing >/dev/null on git ls-files, which causes a spurious filename to appear in terminal output but never prevents a valid commit or allows an invalid one. The dist-workspace.toml change is straightforward and correctly eliminates the shallow-clone limitation. Documentation is accurate and complete.

.config/lefthook.json — minor stdout suppression fix on line 15.

Important Files Changed

Filename Overview
.config/lefthook.json Adds changelog-guard pre-commit hook; logic is correct for the primary release flow with a minor stdout-leak in the tracked-but-unstaged fallback path.
dist-workspace.toml Switches changelog from "git-cliff" (runtime invocation requiring full history) to "CHANGELOG.md" (reads pre-generated file); straightforward and correct.
RELEASING.md Documentation updated to reflect the new just changelog step and removal of git-cliff from CI; accurate and clear.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[git commit] --> B{branch?}
    B -- "release/v*" --> C{CHANGELOG.md staged?}
    C -- yes --> G[allow commit ✅]
    C -- no --> D{CHANGELOG.md tracked\nand unmodified?}
    D -- yes --> G
    D -- no --> E[❌ error: run just changelog]
    B -- "other branch" --> F{CHANGELOG.md staged?}
    F -- yes --> H[❌ error: do not commit CHANGELOG.md here]
    F -- no --> G
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: .config/lefthook.json
Line: 15

Comment:
**`git ls-files` emits filename to stdout**

`git ls-files --error-unmatch CHANGELOG.md 2>/dev/null` only redirects stderr. When `CHANGELOG.md` is tracked, the command prints `CHANGELOG.md` to stdout, which lefthook will surface to the developer. This is harmless but confusing — they'll see a bare `CHANGELOG.md` line printed during the pre-commit hook on a second release-branch commit.

Add `>/dev/null` alongside `2>/dev/null` to suppress it.

```suggestion
        "run": "branch=$(git rev-parse --abbrev-ref HEAD); case \"$branch\" in release/v*) if git diff --cached --name-only | grep -q '^CHANGELOG.md$'; then :; elif git ls-files --error-unmatch CHANGELOG.md >/dev/null 2>/dev/null && ! git diff --name-only -- CHANGELOG.md | grep -q '^CHANGELOG.md$'; then :; else echo \"error: CHANGELOG.md must be staged on release branches (run: mise exec -- just changelog)\"; exit 1; fi;; *) if git diff --cached --name-only | grep -q '^CHANGELOG.md$'; then echo \"error: CHANGELOG.md must not be committed on non-release branches\"; exit 1; fi;; esac"
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix(changelog-guard): allow follow-up co..." | Re-trigger Greptile

Comment thread .config/lefthook.json Outdated
When CHANGELOG.md is already tracked and unmodified, subsequent commits
on a release/v* branch no longer require re-staging the file.
@robdefeo
robdefeo merged commit 7f587b4 into main Apr 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant