Skip to content

Commit 1e56d63

Browse files
committed
feat(bump): add commit filter pattern
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> #2075
1 parent 4184174 commit 1e56d63

15 files changed

Lines changed: 240 additions & 9 deletions

File tree

commitizen/bump.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,17 @@ def find_increment(
6262
return cast("Increment", increment)
6363

6464

65+
def filter_commits(commits: list[GitCommit], pattern: str) -> list[GitCommit]:
66+
"""Filter commits before applying bump-pattern matching.
67+
68+
This keeps the existing line-by-line ``bump_pattern`` behavior intact while
69+
allowing repository-specific configuration to exclude unrelated commits from
70+
the bump calculation entirely.
71+
"""
72+
select_pattern = re.compile(pattern)
73+
return [commit for commit in commits if select_pattern.match(commit.message)]
74+
75+
6576
def update_version_in_files(
6677
current_version: str,
6778
new_version: str,

commitizen/commands/bump.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import questionary
88

9-
from commitizen import bump, factory, git, hooks, out
9+
from commitizen import bump, defaults, factory, git, hooks, out
1010
from commitizen.changelog_formats import get_changelog_format
1111
from commitizen.commands.changelog import Changelog
1212
from commitizen.defaults import Settings
@@ -158,7 +158,18 @@ def _find_increment(self, commits: list[git.GitCommit]) -> Increment | None:
158158
raise NoPatternMapError(
159159
f"'{self.config.settings['name']}' rule does not support bump"
160160
)
161-
return bump.find_increment(commits, regex=bump_pattern, increments_map=bump_map)
161+
default_filter_pattern = defaults.DEFAULT_SETTINGS["bump_commit_filter_pattern"]
162+
bump_commit_filter_pattern = self.cz.bump_commit_filter_pattern
163+
if bump_commit_filter_pattern in (None, default_filter_pattern):
164+
bump_commit_filter_pattern = self.config.settings.get(
165+
"bump_commit_filter_pattern"
166+
)
167+
if bump_commit_filter_pattern is None:
168+
bump_commit_filter_pattern = default_filter_pattern
169+
filtered_commits = bump.filter_commits(commits, bump_commit_filter_pattern)
170+
return bump.find_increment(
171+
filtered_commits, regex=bump_pattern, increments_map=bump_map
172+
)
162173

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

commitizen/commands/version.py

Lines changed: 11 additions & 2 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 bump, defaults, factory, git, out
88
from commitizen.__version__ import __version__
99
from commitizen.config import BaseConfig
1010
from commitizen.exceptions import (
@@ -180,8 +180,17 @@ def _get_next_git_version(
180180
raise NoPatternMapError(
181181
f"'{self.config.settings['name']}' rule does not support bump"
182182
)
183+
default_filter_pattern = defaults.DEFAULT_SETTINGS["bump_commit_filter_pattern"]
184+
bump_commit_filter_pattern = self.cz.bump_commit_filter_pattern
185+
if bump_commit_filter_pattern in (None, default_filter_pattern):
186+
bump_commit_filter_pattern = self.config.settings.get(
187+
"bump_commit_filter_pattern"
188+
)
189+
if bump_commit_filter_pattern is None:
190+
bump_commit_filter_pattern = default_filter_pattern
191+
filtered_commits = bump.filter_commits(commits, bump_commit_filter_pattern)
183192
increment = bump.find_increment(
184-
commits, regex=bump_pattern, increments_map=bump_map
193+
filtered_commits, regex=bump_pattern, increments_map=bump_map
185194
)
186195

187196
# TODO: Consider adding all the parameters `.bump` supports:

commitizen/cz/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class ValidationResult(NamedTuple):
3636

3737

3838
class BaseCommitizen(metaclass=ABCMeta):
39+
bump_commit_filter_pattern: str | None = None
3940
bump_pattern: str | None = None
4041
bump_map: dict[str, str] | None = None
4142
bump_map_major_version_zero: dict[str, str] | None = None

commitizen/cz/conventional_commits/conventional_commits.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class ConventionalCommitsAnswers(TypedDict):
3131

3232

3333
class ConventionalCommitsCz(BaseCommitizen):
34+
bump_commit_filter_pattern = defaults.DEFAULT_SETTINGS["bump_commit_filter_pattern"]
3435
bump_pattern = defaults.BUMP_PATTERN
3536
bump_map = defaults.BUMP_MAP
3637
bump_map_major_version_zero = defaults.BUMP_MAP_MAJOR_VERSION_ZERO

commitizen/cz/customize/customize.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def _derive_major_version_zero(
4444

4545

4646
class CustomizeCommitsCz(BaseCommitizen):
47+
bump_commit_filter_pattern = defaults.DEFAULT_SETTINGS["bump_commit_filter_pattern"]
4748
bump_pattern = defaults.BUMP_PATTERN
4849
bump_map = defaults.BUMP_MAP
4950
bump_map_major_version_zero = defaults.BUMP_MAP_MAJOR_VERSION_ZERO
@@ -57,6 +58,7 @@ def __init__(self, config: BaseConfig) -> None:
5758
self.custom_settings = self.config.settings["customize"]
5859

5960
for attr_name in [
61+
"bump_commit_filter_pattern",
6062
"bump_pattern",
6163
"bump_map",
6264
"bump_map_major_version_zero",

commitizen/defaults.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313

1414
class CzSettings(TypedDict, total=False):
15+
bump_commit_filter_pattern: str
1516
bump_pattern: str
1617
bump_map: OrderedDict[str, str]
1718
bump_map_major_version_zero: OrderedDict[str, str]
@@ -34,6 +35,7 @@ class Settings(TypedDict, total=False):
3435
allowed_prefixes: list[str]
3536
always_signoff: bool
3637
annotated_tag: bool
38+
bump_commit_filter_pattern: str
3739
bump_message: str | None
3840
change_type_map: dict[str, str]
3941
changelog_file: str
@@ -88,6 +90,7 @@ class Settings(TypedDict, total=False):
8890
"tag_format": "$version", # example v$version
8991
"legacy_tag_formats": [],
9092
"ignored_tag_formats": [],
93+
"bump_commit_filter_pattern": r".*",
9194
"bump_message": None, # bumped v$current_version to $new_version
9295
"retry_after_failure": False,
9396
"allow_abort": False,

docs/config/bump.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,22 @@ When set to `true`, `cz bump` is equivalent to `cz bump --annotated-tag`.
1111
annotated_tag = true
1212
```
1313

14+
## `bump_commit_filter_pattern`
15+
16+
- Type: `str`
17+
- Default: `".*"`
18+
19+
Regular expression used to decide which commits `cz bump` should consider
20+
before applying the commit rule's `bump_pattern`.
21+
22+
This is useful in monorepos where a component should ignore commits that belong
23+
to other applications or packages.
24+
25+
```toml title="pyproject.toml"
26+
[tool.commitizen]
27+
bump_commit_filter_pattern = "^(feat|fix)\\(library-b\\)(!)?:"
28+
```
29+
1430
## `bump_message`
1531

1632
Template used to specify the commit message generated when bumping.

docs/config/configuration_file.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ All formats support the same configuration options. Choose the format that best
6868
update_changelog_on_bump = true
6969
changelog_file = "CHANGELOG.md"
7070
changelog_incremental = false
71+
bump_commit_filter_pattern = ".*"
7172
bump_message = "bump: version $current_version → $new_version"
7273
gpg_sign = false
7374
annotated_tag = false
@@ -126,6 +127,7 @@ All formats support the same configuration options. Choose the format that best
126127
"update_changelog_on_bump": true,
127128
"changelog_file": "CHANGELOG.md",
128129
"changelog_incremental": false,
130+
"bump_commit_filter_pattern": ".*",
129131
"bump_message": "bump: version $current_version → $new_version",
130132
"gpg_sign": false,
131133
"annotated_tag": false,
@@ -182,6 +184,7 @@ All formats support the same configuration options. Choose the format that best
182184
update_changelog_on_bump: true
183185
changelog_file: CHANGELOG.md
184186
changelog_incremental: false
187+
bump_commit_filter_pattern: ".*"
185188
bump_message: "bump: version $current_version → $new_version"
186189
gpg_sign: false
187190
annotated_tag: false
@@ -235,7 +238,7 @@ Key configuration categories include:
235238
- **Version Management**: `version`, `version_provider`, `version_scheme`, `version_files`
236239
- **Tagging**: `tag_format`, `legacy_tag_formats`, `ignored_tag_formats`, `gpg_sign`, `annotated_tag`
237240
- **Changelog**: `changelog_file`, `changelog_format`, `changelog_incremental`, `update_changelog_on_bump`
238-
- **Bumping**: `bump_message`, `major_version_zero`, `prerelease_offset`, `pre_bump_hooks`, `post_bump_hooks`
241+
- **Bumping**: `bump_commit_filter_pattern`, `bump_message`, `major_version_zero`, `prerelease_offset`, `pre_bump_hooks`, `post_bump_hooks`
239242
- **Commit Validation**: `allowed_prefixes`, `message_length_limit`, `allow_abort`, `retry_after_failure`
240243
- **Customization**: `customize`, `style`, `use_shortcuts`, `template`, `extras`
241244

docs/tutorials/monorepo_guidance.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Here is a step-by-step example using two libraries, `library-b` and `library-z`:
3434
version = "0.0.0"
3535
tag_format = "${version}-library-b" # the component name can be a prefix or suffix with or without a separator
3636
ignored_tag_formats = ["${version}-library-*"] # Avoid noise from other tags
37+
bump_commit_filter_pattern = "^(feat|fix)\\(library-b\\)(!)?:"
3738
update_changelog_on_bump = true
3839
```
3940
@@ -44,6 +45,7 @@ Here is a step-by-step example using two libraries, `library-b` and `library-z`:
4445
version = "0.0.0"
4546
tag_format = "${version}-library-z"
4647
ignored_tag_formats = ["${version}-library-*"] # Avoid noise from other tags
48+
bump_commit_filter_pattern = "^(feat|fix)\\(library-z\\)(!)?:"
4749
update_changelog_on_bump = true
4850
```
4951
@@ -55,7 +57,7 @@ Here is a step-by-step example using two libraries, `library-b` and `library-z`:
5557
```
5658
5759
58-
## Changelog per component
60+
## Bump and changelog per component
5961
6062
To filter the correct commits for each component, you'll need to define a strategy.
6163
@@ -70,8 +72,9 @@ For example:
7072
7173
### Example with scope in conventional commits
7274
73-
In this example, we want `library-b`'s changelog to only include commits that use the `library-b` scope.
74-
To achieve this, we configure Commitizen to match only commit messages with that scope.
75+
In this example, we want `library-b`'s bump calculation and changelog to only
76+
include commits that use the `library-b` scope. To achieve this, we configure
77+
Commitizen to match only commit messages with that scope.
7578
7679
Here is an example configuration for `library-b`:
7780

0 commit comments

Comments
 (0)