Uh oh!
There was an error while loading. Please reload this page.
feat(bump_rule): add BumpRule, VersionIncrement enum, ConventionalCommitBumpRule - #1518
feat(bump_rule): add BumpRule, VersionIncrement enum, ConventionalCommitBumpRule#1518bearomorphism wants to merge 1 commit into
Conversation
bb305ad to
8a6c84fCompareCodecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@## master #1518 +/- ##
==========================================
+ Coverage 98.23% 98.26% +0.02%
==========================================
Files 61 62 +1 Lines 2779 2818 +39 ==========================================
+ Hits 2730 2769 +39
Misses 49 49 ☔ View full report in Codecov by Sentry. |
8a6c84f to
8dd8d42Compare
Lee-W
left a comment
There was a problem hiding this comment.
This is definitely a great pull request that cleans up a lot of legacy code. However, we need to be cautious about maintaining backward compatibility. We can likely add some of the logic incrementally while keeping compatibility for a few minor versions. After that, we can bump the major version and remove the compatibility handling code.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| return bump.find_increment(commits, regex=bump_pattern, increments_map=bump_map) | ||
| return VersionIncrement.get_highest_by_messages( | ||
| (commit.message for commit in commits), | ||
| lambda x: self.cz.bump_rule.get_increment(x, is_major_version_zero), |
There was a problem hiding this comment.
this might be a breaking change for other non-standard czs
There was a problem hiding this comment.
We'll need a way to keep backward compatibility or move it to 5.0.0 instead (but that would be a pity since the PR looks os good)
There was a problem hiding this comment.
Could you provide more details about why this might be a breaking change for non-standard cz s? I am not familiar with non-standard cz. Thanks
Uh oh!
There was an error while loading. Please reload this page.
83c02fe to
650c720Comparebb61b44 to
9cacfcbComparebearomorphism
commented
Aug 24, 2025
Can we do squash rebase on this PR when it is ready for merge? |
Lee-W
commented
Aug 25, 2025
yep, I can do that |
3cf6689 to
6d0aa11Comparebearomorphism
commented
Sep 8, 2025
What are the next steps for this PR? If there are backward compatibility issues, I can adjust it so that this PR can be checked in. Thanks |
6d0aa11 to
972d9f5CompareThere was a problem hiding this comment.
Core feature change
bearomorphism
commented
Sep 25, 2025
We can get back to this PR after #1598 |
9914feb to
9644e1aComparebearomorphism
commented
Nov 11, 2025
@Lee-W It would be great if we can complete this big PR. I can fix those backward-compatibility issues, but I need more details so I can address the issues. |
bearomorphism
commented
Nov 11, 2025
(I've resolved merge conflicts for several times for this PR) |
Lee-W
commented
Nov 13, 2025
This would fall into |
bearomorphism
commented
Jan 6, 2026
A lot of conflicts... I will probably create another branch and do the change again... |
59fc269 to
4271c36Compare4271c36 to
16ac67dComparebearomorphism
commented
May 9, 2026
will do a human review later... |
…mitBumpRule Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
16ac67d to
07a03cfCompare
Related issue: #129
Original PR: #1431
Previous iteration of this PR (force-pushed; commit
9644e1a1) covered aPrereleaseenum that has now been dropped — see "Out of scope" below.Description
Refactor commitizen's bump-rule machinery to be strict, explicit, and pluggable, while staying backward-compatible with existing
czplugins and configurations.What changes
New
BumpRuleprotocol (commitizen/bump_rule.py)BumpRule.extract_increment(commit_message, major_version_zero) -> VersionIncrement— single-message → single-increment.ConventionalCommitBumpRule— handles the conventional-commits spec (feat,fix,perf,refactor,BREAKING CHANGE/BREAKING-CHANGE,feat!:bang).CustomBumpRule— drop-in replacement for the legacybump_pattern+bump_mapflow. Tries the modern named-group form first, then falls back to the legacy regex-key form so existing user configurations keep working.BaseCommitizen.bump_ruleis a newcached_propertythat returns_bump_ruleif a plugin sets one, otherwise builds aCustomBumpRulefrombump_pattern/bump_map/bump_map_major_version_zero.ConventionalCommitsCz._bump_rule = ConventionalCommitBumpRule()opts the built-in into the new path.Consolidated
VersionIncrementenum (commitizen/version_increment.py)IntEnumalready added in feat(version): add MANUAL_VERSION, --next and --patch to version command #1724 (NONE < PATCH < MINOR < MAJOR).safe_cast(alias of existingfrom_value) —str | object → VersionIncrement, returnsNONEfor unknown.safe_cast_dict— bulk-cast aMapping[str, object]forbump_mapconversion.get_highest_by_messages(messages, extract_increment)— finds the highest increment across many commit messages, splitting multi-line messages and skippingNONE.__str__continues to returnself.name("MAJOR"/"MINOR"/"PATCH") so log lines and hook env vars are unchanged.BaseVersion.bump()acceptsVersionIncrementdirectlyIncrement: Literal["MAJOR","MINOR","PATCH"]string-typed parameter with the enum.Incrementalias is removed fromcommitizen.version_schemes.commitizen.commands.version.Version.__call__is simplified (no more 9-lineif/elifmapping enum back to string before callingbump()).commands/bump.pyuses the newBumpRuleflowBump._find_incrementnow does:bump_mapand callingbump.find_increment.CZ_PRE_INCREMENT/CZ_POST_INCREMENTas"MAJOR"/"MINOR"/"PATCH"strings (or empty when no bump). TheVersionIncrement.NONEcase is mapped back toNoneat the call site so env-var output matches master byte-for-byte.commitizen.bump.find_incrementis removed. Only callers were the deletedtests/test_bump_find_increment.py. Coverage is now provided by the per-rule tests intests/test_bump_rule.pyand the bump-flow tests intests/commands/test_bump_command.py.commitizen.defaults.MAJOR/MINOR/PATCHare now exposed only via PEP-562__getattr__with aDeprecationWarningdirecting users tocommitizen.version_increment.VersionIncrement. The string values ("MAJOR","MINOR","PATCH") are unchanged. Plus a regression test intests/test_deprecated.pyto lock the contract in (a previous iteration shipped a buggy non-tuple form that crashed on access).Docs.
docs/commands/bump.mdgains a "Custom bump" section describingbump_pattern/bump_map/bump_map_major_version_zerowith both the new named-group form and the legacy regex-key form, all in valid Pythondictsyntax.Out of scope (explicitly dropped from a previous iteration of this PR)
Prereleaseis NOT converted to an Enum. It stays asPrerelease: TypeAlias = Literal["alpha", "beta", "rc"]. Reasoning:--prereleaseto{"alpha", "beta", "rc"}via argparsechoices, and theLiteralalready pins the type-level contract.Enumwould break external Python callers ofBaseVersion.bump(prerelease="alpha")for negligible gain inside the codebase.class Prerelease(str, Enum)with a backward-compatible mixin).Backward compatibility
czplugins that definebump_pattern+bump_mapkeep working: theCustomBumpRulefallback path matches the legacybump.find_incrementsemantics for both named-group and regex-key bump maps.bump_map_major_version_zerois optional. Plugins that only definebump_patternandbump_map(withoutbump_map_major_version_zero) continue to work —CustomBumpRulevalidates this lazily and only raisesNoPatternMapErrorwhen an actual bump is attempted withmajor_version_zero=True. This mirrors master'scommands/bump.py::_find_incrementbehaviour exactly.bump_map→safe_cast_dict→CustomBumpRulepipeline. Order matters for the legacy fallback path (it returns the first matching pattern), and tests now lock the order-sensitivity in.commitizen.defaults.MAJOR/MINOR/PATCHkeep working via__getattr__(with a deprecation warning).CZ_PRE_INCREMENT,CZ_POST_INCREMENT) andcz bumpstdout output are byte-for-byte identical.BUMP_MAPvalues still serialize as"MAJOR"/"MINOR"/"PATCH"strings viastr(VersionIncrement.X).Diff at a glance
Checklist
Code Changes
tests/test_bump_rule.py(635 new lines), expandedtests/test_version_increment.py, regression entry intests/test_deprecated.py.uv run poe alllocally to ensure this change passes linter check and testsuv run ruff check— cleanuv run ruff format --check— cleanuv run mypy commitizen tests— cleanuv run pytest— 1322 passed, 3 skipped, 4 GPG-deselected on Windowsmajor_version_zero, multi-line messages, custombump_patternfallback path)Documentation Changes
uv run poe doclocally to ensure the documentation pages render correctlyAdditional Context
v4.10.0. This iteration was rebuilt fresh on top of currentmaster(4d99415a).Prereleaseenum change for incrementality.commitizen.defaults.MAJOR/MINOR/PATCHwere stored as bare strings instead of(value, replacement)tuples —from commitizen.defaults import MAJORwould have crashed withValueError. Fixed with regression test.bump_map_major_version_zerowas incorrectly required at construction time, breaking plugins that only definedbump_pattern+bump_map. Fixed by making it optional and validating lazily, matching master's behaviour exactly. Regression tests added.