fix(generate-changelog): do not fail on release commits or empty changelogs - #78
Conversation
b010cbc to
fb78c39
Compare
fb78c39 to
d645d69
Compare
…gelogs
The generate_changelog workflow fires on every push to main, including when a
release PR is merged. Commitizen then has nothing to add to the changelog and
exits non-zero, failing the job. Two variants have been observed in
dfinity/icp-js-core:
- exit 3 ("No commits found") when the tag already exists
- exit 16 ("No tag found to do an incremental changelog") when the tag has not
been pushed yet, which is the common case since the release tag is pushed
manually a couple of minutes after the release PR merges
Both are no-ops in intent, not errors. Two complementary changes:
- Skip the changelog steps entirely when the head commit subject looks like a
release commit, via a new release_commit_pattern input. This covers the exit
16 case, whose cause is the tag not existing yet.
- Treat commitizen exit 3 as success in actions/generate-changelog, so a
release commit that slips past the subject check (retitled release PR, or a
repo that permits merge commits) still does not fail the job.
Exit 16 deliberately remains fatal. Unlike exit 3 it is ambiguous: it also
fires when tags are genuinely unavailable, for example a shallow clone or a
regression in tag fetching. Swallowing it would turn a loud failure into a
silent no-op where the changelog quietly stops being generated.
Closes #75
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The changelog workflow now treats exit code 3 as a no-op, so the tool defining that code should not upgrade itself on every run. Verified against the pinned version that 3 is NO_COMMITS_FOUND. Also documents release_commit_pattern, which the workflow README was missing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
d645d69 to
f1939a4
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Update the immutable internal action pins and correct the documented release-pattern escaping before approval.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
This PR prevents changelog generation from failing on release commits or empty changelogs.
Changes:
- Detects release commits and skips unnecessary workflow steps.
- Treats Commitizen exit code 3 as successful.
- Pins Commitizen to 4.18.1 and documents the new behavior.
File summaries
| File | Reviewed changes and findings |
|---|---|
workflows/generate-changelog/README.md |
Documents the new input. Nit (1 vote): correct the escaped pipe in the default pattern. |
actions/setup-commitizen/README.md |
Documents Commitizen pinning. |
actions/setup-commitizen/action.yaml |
Pins Commitizen. Moderate (1 vote): update workflow callers to use a commit containing this change. |
actions/generate-changelog/action.yaml |
Handles exit code 3. Moderate (1 vote): update the workflow’s immutable action reference. |
.github/workflows/generate-changelog.yaml |
Adds release-commit detection and conditional steps. Moderate (2 votes): update the internal action pins from the pre-change commit. |
Review details
Suppressed comments (3)
actions/generate-changelog/action.yaml:19
- This new exit-code handling is not used by the reusable workflow:
.github/workflows/generate-changelog.yamlstill invokesdfinity/ci-tools/actions/generate-changelog@afeee4fbdc0683a88ec5a74ed7f59a2ce0e833ad, an immutable SHA from before this change. After merge, an empty changelog will still run the old one-line command and fail with exit 3. Update the pinned action reference to a commit containing this change.
cz changelog --incremental --merge-prerelease --file-name="$FILE_NAME" --version-scheme semver2
actions/setup-commitizen/action.yaml:11
- This pin is likewise not used by the repository's workflow callers:
check-commit-messages,check-pr-title, andgenerate-changelogall pinsetup-commitizentoafeee4fbdc0683a88ec5a74ed7f59a2ce0e833ad. Because that ref is immutable, those workflows will continue installing the unpinned Commitizen action after this change, so the exit-code contract is still not reproducible. Update their pinned refs to a commit containing this action change.
run: pip install 'commitizen==4.18.1'
workflows/generate-changelog/README.md:24
- The documented default contains
\|inside an inline code span, so it renders as a backslash plus pipe rather than the|alternation in the workflow default. A user copying this value will not match normal subjects such aschore: release 1.2.3; use a table-safe representation that renders a literal|without the backslash.
| `release_commit_pattern` | Skip changelog generation when the head commit subject matches this extended regular expression. Set to an empty string to disable the check. | `'^chore:[[:space:]]release([[:space:]]\|$)'` |
- Files reviewed: 5/5 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🔵 Needs a closer look
Invalid release-pattern expressions can silently disable the release guard and should fail explicitly.
Review details
Suppressed comments (1)
.github/workflows/generate-changelog.yaml:119
[[ ... =~ ... ]]returns status 2 for an invalid ERE, but because it is used directly as anifcondition,set -edoes not abort and theelsebranch recordsskip=false. A typo in this configurable pattern therefore silently disables the release guard and can let a release commit run through changelog generation; capture the match status and fail explicitly when it is 2.
if [ -n "$RELEASE_COMMIT_PATTERN" ] && [[ "$subject" =~ $RELEASE_COMMIT_PATTERN ]]; then
echo 'skip=true' >> "$GITHUB_OUTPUT"
echo "::notice::Head commit is a release commit ('$subject'); skipping changelog generation."
else
echo 'skip=false' >> "$GITHUB_OUTPUT"
fi
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
Bash returns 2 rather than 1 for a malformed regular expression, and as an if condition that fell through to the else branch and recorded skip=false. A typo in the pattern therefore disabled the release check while the job stayed green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Valid, including the suppressed one, and fixed in 20889b4. Confirmed the behaviour first — bash returns 2 for a malformed ERE and the So a typo in a configurable input silently disabled the guard while the job stayed green — the same quiet-failure shape this PR is trying to remove, which makes it worth fixing rather than suppressing. The match status is now captured and 2 fails the step with Empty still disables the check deliberately, as documented. |
#78 changed the generate-changelog and setup-commitizen actions, which the workflows still pinned from before, so they would have kept running the previous copies. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* ci: fail when a workflow pins a stale copy of an action Workflows reference this repository's own actions by commit SHA, and those pins do not move when an action changes, so a workflow keeps running the previous copy of it. Passing a newly added input to such an action is reported as a warning rather than an error, so the run stays green while the new behaviour does nothing. actions/create-pr was already a commit behind, which meant the bundle rebuilt in #79 was not the one the changelog workflow ran. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: note the bump constraints on the self reference check A bump has to be its own pull request, because --fix can only pin to a commit that already exists. And the check cannot be a required status check, since it only reports after a merge. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: fail clearly on a shallow clone in the self reference check Pins are resolved against local history, so a shallow checkout made every one of them report as an unknown commit, which reads as a problem with the references rather than with the checkout. The documented example now shows the checkout it needs, and says that the script covers this repository only. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: pin self references at the default branch, not HEAD --fix resolved HEAD, so running it from a branch wrote a SHA that squash and rebase merges discard, leaving a reference to a commit that never lands. It now pins at the default branch tip and says so when that differs from HEAD. Also corrects the usage text, which claimed --fix repoints every reference unconditionally when it only does so once one has fallen behind. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: repoint workflow self references at the current commit #78 changed the generate-changelog and setup-commitizen actions, which the workflows still pinned from before, so they would have kept running the previous copies. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fixes #75.
generate_changelogruns on every push tomain, release-PR merges included. Commitizen has nothing to add on those and exits non-zero, so the job fails.Behaviour changes
release_commit_patterninput skips changelog generation entirely. Default^chore:[[:space:]]release([[:space:]]|$); an empty string disables the check.No commits found, no longer fails the job.release_commit_patternnow fails the step. Bash returns 2 for a malformed expression, which previously read as "not a release commit" and silently disabled the check.4.18.1, rather thanpip install -Uupgrading it on every run.For the reviewer
Exit 16 stays fatal. It also fires when tags are genuinely unavailable, so swallowing it would let changelog generation stop silently. The subject check covers the release case instead, which means a retitled release PR can still fail.
Inert until #87 lands. The exit-code handling and the Commitizen pin live in actions this workflow still pins at
afeee4f.🤖 Generated with Claude Code