fix(bump): only consider commit titles when matching bump patterns#1983
fix(bump): only consider commit titles when matching bump patterns#1983bearomorphism wants to merge 2 commits intocommitizen-tools:masterfrom
Conversation
`find_increment` previously scanned every line of every commit message when looking for the conventional-commits type token. Auto-generated commit bodies (notably Dependabot PR descriptions that quote upstream changelog lines like `fix: ...`) frequently contain text that matches the bump pattern even though no in-repo change of that type happened. The result was false-positive `PATCH` bumps on plain `ci:` commits (commitizen-tools#1772). Restrict type-pattern matching to the commit title (the first line), where the conventional-commits type lives. The body is still scanned, but only for `BREAKING CHANGE:` / `BREAKING-CHANGE:` footers, which the spec places there. Other body lines no longer drive the increment. Closes commitizen-tools#1772 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1983 +/- ##
=======================================
Coverage 98.23% 98.23%
=======================================
Files 61 61
Lines 2779 2784 +5
=======================================
+ Hits 2730 2735 +5
Misses 49 49 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Pull request overview
Adjusts cz bump increment detection to align with Conventional Commits by matching bump patterns against the commit title only, while still honoring BREAKING CHANGE: / BREAKING-CHANGE: footers in the body. This prevents false-positive bumps from autogenerated commit bodies (e.g., Dependabot PR descriptions) that contain lines like fix: ....
Changes:
- Update
find_increment()to scancommit.titleplus body lines that begin withBREAKING CHANGE:/BREAKING-CHANGE:(after left-stripping). - Add regression tests covering the Dependabot body false-positive scenario and ensuring breaking-change footers in the body still trigger
MAJOR.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
commitizen/bump.py |
Restricts bump-pattern matching to commit titles, with an allowlist for breaking-change footers in the body. |
tests/test_bump_find_increment.py |
Adds regression tests for ignoring type-like tokens in commit bodies and preserving breaking-change footer behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
drafting this since I'm going to remove |
Replaced the invisible U+200B in '@actions/artifact' with plain ASCII so the fixture is readable, greppable, and produces clean diffs. Test still asserts the regression (type tokens in commit body don't trigger a bump). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description
Closes #1772.
Why
cz bumpwas producing spuriousPATCHversion bumps onci:commits whose bodies contained Dependabot-generated content. Dependabot's pull-request descriptions quote upstream repository changelogs verbatim, and those changelogs routinely contain lines such asfix: update @actions/artifact to ^5.0.0 for Node.js 24 punycode fix. Becausefind_incrementincommitizen/bump.py:37(master) iterates over every line ofcommit.message— which is computed asf"{self.title}\n\n{self.body}".strip()atcommitizen/git.py:78–79— those body lines are matched against thebump_patternand counted asfix:commits, triggering aPATCHbump on a commit that is semantically a dependency-update automation entry with aci:title.The issue was initially closed as "working as designed" after a maintainer misread the log: the
fix:line in question was not a commit in the user's repository — it was text inside the Dependabot PR body (which becomes the body of the squash-mergedci:commit). @Clockwork-Muse clarified this with a screenshot in February 2026, and @Lee-W reopened the issue. Subsequent verification against master (4.15.1) in the #1964 audit confirmed the false positive is still reproducible: aci:commit whose body contains an unbulletedfix: …line at column 0 produces aPATCHbump and a spurious### Fixchangelog section. The Conventional Commits specification places the commit type exclusively in the title (the first line); scanning every body line for type-prefixed text contradicts the spec and produces this class of false positive on auto-generated commit bodies.What changed
commitizen/bump.pyfind_increment(), replace thecommit.message.split("\n")loop at line 37 (master) with acandidate_lineslist containing onlycommit.titleplus any body lines that begin withBREAKING CHANGE:orBREAKING-CHANGE:tests/test_bump_find_increment.pytest_find_increment_ignores_type_tokens_in_commit_body(the Dependabot false-positive scenario) andtest_find_increment_still_honors_breaking_change_in_body(confirmingMAJORis still triggered by a body footer)How it works
candidate_linesis initialised as[commit.title]. Thecommit.titleattribute stores only the first line of the commit message (set atcommitizen/git.py:71), so no body content can reach thebump_patternvia this path."\n"and each line is tested withstripped.startswith(("BREAKING CHANGE:", "BREAKING-CHANGE:"))after alstrip()call. Matching lines are appended tocandidate_linesand then processed by the sameselect_pattern.search()call as the title.lstrip()rather thanstrip()for footer indentation tolerance — the non-obvious choice: the Conventional Commits spec allows trailers to be indented (e.g.,BREAKING CHANGE: x). Usinglstrip()means such indented footers are still accepted, while a body line likefix: somethingis stripped tofix: something, which does not start with either breaking-change token and so is correctly excluded. Usingstrip()instead would also work here, butlstrip()is semantically more precise — the trailing content of a footer is not guaranteed to be whitespace-free, so only left-stripping is warranted for the prefix check.commit.messageproperty untouched:commitizen/git.py:77–79definesmessageastitle + "\n\n" + bodyand this property is used elsewhere (changelog rendering, thecheckcommand). Onlyfind_incrementchanges which lines it examines; every other consumer ofcommit.messageis unaffected.Backward compatibility
fix:,feat:,perf:, etc.) is still bumped exactly as before.BREAKING CHANGE:/BREAKING-CHANGE:footers in the commit body still trigger aMAJORbump.feat!:/fix!:exclamation-mark breaking-change syntax in the title is unaffected — it is matched againstcommit.titleby the sameselect_pattern.commit.message,commit.title, andcommit.bodyonGitCommit(commitizen/git.py:60–79) are untouched.test_find_increment_*tests intests/test_bump_find_increment.pypass; the full bump command integration test suite (131 tests) passes with the same 4 GPG-fixture tests deselected on Windows as before.Checklist
Was generative AI tooling used to co-author this PR?
Generated-by: Claude following the guidelines
Code Changes
uv run poe alllocally to ensure this change passes linter check and testsExpected Behavior
ci:commit whose body containsfix: …lines (Dependabot-style)fix: normal patch fixin the commit titlePATCHbump — unchangedfeat: new featuretitle withBREAKING CHANGE: old API removedin the bodyMAJORbump — breaking-change footer still honouredfeat!: breaking change flagged in titleMAJORbump — exclamation-mark syntax in title still honouredci:commit with a bulleted body line- fix: addresses CVE-…-preventsstartswithmatch and the line is excludedSteps to Test This Pull Request
Additional Context
This fix was surfaced during the #1964 issue audit. The issue had been incorrectly closed in February 2026 after a maintainer misidentified the
fix:line as a commit in the user's own repository; @Clockwork-Muse's follow-up comment and screenshot clarified that the line comes from Dependabot quoting an upstream changelog entry — it is not a commit in the user's repository at all. @namwoam was assigned in January 2026 and identified the correct code path (commitizen/bump.py:37–38, master) but proposed an author-filter approach; this PR takes the simpler route of anchoring the type match to the commit title only, which aligns with the Conventional Commits specification without introducing new configuration surface. @namwoam is welcome to take over if still active on this — please comment and this PR will be closed.