Skip to content

Commit 67dc6d5

Browse files
committed
refactor(bump): replace find_increment with VersionIncrement max
1 parent 642b8be commit 67dc6d5

6 files changed

Lines changed: 266 additions & 184 deletions

File tree

‎commitizen/bump.py‎

Lines changed: 4 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,18 @@
22

33
import os
44
import re
5-
from collections import OrderedDict
65
from glob import iglob
7-
from logging import getLogger
86
from string import Template
9-
from typing import TYPE_CHECKING, cast
7+
from typing import TYPE_CHECKING
108

11-
from commitizen.defaults import BUMP_MESSAGE, MAJOR, MINOR, PATCH
9+
from commitizen.defaults import BUMP_MESSAGE
1210
from commitizen.exceptions import CurrentVersionNotFoundError
13-
from commitizen.git import GitCommit, smart_open
11+
from commitizen.git import smart_open
1412

1513
if TYPE_CHECKING:
1614
from collections.abc import Generator, Iterable
1715

18-
from commitizen.version_schemes import Increment, VersionProtocol
19-
20-
VERSION_TYPES = [None, PATCH, MINOR, MAJOR]
21-
22-
logger = getLogger("commitizen")
23-
24-
25-
def find_increment(
26-
commits: list[GitCommit], regex: str, increments_map: dict | OrderedDict
27-
) -> Increment | None:
28-
if isinstance(increments_map, dict):
29-
increments_map = OrderedDict(increments_map)
30-
31-
# Most important cases are major and minor.
32-
# Everything else will be considered patch.
33-
select_pattern = re.compile(regex)
34-
increment: str | None = None
35-
36-
for commit in commits:
37-
for message in commit.message.split("\n"):
38-
result = select_pattern.search(message)
39-
40-
if result:
41-
found_keyword = result.group(1)
42-
new_increment = None
43-
for match_pattern in increments_map.keys():
44-
if re.match(match_pattern, found_keyword):
45-
new_increment = increments_map[match_pattern]
46-
break
47-
48-
if new_increment is None:
49-
logger.debug(
50-
f"no increment needed for '{found_keyword}' in '{message}'"
51-
)
52-
53-
if VERSION_TYPES.index(increment) < VERSION_TYPES.index(new_increment):
54-
logger.debug(
55-
f"increment detected is '{new_increment}' due to '{found_keyword}' in '{message}'"
56-
)
57-
increment = new_increment
58-
59-
if increment == MAJOR:
60-
break
61-
62-
return cast("Increment", increment)
16+
from commitizen.version_schemes import VersionProtocol
6317

6418

6519
def update_version_in_files(

‎commitizen/commands/bump.py‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
)
2525
from commitizen.providers import get_provider
2626
from commitizen.tags import TagRules
27+
from commitizen.version_increment import VersionIncrement
2728
from commitizen.version_schemes import (
2829
Increment,
2930
InvalidVersion,
@@ -145,8 +146,8 @@ def _is_initial_tag(
145146
return bool(questionary.confirm("Is this the first tag created?").ask())
146147

147148
def _find_increment(self, commits: list[git.GitCommit]) -> Increment | None:
149+
"""Determine the highest configured increment across candidate commits."""
148150
# Update the bump map to ensure major version doesn't increment.
149-
# self.cz.bump_map = defaults.bump_map_major_version_zero
150151
bump_map = (
151152
self.cz.bump_map_major_version_zero
152153
if self.bump_settings["major_version_zero"]
@@ -158,11 +159,15 @@ def _find_increment(self, commits: list[git.GitCommit]) -> Increment | None:
158159
raise NoPatternMapError(
159160
f"'{self.config.settings['name']}' rule does not support bump"
160161
)
161-
return bump.find_increment(
162-
self.cz.filter_commits_before_bump(commits),
163-
regex=bump_pattern,
164-
increments_map=bump_map,
162+
163+
increment = VersionIncrement.get_highest_by_messages(
164+
(commit.message for commit in self.cz.filter_commits_before_bump(commits)),
165+
bump_pattern,
166+
bump_map,
165167
)
168+
if increment == VersionIncrement.NONE:
169+
return None
170+
return cast("Increment", str(increment))
166171

167172
def _validate_arguments(self, current_version: VersionProtocol) -> None:
168173
errors: list[str] = []

‎commitizen/commands/version.py‎

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from packaging.version import InvalidVersion
66

7-
from commitizen import bump, factory, git, out
7+
from commitizen import factory, git, out
88
from commitizen.__version__ import __version__
99
from commitizen.config import BaseConfig
1010
from commitizen.exceptions import (
@@ -180,11 +180,20 @@ def _get_next_git_version(
180180
raise NoPatternMapError(
181181
f"'{self.config.settings['name']}' rule does not support bump"
182182
)
183-
increment = bump.find_increment(
184-
self.cz.filter_commits_before_bump(commits),
185-
regex=bump_pattern,
186-
increments_map=bump_map,
183+
next_increment = VersionIncrement.get_highest_by_messages(
184+
(commit.message for commit in self.cz.filter_commits_before_bump(commits)),
185+
bump_pattern,
186+
bump_map,
187187
)
188+
increment: Increment | None
189+
if next_increment == VersionIncrement.NONE:
190+
increment = None
191+
elif next_increment == VersionIncrement.PATCH:
192+
increment = "PATCH"
193+
elif next_increment == VersionIncrement.MINOR:
194+
increment = "MINOR"
195+
else:
196+
increment = "MAJOR"
188197

189198
# TODO: Consider adding all the parameters `.bump` supports:
190199
# prerelease, prerelease_offset,exact_increment, etc..

‎commitizen/version_increment.py‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from __future__ import annotations
22

3+
import re
34
from enum import IntEnum
5+
from typing import TYPE_CHECKING
6+
7+
if TYPE_CHECKING:
8+
from collections.abc import Iterable, Mapping
49

510

611
class VersionIncrement(IntEnum):
@@ -21,13 +26,64 @@ class VersionIncrement(IntEnum):
2126
MAJOR = 3
2227

2328
def __str__(self) -> str:
29+
"""Return the legacy string representation used by existing callers."""
2430
return self.name
2531

2632
@classmethod
2733
def from_value(cls, value: object) -> VersionIncrement:
34+
"""Convert a possibly-invalid external value into a known increment."""
2835
if not isinstance(value, str):
2936
return VersionIncrement.NONE
3037
try:
3138
return cls[value]
3239
except KeyError:
3340
return VersionIncrement.NONE
41+
42+
@classmethod
43+
def from_match(
44+
cls, matched_text: str, increments_map: Mapping[str, object]
45+
) -> VersionIncrement:
46+
"""Resolve one extracted bump token against a configured bump map.
47+
48+
The first regular-expression key that matches wins, preserving the
49+
current user-visible behavior of ``bump_map`` ordering.
50+
"""
51+
for match_pattern, increment in increments_map.items():
52+
if re.match(match_pattern, matched_text):
53+
return cls.from_value(increment)
54+
return cls.NONE
55+
56+
@classmethod
57+
def from_message(
58+
cls, message: str, regex: str, increments_map: Mapping[str, object]
59+
) -> VersionIncrement:
60+
"""Compute the highest increment contributed by one commit message.
61+
62+
Commitizen historically evaluates each line of the full commit message
63+
against ``bump_pattern`` and then keeps the highest resulting bump.
64+
This method preserves that behavior while returning a comparable enum.
65+
"""
66+
select_pattern = re.compile(regex)
67+
increments = []
68+
69+
for line in message.split("\n"):
70+
result = select_pattern.search(line)
71+
if result:
72+
increments.append(cls.from_match(result.group(1), increments_map))
73+
74+
return max(increments, default=cls.NONE)
75+
76+
@classmethod
77+
def get_highest_by_messages(
78+
cls, messages: Iterable[str], regex: str, increments_map: Mapping[str, object]
79+
) -> VersionIncrement:
80+
"""Compute the highest increment across many commit messages.
81+
82+
An empty iterable yields ``NONE`` so callers can preserve the existing
83+
"no increment" behavior explicitly instead of relying on exceptions from
84+
``max()``.
85+
"""
86+
return max(
87+
(cls.from_message(message, regex, increments_map) for message in messages),
88+
default=cls.NONE,
89+
)

‎tests/test_bump_find_increment.py‎

Lines changed: 0 additions & 124 deletions
This file was deleted.

0 commit comments

Comments
 (0)