feat(bump_rule): add BumpRule, VersionIncrement enum, ConventionalCommitBumpRule#1518
feat(bump_rule): add BumpRule, VersionIncrement enum, ConventionalCommitBumpRule#1518bearomorphism wants to merge 1 commit intocommitizen-tools:masterfrom
Conversation
bb305ad to
8a6c84f
Compare
Codecov 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
8dd8d42
Compare
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.
| 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
83c02fe to
650c720
Compare
bb61b44 to
9cacfcb
Compare
|
Can we do squash rebase on this PR when it is ready for merge? |
yep, I can do that |
3cf6689 to
6d0aa11
Compare
|
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
972d9f5
Compare
There was a problem hiding this comment.
Core feature change
|
We can get back to this PR after #1598 |
9914feb to
9644e1a
Compare
|
@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. |
|
(I've resolved merge conflicts for several times for this PR) |
|
This would fall into |
|
A lot of conflicts... I will probably create another branch and do the change again... |
59fc269 to
4271c36
Compare
4271c36 to
16ac67d
Compare
|
will do a human review later... |
…mitBumpRule Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
16ac67d to
07a03cf
Compare
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.