diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000..ff949d8 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,45 @@ +name: Update Changelog + +# Keeps the [Unreleased] section of CHANGELOG.md current as work lands on main. +# A release (release.yml) later promotes [Unreleased] -> [vX.Y.Z] via --tag. +on: + push: + branches: [main] + +permissions: + contents: write + +# Serialize so two quick merges can't race on pushing CHANGELOG.md back to main. +concurrency: + group: changelog-main + cancel-in-progress: false + +jobs: + changelog: + name: Update Changelog + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + token: ${{ secrets.RELEASE_TOKEN }} + fetch-depth: 0 + + - name: Install git-cliff + run: pip install git-cliff + + - name: Regenerate unreleased changelog + run: make changelog.unreleased + + - name: Commit if changed + run: | + if git diff --quiet -- CHANGELOG.md; then + echo "CHANGELOG.md already up to date" + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add CHANGELOG.md + # [skip ci] stops this push from re-triggering the workflow (loop guard). + git commit -m "chore(changelog): update unreleased [skip ci]" + git push origin HEAD:main diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e2db0c4..b26e128 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,8 +49,11 @@ jobs: run: | # Full changelog for CHANGELOG.md (committed to repo) make changelog VERSION=${{ github.event.inputs.version }} - # Release notes for this version only (passed to goreleaser) - git-cliff --tag ${{ github.event.inputs.version }} --latest --strip header -o RELEASE_NOTES.md + # Release notes for this version only (passed to goreleaser). + # --unreleased (not --latest): the tag is created in a later step, so these + # commits aren't tagged yet. --latest would select the previous tag (v1.7.0), + # which is the bug this fixes. --tag labels the unreleased section with VERSION. + git-cliff --unreleased --tag ${{ github.event.inputs.version }} --strip header -o RELEASE_NOTES.md - name: Commit changelog and tag release run: | @@ -59,7 +62,9 @@ jobs: git config user.email "github-actions[bot]@users.noreply.github.com" git remote set-url origin https://x-access-token:${{ secrets.RELEASE_TOKEN }}@github.com/${{ github.repository }} git add CHANGELOG.md - git commit -m "chore(release): update changelog for ${VERSION}" + # [skip ci]: the changelog already reflects this release; no need to + # re-trigger the Update Changelog workflow on this push. + git commit -m "chore(release): update changelog for ${VERSION} [skip ci]" git tag "${VERSION}" git push origin main --tags diff --git a/Makefile b/Makefile index b2cc232..d01f6c9 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ OUTPUT_DIR ?= bin -.PHONY: all build clean lint lint.fix security test test.integration test-s3-integration fmt changelog hooks.install pre-commit help +.PHONY: all build clean lint lint.fix security test test.integration test-s3-integration fmt changelog changelog.unreleased hooks.install pre-commit help ## Build ------------------------------------------------------------------- @@ -49,6 +49,9 @@ ifndef VERSION endif @git-cliff --tag $(VERSION) -o CHANGELOG.md +changelog.unreleased: ## Regenerate CHANGELOG.md with pending commits under [Unreleased] + @git-cliff -o CHANGELOG.md + ## Git Hooks --------------------------------------------------------------- hooks.install: ## Configure git to use githooks/ as the hooks directory diff --git a/cliff.toml b/cliff.toml index 224a3ef..7e553c3 100644 --- a/cliff.toml +++ b/cliff.toml @@ -32,4 +32,5 @@ topo_order = false sort_commits = "oldest" commit_parsers = [ { message = "^chore\\(release\\)", skip = true }, + { message = "^chore\\(changelog\\)", skip = true }, ]