commitizen 4.2.2__tar.gz → 4.4.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.2.2 → commitizen-4.4.0}/PKG-INFO +1 -1
- commitizen-4.4.0/commitizen/__version__.py +1 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/bump.py +1 -29
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/changelog.py +26 -58
- commitizen-4.4.0/commitizen/changelog_formats/asciidoc.py +28 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/changelog_formats/base.py +12 -16
- commitizen-4.4.0/commitizen/changelog_formats/markdown.py +29 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/changelog_formats/restructuredtext.py +5 -26
- commitizen-4.4.0/commitizen/changelog_formats/textile.py +26 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/bump.py +19 -19
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/changelog.py +18 -21
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/init.py +1 -1
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/defaults.py +15 -13
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/providers/__init__.py +2 -0
- commitizen-4.4.0/commitizen/providers/scm_provider.py +28 -0
- commitizen-4.4.0/commitizen/providers/uv_provider.py +41 -0
- commitizen-4.4.0/commitizen/tags.py +257 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/version_schemes.py +6 -6
- {commitizen-4.2.2 → commitizen-4.4.0}/pyproject.toml +12 -13
- commitizen-4.2.2/commitizen/__version__.py +0 -1
- commitizen-4.2.2/commitizen/changelog_formats/asciidoc.py +0 -39
- commitizen-4.2.2/commitizen/changelog_formats/markdown.py +0 -42
- commitizen-4.2.2/commitizen/changelog_formats/textile.py +0 -42
- commitizen-4.2.2/commitizen/providers/scm_provider.py +0 -80
- {commitizen-4.2.2 → commitizen-4.4.0}/LICENSE +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/__init__.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/__main__.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/changelog_formats/__init__.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cli.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cmd.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/__init__.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/check.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/commit.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/example.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/info.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/list_cz.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/schema.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/commands/version.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/config/__init__.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/config/base_config.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/config/json_config.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/config/toml_config.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/config/yaml_config.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/__init__.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/base.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/conventional_commits/__init__.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/conventional_commits/conventional_commits.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/conventional_commits/conventional_commits_info.txt +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/customize/__init__.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/customize/customize.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/customize/customize_info.txt +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/exceptions.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/jira/__init__.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/jira/jira.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/jira/jira_info.txt +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/cz/utils.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/exceptions.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/factory.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/git.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/hooks.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/out.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/providers/base_provider.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/providers/cargo_provider.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/providers/commitizen_provider.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/providers/composer_provider.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/providers/npm_provider.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/providers/pep621_provider.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/providers/poetry_provider.py +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/py.typed +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/templates/CHANGELOG.adoc.j2 +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/templates/CHANGELOG.md.j2 +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/templates/CHANGELOG.rst.j2 +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/commitizen/templates/CHANGELOG.textile.j2 +0 -0
- {commitizen-4.2.2 → commitizen-4.4.0}/docs/README.md +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "4.4.0"
|
|
@@ -11,7 +11,7 @@ from typing import cast
|
|
|
11
11
|
from commitizen.defaults import MAJOR, MINOR, PATCH, bump_message, encoding
|
|
12
12
|
from commitizen.exceptions import CurrentVersionNotFoundError
|
|
13
13
|
from commitizen.git import GitCommit, smart_open
|
|
14
|
-
from commitizen.version_schemes import
|
|
14
|
+
from commitizen.version_schemes import Increment, Version
|
|
15
15
|
|
|
16
16
|
VERSION_TYPES = [None, PATCH, MINOR, MAJOR]
|
|
17
17
|
|
|
@@ -142,34 +142,6 @@ def _version_to_regex(version: str) -> str:
|
|
|
142
142
|
return version.replace(".", r"\.").replace("+", r"\+")
|
|
143
143
|
|
|
144
144
|
|
|
145
|
-
def normalize_tag(
|
|
146
|
-
version: Version | str,
|
|
147
|
-
tag_format: str,
|
|
148
|
-
scheme: VersionScheme | None = None,
|
|
149
|
-
) -> str:
|
|
150
|
-
"""The tag and the software version might be different.
|
|
151
|
-
|
|
152
|
-
That's why this function exists.
|
|
153
|
-
|
|
154
|
-
Example:
|
|
155
|
-
| tag | version (PEP 0440) |
|
|
156
|
-
| --- | ------- |
|
|
157
|
-
| v0.9.0 | 0.9.0 |
|
|
158
|
-
| ver1.0.0 | 1.0.0 |
|
|
159
|
-
| ver1.0.0.a0 | 1.0.0a0 |
|
|
160
|
-
"""
|
|
161
|
-
scheme = scheme or DEFAULT_SCHEME
|
|
162
|
-
version = scheme(version) if isinstance(version, str) else version
|
|
163
|
-
|
|
164
|
-
major, minor, patch = version.release
|
|
165
|
-
prerelease = version.prerelease or ""
|
|
166
|
-
|
|
167
|
-
t = Template(tag_format)
|
|
168
|
-
return t.safe_substitute(
|
|
169
|
-
version=version, major=major, minor=minor, patch=patch, prerelease=prerelease
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
|
|
173
145
|
def create_commit_message(
|
|
174
146
|
current_version: Version | str,
|
|
175
147
|
new_version: Version | str,
|
|
@@ -42,21 +42,13 @@ from jinja2 import (
|
|
|
42
42
|
Template,
|
|
43
43
|
)
|
|
44
44
|
|
|
45
|
-
from commitizen import out
|
|
46
|
-
from commitizen.bump import normalize_tag
|
|
47
45
|
from commitizen.cz.base import ChangelogReleaseHook
|
|
48
|
-
from commitizen.defaults import get_tag_regexes
|
|
49
46
|
from commitizen.exceptions import InvalidConfigurationError, NoCommitsFoundError
|
|
50
47
|
from commitizen.git import GitCommit, GitTag
|
|
51
|
-
from commitizen.
|
|
52
|
-
DEFAULT_SCHEME,
|
|
53
|
-
BaseVersion,
|
|
54
|
-
InvalidVersion,
|
|
55
|
-
)
|
|
48
|
+
from commitizen.tags import TagRules
|
|
56
49
|
|
|
57
50
|
if TYPE_CHECKING:
|
|
58
51
|
from commitizen.cz.base import MessageBuilderHook
|
|
59
|
-
from commitizen.version_schemes import VersionScheme
|
|
60
52
|
|
|
61
53
|
|
|
62
54
|
@dataclass
|
|
@@ -69,50 +61,19 @@ class Metadata:
|
|
|
69
61
|
unreleased_end: int | None = None
|
|
70
62
|
latest_version: str | None = None
|
|
71
63
|
latest_version_position: int | None = None
|
|
64
|
+
latest_version_tag: str | None = None
|
|
65
|
+
|
|
66
|
+
def __post_init__(self):
|
|
67
|
+
if self.latest_version and not self.latest_version_tag:
|
|
68
|
+
# Test syntactic sugar
|
|
69
|
+
# latest version tag is optional if same as latest version
|
|
70
|
+
self.latest_version_tag = self.latest_version
|
|
72
71
|
|
|
73
72
|
|
|
74
73
|
def get_commit_tag(commit: GitCommit, tags: list[GitTag]) -> GitTag | None:
|
|
75
74
|
return next((tag for tag in tags if tag.rev == commit.rev), None)
|
|
76
75
|
|
|
77
76
|
|
|
78
|
-
def tag_included_in_changelog(
|
|
79
|
-
tag: GitTag,
|
|
80
|
-
used_tags: list,
|
|
81
|
-
merge_prerelease: bool,
|
|
82
|
-
scheme: VersionScheme = DEFAULT_SCHEME,
|
|
83
|
-
) -> bool:
|
|
84
|
-
if tag in used_tags:
|
|
85
|
-
return False
|
|
86
|
-
|
|
87
|
-
try:
|
|
88
|
-
version = scheme(tag.name)
|
|
89
|
-
except InvalidVersion:
|
|
90
|
-
return False
|
|
91
|
-
|
|
92
|
-
if merge_prerelease and version.is_prerelease:
|
|
93
|
-
return False
|
|
94
|
-
|
|
95
|
-
return True
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def get_version_tags(
|
|
99
|
-
scheme: type[BaseVersion], tags: list[GitTag], tag_format: str
|
|
100
|
-
) -> list[GitTag]:
|
|
101
|
-
valid_tags: list[GitTag] = []
|
|
102
|
-
TAG_FORMAT_REGEXS = get_tag_regexes(scheme.parser.pattern)
|
|
103
|
-
tag_format_regex = tag_format
|
|
104
|
-
for pattern, regex in TAG_FORMAT_REGEXS.items():
|
|
105
|
-
tag_format_regex = tag_format_regex.replace(pattern, regex)
|
|
106
|
-
for tag in tags:
|
|
107
|
-
if re.match(tag_format_regex, tag.name):
|
|
108
|
-
valid_tags.append(tag)
|
|
109
|
-
else:
|
|
110
|
-
out.warn(
|
|
111
|
-
f"InvalidVersion {tag.name} doesn't match configured tag format {tag_format}"
|
|
112
|
-
)
|
|
113
|
-
return valid_tags
|
|
114
|
-
|
|
115
|
-
|
|
116
77
|
def generate_tree_from_commits(
|
|
117
78
|
commits: list[GitCommit],
|
|
118
79
|
tags: list[GitTag],
|
|
@@ -122,13 +83,13 @@ def generate_tree_from_commits(
|
|
|
122
83
|
change_type_map: dict[str, str] | None = None,
|
|
123
84
|
changelog_message_builder_hook: MessageBuilderHook | None = None,
|
|
124
85
|
changelog_release_hook: ChangelogReleaseHook | None = None,
|
|
125
|
-
|
|
126
|
-
scheme: VersionScheme = DEFAULT_SCHEME,
|
|
86
|
+
rules: TagRules | None = None,
|
|
127
87
|
) -> Iterable[dict]:
|
|
128
88
|
pat = re.compile(changelog_pattern)
|
|
129
89
|
map_pat = re.compile(commit_parser, re.MULTILINE)
|
|
130
90
|
body_map_pat = re.compile(commit_parser, re.MULTILINE | re.DOTALL)
|
|
131
91
|
current_tag: GitTag | None = None
|
|
92
|
+
rules = rules or TagRules()
|
|
132
93
|
|
|
133
94
|
# Check if the latest commit is not tagged
|
|
134
95
|
if commits:
|
|
@@ -148,8 +109,10 @@ def generate_tree_from_commits(
|
|
|
148
109
|
for commit in commits:
|
|
149
110
|
commit_tag = get_commit_tag(commit, tags)
|
|
150
111
|
|
|
151
|
-
if
|
|
152
|
-
commit_tag
|
|
112
|
+
if (
|
|
113
|
+
commit_tag
|
|
114
|
+
and commit_tag not in used_tags
|
|
115
|
+
and rules.include_in_changelog(commit_tag)
|
|
153
116
|
):
|
|
154
117
|
used_tags.append(commit_tag)
|
|
155
118
|
release = {
|
|
@@ -343,8 +306,7 @@ def get_smart_tag_range(
|
|
|
343
306
|
def get_oldest_and_newest_rev(
|
|
344
307
|
tags: list[GitTag],
|
|
345
308
|
version: str,
|
|
346
|
-
|
|
347
|
-
scheme: VersionScheme | None = None,
|
|
309
|
+
rules: TagRules,
|
|
348
310
|
) -> tuple[str | None, str | None]:
|
|
349
311
|
"""Find the tags for the given version.
|
|
350
312
|
|
|
@@ -358,22 +320,28 @@ def get_oldest_and_newest_rev(
|
|
|
358
320
|
oldest, newest = version.split("..")
|
|
359
321
|
except ValueError:
|
|
360
322
|
newest = version
|
|
361
|
-
newest_tag
|
|
323
|
+
if not (newest_tag := rules.find_tag_for(tags, newest)):
|
|
324
|
+
raise NoCommitsFoundError("Could not find a valid revision range.")
|
|
362
325
|
|
|
363
326
|
oldest_tag = None
|
|
327
|
+
oldest_tag_name = None
|
|
364
328
|
if oldest:
|
|
365
|
-
oldest_tag
|
|
329
|
+
if not (oldest_tag := rules.find_tag_for(tags, oldest)):
|
|
330
|
+
raise NoCommitsFoundError("Could not find a valid revision range.")
|
|
331
|
+
oldest_tag_name = oldest_tag.name
|
|
366
332
|
|
|
367
|
-
tags_range = get_smart_tag_range(
|
|
333
|
+
tags_range = get_smart_tag_range(
|
|
334
|
+
tags, newest=newest_tag.name, oldest=oldest_tag_name
|
|
335
|
+
)
|
|
368
336
|
if not tags_range:
|
|
369
337
|
raise NoCommitsFoundError("Could not find a valid revision range.")
|
|
370
338
|
|
|
371
339
|
oldest_rev: str | None = tags_range[-1].name
|
|
372
|
-
newest_rev = newest_tag
|
|
340
|
+
newest_rev = newest_tag.name
|
|
373
341
|
|
|
374
342
|
# check if it's the first tag created
|
|
375
343
|
# and it's also being requested as part of the range
|
|
376
|
-
if oldest_rev == tags[-1].name and oldest_rev ==
|
|
344
|
+
if oldest_rev == tags[-1].name and oldest_rev == oldest_tag_name:
|
|
377
345
|
return None, newest_rev
|
|
378
346
|
|
|
379
347
|
# when they are the same, and it's also the
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from .base import BaseFormat
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from commitizen.tags import VersionTag
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AsciiDoc(BaseFormat):
|
|
13
|
+
extension = "adoc"
|
|
14
|
+
|
|
15
|
+
RE_TITLE = re.compile(r"^(?P<level>=+) (?P<title>.*)$")
|
|
16
|
+
|
|
17
|
+
def parse_version_from_title(self, line: str) -> VersionTag | None:
|
|
18
|
+
m = self.RE_TITLE.match(line)
|
|
19
|
+
if not m:
|
|
20
|
+
return None
|
|
21
|
+
# Capture last match as AsciiDoc use postfixed URL labels
|
|
22
|
+
return self.tag_rules.search_version(m.group("title"), last=True)
|
|
23
|
+
|
|
24
|
+
def parse_title_level(self, line: str) -> int | None:
|
|
25
|
+
m = self.RE_TITLE.match(line)
|
|
26
|
+
if not m:
|
|
27
|
+
return None
|
|
28
|
+
return len(m.group("level"))
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
import re
|
|
5
4
|
from abc import ABCMeta
|
|
6
|
-
from re import Pattern
|
|
7
5
|
from typing import IO, Any, ClassVar
|
|
8
6
|
|
|
9
7
|
from commitizen.changelog import Metadata
|
|
10
8
|
from commitizen.config.base_config import BaseConfig
|
|
11
|
-
from commitizen.
|
|
9
|
+
from commitizen.tags import TagRules, VersionTag
|
|
12
10
|
from commitizen.version_schemes import get_version_scheme
|
|
13
11
|
|
|
14
12
|
from . import ChangelogFormat
|
|
@@ -28,15 +26,12 @@ class BaseFormat(ChangelogFormat, metaclass=ABCMeta):
|
|
|
28
26
|
self.config = config
|
|
29
27
|
self.encoding = self.config.settings["encoding"]
|
|
30
28
|
self.tag_format = self.config.settings["tag_format"]
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
for pattern, regex in TAG_FORMAT_REGEXS.items():
|
|
38
|
-
tag_regex = tag_regex.replace(pattern, regex)
|
|
39
|
-
return re.compile(tag_regex)
|
|
29
|
+
self.tag_rules = TagRules(
|
|
30
|
+
scheme=get_version_scheme(self.config.settings),
|
|
31
|
+
tag_format=self.tag_format,
|
|
32
|
+
legacy_tag_formats=self.config.settings["legacy_tag_formats"],
|
|
33
|
+
ignored_tag_formats=self.config.settings["ignored_tag_formats"],
|
|
34
|
+
)
|
|
40
35
|
|
|
41
36
|
def get_metadata(self, filepath: str) -> Metadata:
|
|
42
37
|
if not os.path.isfile(filepath):
|
|
@@ -63,9 +58,10 @@ class BaseFormat(ChangelogFormat, metaclass=ABCMeta):
|
|
|
63
58
|
meta.unreleased_end = index
|
|
64
59
|
|
|
65
60
|
# Try to find the latest release done
|
|
66
|
-
|
|
67
|
-
if
|
|
68
|
-
meta.latest_version = version
|
|
61
|
+
parsed = self.parse_version_from_title(line)
|
|
62
|
+
if parsed:
|
|
63
|
+
meta.latest_version = parsed.version
|
|
64
|
+
meta.latest_version_tag = parsed.tag
|
|
69
65
|
meta.latest_version_position = index
|
|
70
66
|
break # there's no need for more info
|
|
71
67
|
if meta.unreleased_start is not None and meta.unreleased_end is None:
|
|
@@ -73,7 +69,7 @@ class BaseFormat(ChangelogFormat, metaclass=ABCMeta):
|
|
|
73
69
|
|
|
74
70
|
return meta
|
|
75
71
|
|
|
76
|
-
def parse_version_from_title(self, line: str) ->
|
|
72
|
+
def parse_version_from_title(self, line: str) -> VersionTag | None:
|
|
77
73
|
"""
|
|
78
74
|
Extract the version from a title line if any
|
|
79
75
|
"""
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from .base import BaseFormat
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from commitizen.tags import VersionTag
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Markdown(BaseFormat):
|
|
13
|
+
extension = "md"
|
|
14
|
+
|
|
15
|
+
alternative_extensions = {"markdown", "mkd"}
|
|
16
|
+
|
|
17
|
+
RE_TITLE = re.compile(r"^(?P<level>#+) (?P<title>.*)$")
|
|
18
|
+
|
|
19
|
+
def parse_version_from_title(self, line: str) -> VersionTag | None:
|
|
20
|
+
m = self.RE_TITLE.match(line)
|
|
21
|
+
if not m:
|
|
22
|
+
return None
|
|
23
|
+
return self.tag_rules.search_version(m.group("title"))
|
|
24
|
+
|
|
25
|
+
def parse_title_level(self, line: str) -> int | None:
|
|
26
|
+
m = self.RE_TITLE.match(line)
|
|
27
|
+
if not m:
|
|
28
|
+
return None
|
|
29
|
+
return len(m.group("level"))
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import re
|
|
4
3
|
import sys
|
|
5
4
|
from itertools import zip_longest
|
|
6
5
|
from typing import IO, TYPE_CHECKING, Any, Union
|
|
@@ -64,31 +63,11 @@ class RestructuredText(BaseFormat):
|
|
|
64
63
|
elif unreleased_title_kind and unreleased_title_kind == kind:
|
|
65
64
|
meta.unreleased_end = index
|
|
66
65
|
# Try to find the latest release done
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
meta.latest_version = version
|
|
73
|
-
meta.latest_version_position = index
|
|
74
|
-
break # there's no need for more info
|
|
75
|
-
try:
|
|
76
|
-
partial_version = (
|
|
77
|
-
f"{matches['major']}.{matches['minor']}.{matches['patch']}"
|
|
78
|
-
)
|
|
79
|
-
if matches.get("prerelease"):
|
|
80
|
-
partial_version = (
|
|
81
|
-
f"{partial_version}-{matches['prerelease']}"
|
|
82
|
-
)
|
|
83
|
-
if matches.get("devrelease"):
|
|
84
|
-
partial_version = (
|
|
85
|
-
f"{partial_version}{matches['devrelease']}"
|
|
86
|
-
)
|
|
87
|
-
meta.latest_version = partial_version
|
|
88
|
-
meta.latest_version_position = index
|
|
89
|
-
break
|
|
90
|
-
except KeyError:
|
|
91
|
-
pass
|
|
66
|
+
if version := self.tag_rules.search_version(title):
|
|
67
|
+
meta.latest_version = version[0]
|
|
68
|
+
meta.latest_version_tag = version[1]
|
|
69
|
+
meta.latest_version_position = index
|
|
70
|
+
break
|
|
92
71
|
if meta.unreleased_start is not None and meta.unreleased_end is None:
|
|
93
72
|
meta.unreleased_end = (
|
|
94
73
|
meta.latest_version_position if meta.latest_version else index + 1
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from .base import BaseFormat
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from commitizen.tags import VersionTag
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Textile(BaseFormat):
|
|
13
|
+
extension = "textile"
|
|
14
|
+
|
|
15
|
+
RE_TITLE = re.compile(r"^h(?P<level>\d)\. (?P<title>.*)$")
|
|
16
|
+
|
|
17
|
+
def parse_version_from_title(self, line: str) -> VersionTag | None:
|
|
18
|
+
if not self.RE_TITLE.match(line):
|
|
19
|
+
return None
|
|
20
|
+
return self.tag_rules.search_version(line)
|
|
21
|
+
|
|
22
|
+
def parse_title_level(self, line: str) -> int | None:
|
|
23
|
+
m = self.RE_TITLE.match(line)
|
|
24
|
+
if not m:
|
|
25
|
+
return None
|
|
26
|
+
return int(m.group("level"))
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import warnings
|
|
4
4
|
from logging import getLogger
|
|
5
|
+
from typing import cast
|
|
5
6
|
|
|
6
7
|
import questionary
|
|
7
8
|
|
|
@@ -9,6 +10,7 @@ from commitizen import bump, factory, git, hooks, out
|
|
|
9
10
|
from commitizen.changelog_formats import get_changelog_format
|
|
10
11
|
from commitizen.commands.changelog import Changelog
|
|
11
12
|
from commitizen.config import BaseConfig
|
|
13
|
+
from commitizen.defaults import Settings
|
|
12
14
|
from commitizen.exceptions import (
|
|
13
15
|
BumpCommitFailedError,
|
|
14
16
|
BumpTagFailedError,
|
|
@@ -24,6 +26,7 @@ from commitizen.exceptions import (
|
|
|
24
26
|
NoVersionSpecifiedError,
|
|
25
27
|
)
|
|
26
28
|
from commitizen.providers import get_provider
|
|
29
|
+
from commitizen.tags import TagRules
|
|
27
30
|
from commitizen.version_schemes import (
|
|
28
31
|
Increment,
|
|
29
32
|
InvalidVersion,
|
|
@@ -84,7 +87,7 @@ class Bump:
|
|
|
84
87
|
)
|
|
85
88
|
)
|
|
86
89
|
self.scheme = get_version_scheme(
|
|
87
|
-
self.config, arguments["version_scheme"] or deprecated_version_type
|
|
90
|
+
self.config.settings, arguments["version_scheme"] or deprecated_version_type
|
|
88
91
|
)
|
|
89
92
|
self.file_name = arguments["file_name"] or self.config.settings.get(
|
|
90
93
|
"changelog_file"
|
|
@@ -98,18 +101,20 @@ class Bump:
|
|
|
98
101
|
)
|
|
99
102
|
self.extras = arguments["extras"]
|
|
100
103
|
|
|
101
|
-
def is_initial_tag(
|
|
104
|
+
def is_initial_tag(
|
|
105
|
+
self, current_tag: git.GitTag | None, is_yes: bool = False
|
|
106
|
+
) -> bool:
|
|
102
107
|
"""Check if reading the whole git tree up to HEAD is needed."""
|
|
103
108
|
is_initial = False
|
|
104
|
-
if not
|
|
109
|
+
if not current_tag:
|
|
105
110
|
if is_yes:
|
|
106
111
|
is_initial = True
|
|
107
112
|
else:
|
|
108
|
-
out.info(
|
|
113
|
+
out.info("No tag matching configuration could not be found.")
|
|
109
114
|
out.info(
|
|
110
115
|
"Possible causes:\n"
|
|
111
116
|
"- version in configuration is not the current version\n"
|
|
112
|
-
"- tag_format is missing, check them using 'git tag --list'\n"
|
|
117
|
+
"- tag_format or legacy_tag_formats is missing, check them using 'git tag --list'\n"
|
|
113
118
|
)
|
|
114
119
|
is_initial = questionary.confirm("Is this the first tag created?").ask()
|
|
115
120
|
return is_initial
|
|
@@ -143,7 +148,6 @@ class Bump:
|
|
|
143
148
|
except TypeError:
|
|
144
149
|
raise NoVersionSpecifiedError()
|
|
145
150
|
|
|
146
|
-
tag_format: str = self.bump_settings["tag_format"]
|
|
147
151
|
bump_commit_message: str = self.bump_settings["bump_message"]
|
|
148
152
|
version_files: list[str] = self.bump_settings["version_files"]
|
|
149
153
|
major_version_zero: bool = self.bump_settings["major_version_zero"]
|
|
@@ -221,13 +225,13 @@ class Bump:
|
|
|
221
225
|
or self.changelog_config
|
|
222
226
|
)
|
|
223
227
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
+
rules = TagRules.from_settings(cast(Settings, self.bump_settings))
|
|
229
|
+
current_tag = rules.find_tag_for(git.get_tags(), current_version)
|
|
230
|
+
current_tag_version = getattr(
|
|
231
|
+
current_tag, "name", rules.normalize_tag(current_version)
|
|
228
232
|
)
|
|
229
233
|
|
|
230
|
-
is_initial = self.is_initial_tag(
|
|
234
|
+
is_initial = self.is_initial_tag(current_tag, is_yes)
|
|
231
235
|
|
|
232
236
|
if manual_version:
|
|
233
237
|
try:
|
|
@@ -239,10 +243,10 @@ class Bump:
|
|
|
239
243
|
) from exc
|
|
240
244
|
else:
|
|
241
245
|
if increment is None:
|
|
242
|
-
if
|
|
243
|
-
commits = git.get_commits()
|
|
246
|
+
if current_tag:
|
|
247
|
+
commits = git.get_commits(current_tag.name)
|
|
244
248
|
else:
|
|
245
|
-
commits = git.get_commits(
|
|
249
|
+
commits = git.get_commits()
|
|
246
250
|
|
|
247
251
|
# No commits, there is no need to create an empty tag.
|
|
248
252
|
# Unless we previously had a prerelease.
|
|
@@ -280,11 +284,7 @@ class Bump:
|
|
|
280
284
|
exact_increment=increment_mode == "exact",
|
|
281
285
|
)
|
|
282
286
|
|
|
283
|
-
new_tag_version =
|
|
284
|
-
new_version,
|
|
285
|
-
tag_format=tag_format,
|
|
286
|
-
scheme=self.scheme,
|
|
287
|
-
)
|
|
287
|
+
new_tag_version = rules.normalize_tag(new_version)
|
|
288
288
|
message = bump.create_commit_message(
|
|
289
289
|
current_version, new_version, bump_commit_message
|
|
290
290
|
)
|
|
@@ -6,7 +6,7 @@ from operator import itemgetter
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Callable, cast
|
|
8
8
|
|
|
9
|
-
from commitizen import
|
|
9
|
+
from commitizen import changelog, defaults, factory, git, out
|
|
10
10
|
from commitizen.changelog_formats import get_changelog_format
|
|
11
11
|
from commitizen.config import BaseConfig
|
|
12
12
|
from commitizen.cz.base import ChangelogReleaseHook, MessageBuilderHook
|
|
@@ -20,6 +20,7 @@ from commitizen.exceptions import (
|
|
|
20
20
|
NotAllowed,
|
|
21
21
|
)
|
|
22
22
|
from commitizen.git import GitTag, smart_open
|
|
23
|
+
from commitizen.tags import TagRules
|
|
23
24
|
from commitizen.version_schemes import get_version_scheme
|
|
24
25
|
|
|
25
26
|
|
|
@@ -53,7 +54,9 @@ class Changelog:
|
|
|
53
54
|
)
|
|
54
55
|
self.dry_run = args["dry_run"]
|
|
55
56
|
|
|
56
|
-
self.scheme = get_version_scheme(
|
|
57
|
+
self.scheme = get_version_scheme(
|
|
58
|
+
self.config.settings, args.get("version_scheme")
|
|
59
|
+
)
|
|
57
60
|
|
|
58
61
|
current_version = (
|
|
59
62
|
args.get("current_version", config.settings.get("version")) or ""
|
|
@@ -73,9 +76,14 @@ class Changelog:
|
|
|
73
76
|
self.tag_format: str = (
|
|
74
77
|
args.get("tag_format") or self.config.settings["tag_format"]
|
|
75
78
|
)
|
|
76
|
-
self.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
self.tag_rules = TagRules(
|
|
80
|
+
scheme=self.scheme,
|
|
81
|
+
tag_format=self.tag_format,
|
|
82
|
+
legacy_tag_formats=self.config.settings["legacy_tag_formats"],
|
|
83
|
+
ignored_tag_formats=self.config.settings["ignored_tag_formats"],
|
|
84
|
+
merge_prereleases=args.get("merge_prerelease")
|
|
85
|
+
or self.config.settings["changelog_merge_prerelease"],
|
|
86
|
+
)
|
|
79
87
|
|
|
80
88
|
self.template = (
|
|
81
89
|
args.get("template")
|
|
@@ -152,7 +160,6 @@ class Changelog:
|
|
|
152
160
|
changelog_release_hook: ChangelogReleaseHook | None = (
|
|
153
161
|
self.cz.changelog_release_hook
|
|
154
162
|
)
|
|
155
|
-
merge_prerelease = self.merge_prerelease
|
|
156
163
|
|
|
157
164
|
if self.export_template_to:
|
|
158
165
|
return self.export_template()
|
|
@@ -168,28 +175,19 @@ class Changelog:
|
|
|
168
175
|
# Don't continue if no `file_name` specified.
|
|
169
176
|
assert self.file_name
|
|
170
177
|
|
|
171
|
-
tags = (
|
|
172
|
-
changelog.get_version_tags(self.scheme, git.get_tags(), self.tag_format)
|
|
173
|
-
or []
|
|
174
|
-
)
|
|
178
|
+
tags = self.tag_rules.get_version_tags(git.get_tags(), warn=True)
|
|
175
179
|
end_rev = ""
|
|
176
180
|
if self.incremental:
|
|
177
181
|
changelog_meta = self.changelog_format.get_metadata(self.file_name)
|
|
178
182
|
if changelog_meta.latest_version:
|
|
179
|
-
latest_tag_version: str = bump.normalize_tag(
|
|
180
|
-
changelog_meta.latest_version,
|
|
181
|
-
tag_format=self.tag_format,
|
|
182
|
-
scheme=self.scheme,
|
|
183
|
-
)
|
|
184
183
|
start_rev = self._find_incremental_rev(
|
|
185
|
-
strip_local_version(
|
|
184
|
+
strip_local_version(changelog_meta.latest_version_tag), tags
|
|
186
185
|
)
|
|
187
186
|
if self.rev_range:
|
|
188
187
|
start_rev, end_rev = changelog.get_oldest_and_newest_rev(
|
|
189
188
|
tags,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
scheme=self.scheme,
|
|
189
|
+
self.rev_range,
|
|
190
|
+
self.tag_rules,
|
|
193
191
|
)
|
|
194
192
|
commits = git.get_commits(start=start_rev, end=end_rev, args="--topo-order")
|
|
195
193
|
if not commits and (
|
|
@@ -205,8 +203,7 @@ class Changelog:
|
|
|
205
203
|
change_type_map=change_type_map,
|
|
206
204
|
changelog_message_builder_hook=changelog_message_builder_hook,
|
|
207
205
|
changelog_release_hook=changelog_release_hook,
|
|
208
|
-
|
|
209
|
-
scheme=self.scheme,
|
|
206
|
+
rules=self.tag_rules,
|
|
210
207
|
)
|
|
211
208
|
if self.change_type_order:
|
|
212
209
|
tree = changelog.order_changelog_tree(tree, self.change_type_order)
|
|
@@ -98,7 +98,7 @@ class Init:
|
|
|
98
98
|
version_provider = self._ask_version_provider() # select
|
|
99
99
|
tag = self._ask_tag() # confirm & select
|
|
100
100
|
version_scheme = self._ask_version_scheme() # select
|
|
101
|
-
version = get_version_scheme(self.config, version_scheme)(tag)
|
|
101
|
+
version = get_version_scheme(self.config.settings, version_scheme)(tag)
|
|
102
102
|
tag_format = self._ask_tag_format(tag) # confirm & text
|
|
103
103
|
update_changelog_on_bump = self._ask_update_changelog_on_bump() # confirm
|
|
104
104
|
major_version_zero = self._ask_major_version_zero(version) # confirm
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import pathlib
|
|
4
4
|
from collections import OrderedDict
|
|
5
|
-
from collections.abc import Iterable, MutableMapping
|
|
5
|
+
from collections.abc import Iterable, MutableMapping, Sequence
|
|
6
6
|
from typing import Any, TypedDict
|
|
7
7
|
|
|
8
8
|
# Type
|
|
@@ -35,6 +35,8 @@ class Settings(TypedDict, total=False):
|
|
|
35
35
|
version_scheme: str | None
|
|
36
36
|
version_type: str | None
|
|
37
37
|
tag_format: str
|
|
38
|
+
legacy_tag_formats: Sequence[str]
|
|
39
|
+
ignored_tag_formats: Sequence[str]
|
|
38
40
|
bump_message: str | None
|
|
39
41
|
retry_after_failure: bool
|
|
40
42
|
allow_abort: bool
|
|
@@ -77,6 +79,8 @@ DEFAULT_SETTINGS: Settings = {
|
|
|
77
79
|
"version_provider": "commitizen",
|
|
78
80
|
"version_scheme": None,
|
|
79
81
|
"tag_format": "$version", # example v$version
|
|
82
|
+
"legacy_tag_formats": [],
|
|
83
|
+
"ignored_tag_formats": [],
|
|
80
84
|
"bump_message": None, # bumped v$current_version to $new_version
|
|
81
85
|
"retry_after_failure": False,
|
|
82
86
|
"allow_abort": False,
|
|
@@ -138,17 +142,15 @@ bump_message = "bump: version $current_version → $new_version"
|
|
|
138
142
|
def get_tag_regexes(
|
|
139
143
|
version_regex: str,
|
|
140
144
|
) -> dict[str, str]:
|
|
145
|
+
regexs = {
|
|
146
|
+
"version": version_regex,
|
|
147
|
+
"major": r"(?P<major>\d+)",
|
|
148
|
+
"minor": r"(?P<minor>\d+)",
|
|
149
|
+
"patch": r"(?P<patch>\d+)",
|
|
150
|
+
"prerelease": r"(?P<prerelease>\w+\d+)?",
|
|
151
|
+
"devrelease": r"(?P<devrelease>\.dev\d+)?",
|
|
152
|
+
}
|
|
141
153
|
return {
|
|
142
|
-
"$
|
|
143
|
-
"$
|
|
144
|
-
"$minor": r"(?P<minor>\d+)",
|
|
145
|
-
"$patch": r"(?P<patch>\d+)",
|
|
146
|
-
"$prerelease": r"(?P<prerelease>\w+\d+)?",
|
|
147
|
-
"$devrelease": r"(?P<devrelease>\.dev\d+)?",
|
|
148
|
-
"${version}": version_regex,
|
|
149
|
-
"${major}": r"(?P<major>\d+)",
|
|
150
|
-
"${minor}": r"(?P<minor>\d+)",
|
|
151
|
-
"${patch}": r"(?P<patch>\d+)",
|
|
152
|
-
"${prerelease}": r"(?P<prerelease>\w+\d+)?",
|
|
153
|
-
"${devrelease}": r"(?P<devrelease>\.dev\d+)?",
|
|
154
|
+
**{f"${k}": v for k, v in regexs.items()},
|
|
155
|
+
**{f"${{{k}}}": v for k, v in regexs.items()},
|
|
154
156
|
}
|