From be044f8c183404a90dc9d7e91b68c69716d3b39b Mon Sep 17 00:00:00 2001 From: Matthew Greenwald Date: Tue, 12 May 2026 14:50:31 -0400 Subject: [PATCH] ci: drive release notes from CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous release.yml used `gh release --generate-notes`, which walked back to the previous tag and pulled every PR merged in between. For v2.0.0 that meant a year of stale dependabot bumps showed up in the notes for what was a complete rewrite. Extract the matching `## vX.Y.Z` section from CHANGELOG.md instead, and hard-fail the workflow if there's no entry — forcing the CHANGELOG to be updated before any tag can be pushed. No release is cut by this change: release.yml only fires on `vX.Y.Z` tag pushes, and this PR doesn't push a tag. The behavior takes effect on the next intentional release. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/release.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ec7904b..200e07f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,6 +28,21 @@ jobs: exit 1 } + - name: Extract release notes from CHANGELOG.md + env: + TAG: ${{ github.ref_name }} + run: | + awk -v tag="## ${TAG}" ' + $0 == tag { flag=1; next } + /^## / && flag { exit } + flag { print } + ' CHANGELOG.md | sed '/./,$!d' > /tmp/release-notes.md + if [ ! -s /tmp/release-notes.md ]; then + echo "::error::No CHANGELOG.md entry found for ${TAG}." \ + "Add a '## ${TAG}' section before tagging." + exit 1 + fi + - name: Create release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -35,5 +50,5 @@ jobs: run: | gh release create "$TAG" \ --title "$TAG" \ - --generate-notes \ + --notes-file /tmp/release-notes.md \ --verify-tag