Skip to content

Fix: Empty changelog groups, silent-skip on empty release, and publish race - #9

Merged
tajobe merged 1 commit into
mainfrom
fix/changelog-groups-and-publish-race
Jul 22, 2026
Merged

Fix: Empty changelog groups, silent-skip on empty release, and publish race#9
tajobe merged 1 commit into
mainfrom
fix/changelog-groups-and-publish-race

Conversation

@tajobe

@tajobe tajobe commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • changelog.groups is now empty instead of the plugin's default 6-item Keep a Changelog list, so patchChangelog no longer stubs out empty ### Added / ### Changed / ... headers in every new Unreleased section.
  • Set patchEmpty = false on the patchChangelog task invoked from the release hook. Previously, if Unreleased had no content at release time, PatchChangelogTask threw StopActionException, which — since we call .run() directly instead of through Gradle's task graph — got silently swallowed, making the entire release a silent no-op (no commit, no tag, no push) while reporting BUILD SUCCESSFUL. Now it throws MissingReleaseNoteException, a real failure with a clear message.
  • publish-workflow.yml triggers on both the branch push and the tag push from the same release, so two Publish runs fired concurrently and both tried to gradlew publish the same version — one 409s. Added a check-tag step and gated the Gradle Publish step to skip on the branch-triggered run when it's also sitting on a release tag, so only the tag-triggered run publishes.

Test plan

  • ./gradlew clean build passes
  • Verified groups = emptyList() in an isolated worktree via release.localOnly: the new Unreleased section has no stub headers, and existing Unreleased content correctly moved into the new version section (confirmed via git show diff on the resulting local commit)
  • Verified patchEmpty = false in an isolated worktree: with an empty Unreleased section, the release now fails loudly with MissingReleaseNoteException instead of silently producing no commit/tag/push while reporting success
  • publish-workflow.yml YAML syntax validated; the if: condition logic matches the described skip case (branch run + on a release tag) directly

…h race

- changelog.groups is now empty instead of the plugin's default 6-item
  Keep a Changelog list, so patchChangelog no longer stubs out empty
  "### Added / ### Changed / ..." headers in every new Unreleased
  section.
- Set patchEmpty = false on the patchChangelog task invoked from the
  release hook. Previously, if Unreleased had no content at release
  time, PatchChangelogTask threw StopActionException, which - since
  we call .run() directly instead of through Gradle's task graph - got
  silently swallowed, making the entire release a silent no-op (no
  commit, no tag, no push) while reporting BUILD SUCCESSFUL. Now it
  throws MissingReleaseNoteException, a real failure with a clear
  message.
- publish-workflow.yml triggers on both the branch push and the tag
  push from the same release, so two Publish runs fired concurrently
  and both tried to `gradlew publish` the same version - one 409s.
  Added a check-tag step and gated the Gradle Publish step to skip on
  the branch-triggered run when it's also sitting on a release tag, so
  only the tag-triggered run publishes.

Verified all three fixes locally using axion's release.localOnly mode
in isolated worktrees:
- groups=emptyList(): new Unreleased section has no stub headers,
  existing content correctly moved into the new version section.
- patchEmpty=false: release now fails loudly with
  MissingReleaseNoteException when Unreleased is empty, instead of
  silently doing nothing.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the release/publish automation around changelog patching and GitHub Packages publishing, addressing empty changelog group stubs, silent release skipping when Unreleased is empty, and duplicate publish attempts from concurrent workflow triggers.

Changes:

  • Stop pre-populating new Unreleased sections with default Keep a Changelog group headers by setting changelog.groups to empty.
  • Make the release hook fail loudly when Unreleased has no content by setting patchEmpty = false on the invoked patchChangelog task.
  • Add tag-detection and gating in the publish workflow to avoid duplicate publishes when both branch and tag pushes trigger concurrently.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 1 comment.

File Description
CHANGELOG.md Updates Unreleased notes to reflect the release/publish automation fixes.
build.gradle.kts Adjusts changelog plugin configuration and makes empty-Unreleased releases fail loudly.
.github/workflows/publish-workflow.yml Attempts to prevent duplicate publishes by skipping publish on the branch-triggered run when a release tag is present.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 16 to 20
- uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- uses: gradle/actions/setup-gradle@v6
@tajobe
tajobe merged commit 6cb90dd into main Jul 22, 2026
2 checks passed
@tajobe
tajobe deleted the fix/changelog-groups-and-publish-race branch July 22, 2026 18:07
tajobe added a commit that referenced this pull request Jul 22, 2026
…h race (#9)

- changelog.groups is now empty instead of the plugin's default 6-item
  Keep a Changelog list, so patchChangelog no longer stubs out empty
  "### Added / ### Changed / ..." headers in every new Unreleased
  section.
- Set patchEmpty = false on the patchChangelog task invoked from the
  release hook. Previously, if Unreleased had no content at release
  time, PatchChangelogTask threw StopActionException, which - since
  we call .run() directly instead of through Gradle's task graph - got
  silently swallowed, making the entire release a silent no-op (no
  commit, no tag, no push) while reporting BUILD SUCCESSFUL. Now it
  throws MissingReleaseNoteException, a real failure with a clear
  message.
- publish-workflow.yml triggers on both the branch push and the tag
  push from the same release, so two Publish runs fired concurrently
  and both tried to `gradlew publish` the same version - one 409s.
  Added a check-tag step and gated the Gradle Publish step to skip on
  the branch-triggered run when it's also sitting on a release tag, so
  only the tag-triggered run publishes.

Verified all three fixes locally using axion's release.localOnly mode
in isolated worktrees:
- groups=emptyList(): new Unreleased section has no stub headers,
  existing content correctly moved into the new version section.
- patchEmpty=false: release now fails loudly with
  MissingReleaseNoteException when Unreleased is empty, instead of
  silently doing nothing.
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.

2 participants