commitizen 4.8.3__tar.gz → 4.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {commitizen-4.8.3 → commitizen-4.9.0}/PKG-INFO +5 -4
- commitizen-4.9.0/commitizen/__version__.py +1 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/changelog.py +81 -84
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cli.py +22 -19
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/bump.py +22 -39
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/changelog.py +27 -25
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/check.py +21 -13
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/init.py +144 -133
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/version.py +17 -15
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/defaults.py +5 -3
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/exceptions.py +11 -4
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/git.py +10 -2
- commitizen-4.9.0/commitizen/providers/cargo_provider.py +94 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/providers/commitizen_provider.py +4 -1
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/providers/scm_provider.py +2 -4
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/tags.py +11 -9
- {commitizen-4.8.3 → commitizen-4.9.0}/docs/README.md +2 -1
- {commitizen-4.8.3 → commitizen-4.9.0}/pyproject.toml +6 -5
- commitizen-4.8.3/commitizen/__version__.py +0 -1
- commitizen-4.8.3/commitizen/providers/cargo_provider.py +0 -57
- {commitizen-4.8.3 → commitizen-4.9.0}/LICENSE +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/__init__.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/__main__.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/bump.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/changelog_formats/__init__.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/changelog_formats/asciidoc.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/changelog_formats/base.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/changelog_formats/markdown.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/changelog_formats/restructuredtext.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/changelog_formats/textile.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cmd.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/__init__.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/commit.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/example.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/info.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/list_cz.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/commands/schema.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/config/__init__.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/config/base_config.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/config/json_config.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/config/toml_config.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/config/yaml_config.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/__init__.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/base.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/conventional_commits/__init__.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/conventional_commits/conventional_commits.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/conventional_commits/conventional_commits_info.txt +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/customize/__init__.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/customize/customize.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/customize/customize_info.txt +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/exceptions.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/jira/__init__.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/jira/jira.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/jira/jira_info.txt +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/cz/utils.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/factory.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/hooks.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/out.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/providers/__init__.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/providers/base_provider.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/providers/composer_provider.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/providers/npm_provider.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/providers/pep621_provider.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/providers/poetry_provider.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/providers/uv_provider.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/py.typed +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/question.py +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/templates/CHANGELOG.adoc.j2 +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/templates/CHANGELOG.md.j2 +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/templates/CHANGELOG.rst.j2 +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/templates/CHANGELOG.textile.j2 +0 -0
- {commitizen-4.8.3 → commitizen-4.9.0}/commitizen/version_schemes.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: commitizen
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.9.0
|
|
4
4
|
Summary: Python commitizen client tool
|
|
5
5
|
License: MIT License
|
|
6
6
|
|
|
@@ -47,10 +47,10 @@ Requires-Dist: argcomplete (>=1.12.1,<3.7)
|
|
|
47
47
|
Requires-Dist: charset-normalizer (>=2.1.0,<4)
|
|
48
48
|
Requires-Dist: colorama (>=0.4.1,<1.0)
|
|
49
49
|
Requires-Dist: decli (>=0.6.0,<1.0)
|
|
50
|
-
Requires-Dist: importlib-metadata (>=8.0.0
|
|
51
|
-
Requires-Dist: importlib-metadata (>=8.0.0,<9.0.0) ; python_version != "3.9"
|
|
50
|
+
Requires-Dist: importlib-metadata (>=8.0.0,<8.7.0) ; python_version < "3.10"
|
|
52
51
|
Requires-Dist: jinja2 (>=2.10.3)
|
|
53
52
|
Requires-Dist: packaging (>=19)
|
|
53
|
+
Requires-Dist: prompt_toolkit (!=3.0.52)
|
|
54
54
|
Requires-Dist: pyyaml (>=3.08)
|
|
55
55
|
Requires-Dist: questionary (>=2.0,<3.0)
|
|
56
56
|
Requires-Dist: termcolor (>=1.1.0,<4.0.0)
|
|
@@ -128,6 +128,7 @@ Before installing Commitizen, ensure you have:
|
|
|
128
128
|
#### Global Installation (Recommended)
|
|
129
129
|
|
|
130
130
|
The recommended way to install Commitizen is using [`pipx`](https://pipx.pypa.io/) or [`uv`](https://docs.astral.sh/uv/), which ensures a clean, isolated installation:
|
|
131
|
+
|
|
131
132
|
**Using pipx:**
|
|
132
133
|
```bash
|
|
133
134
|
# Install Commitizen
|
|
@@ -176,7 +177,7 @@ poetry add commitizen --dev
|
|
|
176
177
|
|
|
177
178
|
**Using uv:**
|
|
178
179
|
```bash
|
|
179
|
-
uv add commitizen
|
|
180
|
+
uv add --dev commitizen
|
|
180
181
|
```
|
|
181
182
|
|
|
182
183
|
**Using pdm:**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "4.9.0"
|
|
@@ -29,11 +29,13 @@ from __future__ import annotations
|
|
|
29
29
|
|
|
30
30
|
import re
|
|
31
31
|
from collections import OrderedDict, defaultdict
|
|
32
|
-
from collections.abc import Generator, Iterable, Mapping, Sequence
|
|
32
|
+
from collections.abc import Generator, Iterable, Mapping, MutableMapping, Sequence
|
|
33
33
|
from dataclasses import dataclass
|
|
34
34
|
from datetime import date
|
|
35
|
+
from itertools import chain
|
|
35
36
|
from typing import TYPE_CHECKING, Any
|
|
36
37
|
|
|
38
|
+
from deprecated import deprecated
|
|
37
39
|
from jinja2 import (
|
|
38
40
|
BaseLoader,
|
|
39
41
|
ChoiceLoader,
|
|
@@ -88,33 +90,32 @@ def generate_tree_from_commits(
|
|
|
88
90
|
pat = re.compile(changelog_pattern)
|
|
89
91
|
map_pat = re.compile(commit_parser, re.MULTILINE)
|
|
90
92
|
body_map_pat = re.compile(commit_parser, re.MULTILINE | re.DOTALL)
|
|
91
|
-
current_tag: GitTag | None = None
|
|
92
93
|
rules = rules or TagRules()
|
|
93
94
|
|
|
94
95
|
# Check if the latest commit is not tagged
|
|
95
|
-
if commits:
|
|
96
|
-
latest_commit = commits[0]
|
|
97
|
-
current_tag = get_commit_tag(latest_commit, tags)
|
|
98
|
-
|
|
99
|
-
current_tag_name: str = unreleased_version or "Unreleased"
|
|
100
|
-
current_tag_date: str = ""
|
|
101
|
-
if unreleased_version is not None:
|
|
102
|
-
current_tag_date = date.today().isoformat()
|
|
103
|
-
if current_tag is not None and current_tag.name:
|
|
104
|
-
current_tag_name = current_tag.name
|
|
105
|
-
current_tag_date = current_tag.date
|
|
106
96
|
|
|
97
|
+
current_tag = get_commit_tag(commits[0], tags) if commits else None
|
|
98
|
+
current_tag_name = unreleased_version or "Unreleased"
|
|
99
|
+
current_tag_date = (
|
|
100
|
+
date.today().isoformat() if unreleased_version is not None else ""
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
used_tags: set[GitTag] = set()
|
|
104
|
+
if current_tag:
|
|
105
|
+
used_tags.add(current_tag)
|
|
106
|
+
if current_tag.name:
|
|
107
|
+
current_tag_name = current_tag.name
|
|
108
|
+
current_tag_date = current_tag.date
|
|
109
|
+
|
|
110
|
+
commit_tag: GitTag | None = None
|
|
107
111
|
changes: dict = defaultdict(list)
|
|
108
|
-
used_tags: list = [current_tag]
|
|
109
112
|
for commit in commits:
|
|
110
|
-
commit_tag = get_commit_tag(commit, tags)
|
|
111
|
-
|
|
112
113
|
if (
|
|
113
|
-
commit_tag
|
|
114
|
+
(commit_tag := get_commit_tag(commit, tags))
|
|
114
115
|
and commit_tag not in used_tags
|
|
115
116
|
and rules.include_in_changelog(commit_tag)
|
|
116
117
|
):
|
|
117
|
-
used_tags.
|
|
118
|
+
used_tags.add(commit_tag)
|
|
118
119
|
release = {
|
|
119
120
|
"version": current_tag_name,
|
|
120
121
|
"date": current_tag_date,
|
|
@@ -127,24 +128,15 @@ def generate_tree_from_commits(
|
|
|
127
128
|
current_tag_date = commit_tag.date
|
|
128
129
|
changes = defaultdict(list)
|
|
129
130
|
|
|
130
|
-
|
|
131
|
-
if not matches:
|
|
131
|
+
if not pat.match(commit.message):
|
|
132
132
|
continue
|
|
133
133
|
|
|
134
|
-
# Process subject from commit message
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
changes,
|
|
141
|
-
change_type_map,
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
# Process body from commit message
|
|
145
|
-
body_parts = commit.body.split("\n\n")
|
|
146
|
-
for body_part in body_parts:
|
|
147
|
-
if message := body_map_pat.match(body_part):
|
|
134
|
+
# Process subject and body from commit message
|
|
135
|
+
for message in chain(
|
|
136
|
+
[map_pat.match(commit.message)],
|
|
137
|
+
(body_map_pat.match(block) for block in commit.body.split("\n\n")),
|
|
138
|
+
):
|
|
139
|
+
if message:
|
|
148
140
|
process_commit_message(
|
|
149
141
|
changelog_message_builder_hook,
|
|
150
142
|
message,
|
|
@@ -167,8 +159,8 @@ def process_commit_message(
|
|
|
167
159
|
hook: MessageBuilderHook | None,
|
|
168
160
|
parsed: re.Match[str],
|
|
169
161
|
commit: GitCommit,
|
|
170
|
-
|
|
171
|
-
change_type_map:
|
|
162
|
+
ref_changes: MutableMapping[str | None, list],
|
|
163
|
+
change_type_map: Mapping[str, str] | None = None,
|
|
172
164
|
) -> None:
|
|
173
165
|
message: dict[str, Any] = {
|
|
174
166
|
"sha1": commit.rev,
|
|
@@ -178,13 +170,16 @@ def process_commit_message(
|
|
|
178
170
|
**parsed.groupdict(),
|
|
179
171
|
}
|
|
180
172
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
173
|
+
processed_msg = hook(message, commit) if hook else message
|
|
174
|
+
if not processed_msg:
|
|
175
|
+
return
|
|
176
|
+
|
|
177
|
+
messages = [processed_msg] if isinstance(processed_msg, dict) else processed_msg
|
|
178
|
+
for msg in messages:
|
|
179
|
+
change_type = msg.pop("change_type", None)
|
|
180
|
+
if change_type_map:
|
|
181
|
+
change_type = change_type_map.get(change_type, change_type)
|
|
182
|
+
ref_changes[change_type].append(msg)
|
|
188
183
|
|
|
189
184
|
|
|
190
185
|
def generate_ordered_changelog_tree(
|
|
@@ -251,6 +246,7 @@ def incremental_build(
|
|
|
251
246
|
unreleased_start = metadata.unreleased_start
|
|
252
247
|
unreleased_end = metadata.unreleased_end
|
|
253
248
|
latest_version_position = metadata.latest_version_position
|
|
249
|
+
|
|
254
250
|
skip = False
|
|
255
251
|
output_lines: list[str] = []
|
|
256
252
|
for index, line in enumerate(lines):
|
|
@@ -260,9 +256,7 @@ def incremental_build(
|
|
|
260
256
|
skip = False
|
|
261
257
|
if (
|
|
262
258
|
latest_version_position is None
|
|
263
|
-
or
|
|
264
|
-
and isinstance(unreleased_end, int)
|
|
265
|
-
and latest_version_position > unreleased_end
|
|
259
|
+
or latest_version_position > unreleased_end
|
|
266
260
|
):
|
|
267
261
|
continue
|
|
268
262
|
|
|
@@ -271,16 +265,32 @@ def incremental_build(
|
|
|
271
265
|
|
|
272
266
|
if index == latest_version_position:
|
|
273
267
|
output_lines.extend([new_content, "\n"])
|
|
274
|
-
|
|
275
268
|
output_lines.append(line)
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
269
|
+
|
|
270
|
+
if latest_version_position is not None:
|
|
271
|
+
return output_lines
|
|
272
|
+
|
|
273
|
+
if output_lines and output_lines[-1].strip():
|
|
274
|
+
# Ensure at least one blank line between existing and new content.
|
|
275
|
+
output_lines.append("\n")
|
|
276
|
+
output_lines.append(new_content)
|
|
281
277
|
return output_lines
|
|
282
278
|
|
|
283
279
|
|
|
280
|
+
def get_next_tag_name_after_version(tags: Iterable[GitTag], version: str) -> str | None:
|
|
281
|
+
it = iter(tag.name for tag in tags)
|
|
282
|
+
for name in it:
|
|
283
|
+
if name == version:
|
|
284
|
+
return next(it, None)
|
|
285
|
+
|
|
286
|
+
raise NoCommitsFoundError(f"Could not find a valid revision range. {version=}")
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
@deprecated(
|
|
290
|
+
reason="This function is unused and will be removed in v5",
|
|
291
|
+
version="5.0.0",
|
|
292
|
+
category=DeprecationWarning,
|
|
293
|
+
)
|
|
284
294
|
def get_smart_tag_range(
|
|
285
295
|
tags: Sequence[GitTag], newest: str, oldest: str | None = None
|
|
286
296
|
) -> list[GitTag]:
|
|
@@ -308,7 +318,7 @@ def get_smart_tag_range(
|
|
|
308
318
|
|
|
309
319
|
|
|
310
320
|
def get_oldest_and_newest_rev(
|
|
311
|
-
tags:
|
|
321
|
+
tags: Iterable[GitTag],
|
|
312
322
|
version: str,
|
|
313
323
|
rules: TagRules,
|
|
314
324
|
) -> tuple[str | None, str]:
|
|
@@ -318,39 +328,26 @@ def get_oldest_and_newest_rev(
|
|
|
318
328
|
- `0.1.0..0.4.0`: as a range
|
|
319
329
|
- `0.3.0`: as a single version
|
|
320
330
|
"""
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
331
|
+
oldest_version, sep, newest_version = version.partition("..")
|
|
332
|
+
if not sep:
|
|
333
|
+
newest_version = version
|
|
334
|
+
oldest_version = ""
|
|
335
|
+
|
|
336
|
+
def get_tag_name(v: str) -> str:
|
|
337
|
+
if tag := rules.find_tag_for(tags, v):
|
|
338
|
+
return tag.name
|
|
328
339
|
raise NoCommitsFoundError("Could not find a valid revision range.")
|
|
329
340
|
|
|
330
|
-
|
|
331
|
-
oldest_tag_name = None
|
|
332
|
-
if oldest:
|
|
333
|
-
if not (oldest_tag := rules.find_tag_for(tags, oldest)):
|
|
334
|
-
raise NoCommitsFoundError("Could not find a valid revision range.")
|
|
335
|
-
oldest_tag_name = oldest_tag.name
|
|
341
|
+
newest_tag_name = get_tag_name(newest_version)
|
|
342
|
+
oldest_tag_name = get_tag_name(oldest_version) if oldest_version else None
|
|
336
343
|
|
|
337
|
-
|
|
338
|
-
tags,
|
|
344
|
+
oldest_rev = get_next_tag_name_after_version(
|
|
345
|
+
tags, oldest_tag_name or newest_tag_name
|
|
339
346
|
)
|
|
340
|
-
if not tags_range:
|
|
341
|
-
raise NoCommitsFoundError("Could not find a valid revision range.")
|
|
342
|
-
|
|
343
|
-
oldest_rev: str | None = tags_range[-1].name
|
|
344
|
-
newest_rev = newest_tag.name
|
|
345
|
-
|
|
346
|
-
# check if it's the first tag created
|
|
347
|
-
# and it's also being requested as part of the range
|
|
348
|
-
if oldest_rev == tags[-1].name and oldest_rev == oldest_tag_name:
|
|
349
|
-
return None, newest_rev
|
|
350
|
-
|
|
351
|
-
# when they are the same, and it's also the
|
|
352
|
-
# first tag created
|
|
353
|
-
if oldest_rev == newest_rev:
|
|
354
|
-
return None, newest_rev
|
|
355
347
|
|
|
356
|
-
|
|
348
|
+
# Return None for oldest_rev if:
|
|
349
|
+
# 1. The oldest tag is the last tag in the list and matches the requested oldest tag
|
|
350
|
+
# 2. The oldest and the newest tag are the same
|
|
351
|
+
if oldest_rev == newest_tag_name:
|
|
352
|
+
return None, newest_tag_name
|
|
353
|
+
return oldest_rev, newest_tag_name
|
|
@@ -52,16 +52,13 @@ class ParseKwargs(argparse.Action):
|
|
|
52
52
|
) -> None:
|
|
53
53
|
if not isinstance(values, str):
|
|
54
54
|
return
|
|
55
|
-
|
|
55
|
+
|
|
56
|
+
key, sep, value = values.partition("=")
|
|
57
|
+
if not key or not sep:
|
|
56
58
|
raise InvalidCommandArgumentError(
|
|
57
59
|
f"Option {option_string} expect a key=value format"
|
|
58
60
|
)
|
|
59
61
|
kwargs = getattr(namespace, self.dest, None) or {}
|
|
60
|
-
key, value = values.split("=", 1)
|
|
61
|
-
if not key:
|
|
62
|
-
raise InvalidCommandArgumentError(
|
|
63
|
-
f"Option {option_string} expect a key=value format"
|
|
64
|
-
)
|
|
65
62
|
kwargs[key] = value.strip("'\"")
|
|
66
63
|
setattr(namespace, self.dest, kwargs)
|
|
67
64
|
|
|
@@ -474,6 +471,13 @@ data = {
|
|
|
474
471
|
"help": "a range of git rev to check. e.g, master..HEAD",
|
|
475
472
|
"exclusive_group": "group1",
|
|
476
473
|
},
|
|
474
|
+
{
|
|
475
|
+
"name": ["-d", "--use-default-range"],
|
|
476
|
+
"action": "store_true",
|
|
477
|
+
"default": False,
|
|
478
|
+
"help": "check from the default branch to HEAD. e.g, refs/remotes/origin/master..HEAD",
|
|
479
|
+
"exclusive_group": "group1",
|
|
480
|
+
},
|
|
477
481
|
{
|
|
478
482
|
"name": ["-m", "--message"],
|
|
479
483
|
"help": "commit message that needs to be checked",
|
|
@@ -583,20 +587,19 @@ def parse_no_raise(comma_separated_no_raise: str) -> list[int]:
|
|
|
583
587
|
Receives digits and strings and outputs the parsed integer which
|
|
584
588
|
represents the exit code found in exceptions.
|
|
585
589
|
"""
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
for item in no_raise_items:
|
|
589
|
-
if item.isdecimal():
|
|
590
|
-
no_raise_codes.append(int(item))
|
|
591
|
-
continue
|
|
590
|
+
|
|
591
|
+
def exit_code_from_str_or_skip(s: str) -> ExitCode | None:
|
|
592
592
|
try:
|
|
593
|
-
|
|
594
|
-
except KeyError:
|
|
595
|
-
out.warn(f"WARN: no_raise
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
593
|
+
return ExitCode.from_str(s)
|
|
594
|
+
except (KeyError, ValueError):
|
|
595
|
+
out.warn(f"WARN: no_raise value `{s}` is not a valid exit code. Skipping.")
|
|
596
|
+
return None
|
|
597
|
+
|
|
598
|
+
return [
|
|
599
|
+
code.value
|
|
600
|
+
for s in comma_separated_no_raise.split(",")
|
|
601
|
+
if (code := exit_code_from_str_or_skip(s)) is not None
|
|
602
|
+
]
|
|
600
603
|
|
|
601
604
|
|
|
602
605
|
if TYPE_CHECKING:
|
|
@@ -23,7 +23,6 @@ from commitizen.exceptions import (
|
|
|
23
23
|
NoPatternMapError,
|
|
24
24
|
NotAGitProjectError,
|
|
25
25
|
NotAllowed,
|
|
26
|
-
NoVersionSpecifiedError,
|
|
27
26
|
)
|
|
28
27
|
from commitizen.providers import get_provider
|
|
29
28
|
from commitizen.tags import TagRules
|
|
@@ -163,11 +162,7 @@ class Bump:
|
|
|
163
162
|
def __call__(self) -> None:
|
|
164
163
|
"""Steps executed to bump."""
|
|
165
164
|
provider = get_provider(self.config)
|
|
166
|
-
|
|
167
|
-
try:
|
|
168
|
-
current_version = self.scheme(provider.get_version())
|
|
169
|
-
except TypeError:
|
|
170
|
-
raise NoVersionSpecifiedError()
|
|
165
|
+
current_version = self.scheme(provider.get_version())
|
|
171
166
|
|
|
172
167
|
increment = self.arguments["increment"]
|
|
173
168
|
prerelease = self.arguments["prerelease"]
|
|
@@ -177,36 +172,22 @@ class Bump:
|
|
|
177
172
|
build_metadata = self.arguments["build_metadata"]
|
|
178
173
|
get_next = self.arguments["get_next"]
|
|
179
174
|
allow_no_commit = self.arguments["allow_no_commit"]
|
|
175
|
+
major_version_zero = self.arguments["major_version_zero"]
|
|
180
176
|
|
|
181
177
|
if manual_version:
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if build_metadata:
|
|
197
|
-
raise NotAllowed(
|
|
198
|
-
"--build-metadata cannot be combined with MANUAL_VERSION"
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
if self.bump_settings["major_version_zero"]:
|
|
202
|
-
raise NotAllowed(
|
|
203
|
-
"--major-version-zero cannot be combined with MANUAL_VERSION"
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
if get_next:
|
|
207
|
-
raise NotAllowed("--get-next cannot be combined with MANUAL_VERSION")
|
|
208
|
-
|
|
209
|
-
if self.bump_settings["major_version_zero"] and current_version.release[0]:
|
|
178
|
+
for val, option in (
|
|
179
|
+
(increment, "--increment"),
|
|
180
|
+
(prerelease, "--prerelease"),
|
|
181
|
+
(devrelease is not None, "--devrelease"),
|
|
182
|
+
(is_local_version, "--local-version"),
|
|
183
|
+
(build_metadata, "--build-metadata"),
|
|
184
|
+
(major_version_zero, "--major-version-zero"),
|
|
185
|
+
(get_next, "--get-next"),
|
|
186
|
+
):
|
|
187
|
+
if val:
|
|
188
|
+
raise NotAllowed(f"{option} cannot be combined with MANUAL_VERSION")
|
|
189
|
+
|
|
190
|
+
if major_version_zero and current_version.release[0]:
|
|
210
191
|
raise NotAllowed(
|
|
211
192
|
f"--major-version-zero is meaningless for current version {current_version}"
|
|
212
193
|
)
|
|
@@ -215,11 +196,13 @@ class Bump:
|
|
|
215
196
|
raise NotAllowed("--local-version cannot be combined with --build-metadata")
|
|
216
197
|
|
|
217
198
|
if get_next:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
199
|
+
for value, option in (
|
|
200
|
+
(self.changelog_flag, "--changelog"),
|
|
201
|
+
(self.changelog_to_stdout, "--changelog-to-stdout"),
|
|
202
|
+
):
|
|
203
|
+
if value:
|
|
204
|
+
raise NotAllowed(f"{option} cannot be combined with --get-next")
|
|
205
|
+
|
|
223
206
|
# --get-next is a special case, taking precedence over config for 'update_changelog_on_bump'
|
|
224
207
|
self.changelog_config = False
|
|
225
208
|
# Setting dry_run to prevent any unwanted changes to the repo or files
|
|
@@ -11,7 +11,6 @@ from typing import Any, TypedDict, cast
|
|
|
11
11
|
from commitizen import changelog, defaults, factory, git, out
|
|
12
12
|
from commitizen.changelog_formats import get_changelog_format
|
|
13
13
|
from commitizen.config import BaseConfig
|
|
14
|
-
from commitizen.cz.base import ChangelogReleaseHook, MessageBuilderHook
|
|
15
14
|
from commitizen.cz.utils import strip_local_version
|
|
16
15
|
from commitizen.exceptions import (
|
|
17
16
|
DryRunExit,
|
|
@@ -174,28 +173,23 @@ class Changelog:
|
|
|
174
173
|
|
|
175
174
|
changelog_file.write(changelog_out)
|
|
176
175
|
|
|
177
|
-
def _export_template(self) -> None:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
176
|
+
def _export_template(self, dist: str) -> None:
|
|
177
|
+
filename = changelog.get_changelog_template(
|
|
178
|
+
self.cz.template_loader, self.template
|
|
179
|
+
).filename
|
|
180
|
+
if filename is None:
|
|
181
|
+
raise NotAllowed("Template filename is not set")
|
|
182
|
+
|
|
183
|
+
text = Path(filename).read_text()
|
|
184
|
+
Path(dist).write_text(text)
|
|
182
185
|
|
|
183
186
|
def __call__(self) -> None:
|
|
184
187
|
commit_parser = self.cz.commit_parser
|
|
185
188
|
changelog_pattern = self.cz.changelog_pattern
|
|
186
189
|
start_rev = self.start_rev
|
|
187
|
-
unreleased_version = self.unreleased_version
|
|
188
|
-
changelog_meta = changelog.Metadata()
|
|
189
|
-
change_type_map: dict[str, str] | None = self.change_type_map
|
|
190
|
-
changelog_message_builder_hook: MessageBuilderHook | None = (
|
|
191
|
-
self.cz.changelog_message_builder_hook
|
|
192
|
-
)
|
|
193
|
-
changelog_release_hook: ChangelogReleaseHook | None = (
|
|
194
|
-
self.cz.changelog_release_hook
|
|
195
|
-
)
|
|
196
190
|
|
|
197
191
|
if self.export_template_to:
|
|
198
|
-
return self._export_template()
|
|
192
|
+
return self._export_template(self.export_template_to)
|
|
199
193
|
|
|
200
194
|
if not changelog_pattern or not commit_parser:
|
|
201
195
|
raise NoPatternMapError(
|
|
@@ -209,33 +203,37 @@ class Changelog:
|
|
|
209
203
|
assert self.file_name
|
|
210
204
|
|
|
211
205
|
tags = self.tag_rules.get_version_tags(git.get_tags(), warn=True)
|
|
212
|
-
|
|
206
|
+
changelog_meta = changelog.Metadata()
|
|
213
207
|
if self.incremental:
|
|
214
208
|
changelog_meta = self.changelog_format.get_metadata(self.file_name)
|
|
215
209
|
if changelog_meta.latest_version:
|
|
216
210
|
start_rev = self._find_incremental_rev(
|
|
217
211
|
strip_local_version(changelog_meta.latest_version_tag or ""), tags
|
|
218
212
|
)
|
|
213
|
+
|
|
214
|
+
end_rev = ""
|
|
219
215
|
if self.rev_range:
|
|
220
216
|
start_rev, end_rev = changelog.get_oldest_and_newest_rev(
|
|
221
217
|
tags,
|
|
222
218
|
self.rev_range,
|
|
223
219
|
self.tag_rules,
|
|
224
220
|
)
|
|
221
|
+
|
|
225
222
|
commits = git.get_commits(start=start_rev, end=end_rev, args="--topo-order")
|
|
226
223
|
if not commits and (
|
|
227
224
|
self.current_version is None or not self.current_version.is_prerelease
|
|
228
225
|
):
|
|
229
226
|
raise NoCommitsFoundError("No commits found")
|
|
227
|
+
|
|
230
228
|
tree = changelog.generate_tree_from_commits(
|
|
231
229
|
commits,
|
|
232
230
|
tags,
|
|
233
231
|
commit_parser,
|
|
234
232
|
changelog_pattern,
|
|
235
|
-
unreleased_version,
|
|
236
|
-
change_type_map=change_type_map,
|
|
237
|
-
changelog_message_builder_hook=changelog_message_builder_hook,
|
|
238
|
-
changelog_release_hook=changelog_release_hook,
|
|
233
|
+
self.unreleased_version,
|
|
234
|
+
change_type_map=self.change_type_map,
|
|
235
|
+
changelog_message_builder_hook=self.cz.changelog_message_builder_hook,
|
|
236
|
+
changelog_release_hook=self.cz.changelog_release_hook,
|
|
239
237
|
rules=self.tag_rules,
|
|
240
238
|
)
|
|
241
239
|
if self.change_type_order:
|
|
@@ -243,11 +241,15 @@ class Changelog:
|
|
|
243
241
|
tree, self.change_type_order
|
|
244
242
|
)
|
|
245
243
|
|
|
246
|
-
extras = self.cz.template_extras.copy()
|
|
247
|
-
extras.update(self.config.settings["extras"])
|
|
248
|
-
extras.update(self.extras)
|
|
249
244
|
changelog_out = changelog.render_changelog(
|
|
250
|
-
tree,
|
|
245
|
+
tree,
|
|
246
|
+
self.cz.template_loader,
|
|
247
|
+
self.template,
|
|
248
|
+
**{
|
|
249
|
+
**self.cz.template_extras,
|
|
250
|
+
**self.config.settings["extras"],
|
|
251
|
+
**self.extras,
|
|
252
|
+
},
|
|
251
253
|
).lstrip("\n")
|
|
252
254
|
|
|
253
255
|
# Dry_run is executed here to avoid checking and reading the files
|
|
@@ -21,6 +21,7 @@ class CheckArgs(TypedDict, total=False):
|
|
|
21
21
|
message_length_limit: int
|
|
22
22
|
allowed_prefixes: list[str]
|
|
23
23
|
message: str
|
|
24
|
+
use_default_range: bool
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
class Check:
|
|
@@ -40,6 +41,7 @@ class Check:
|
|
|
40
41
|
self.allow_abort = bool(
|
|
41
42
|
arguments.get("allow_abort", config.settings["allow_abort"])
|
|
42
43
|
)
|
|
44
|
+
self.use_default_range = bool(arguments.get("use_default_range"))
|
|
43
45
|
self.max_msg_length = arguments.get("message_length_limit", 0)
|
|
44
46
|
|
|
45
47
|
# we need to distinguish between None and [], which is a valid value
|
|
@@ -50,25 +52,28 @@ class Check:
|
|
|
50
52
|
else config.settings["allowed_prefixes"]
|
|
51
53
|
)
|
|
52
54
|
|
|
53
|
-
self._valid_command_argument()
|
|
54
|
-
|
|
55
|
-
self.config: BaseConfig = config
|
|
56
|
-
self.encoding = config.settings["encoding"]
|
|
57
|
-
self.cz = factory.committer_factory(self.config)
|
|
58
|
-
|
|
59
|
-
def _valid_command_argument(self) -> None:
|
|
60
55
|
num_exclusive_args_provided = sum(
|
|
61
56
|
arg is not None
|
|
62
|
-
for arg in (
|
|
57
|
+
for arg in (
|
|
58
|
+
self.commit_msg_file,
|
|
59
|
+
self.commit_msg,
|
|
60
|
+
self.rev_range,
|
|
61
|
+
)
|
|
63
62
|
)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
elif num_exclusive_args_provided != 1:
|
|
63
|
+
|
|
64
|
+
if num_exclusive_args_provided > 1:
|
|
67
65
|
raise InvalidCommandArgumentError(
|
|
68
66
|
"Only one of --rev-range, --message, and --commit-msg-file is permitted by check command! "
|
|
69
67
|
"See 'cz check -h' for more information"
|
|
70
68
|
)
|
|
71
69
|
|
|
70
|
+
if num_exclusive_args_provided == 0 and not sys.stdin.isatty():
|
|
71
|
+
self.commit_msg = sys.stdin.read()
|
|
72
|
+
|
|
73
|
+
self.config: BaseConfig = config
|
|
74
|
+
self.encoding = config.settings["encoding"]
|
|
75
|
+
self.cz = factory.committer_factory(self.config)
|
|
76
|
+
|
|
72
77
|
def __call__(self) -> None:
|
|
73
78
|
"""Validate if commit messages follows the conventional pattern.
|
|
74
79
|
|
|
@@ -109,7 +114,10 @@ class Check:
|
|
|
109
114
|
return [git.GitCommit(rev="", title="", body=self._filter_comments(msg))]
|
|
110
115
|
|
|
111
116
|
# Get commit messages from git log (--rev-range)
|
|
112
|
-
return git.get_commits(
|
|
117
|
+
return git.get_commits(
|
|
118
|
+
git.get_default_branch() if self.use_default_range else None,
|
|
119
|
+
self.rev_range,
|
|
120
|
+
)
|
|
113
121
|
|
|
114
122
|
@staticmethod
|
|
115
123
|
def _filter_comments(msg: str) -> str:
|
|
@@ -134,7 +142,7 @@ class Check:
|
|
|
134
142
|
The filtered commit message without comments.
|
|
135
143
|
"""
|
|
136
144
|
|
|
137
|
-
lines = []
|
|
145
|
+
lines: list[str] = []
|
|
138
146
|
for line in msg.split("\n"):
|
|
139
147
|
if "# ------------------------ >8 ------------------------" in line:
|
|
140
148
|
break
|