Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 070bfdf

Browse filesBrowse files
committed
feat(tags): adds legacy_tag_formats and ignored_tag_formats settings
1 parent e03b085 commit 070bfdf
Copy full SHA for 070bfdf
Expand file treeCollapse file tree

32 files changed

+982
-372
lines changed

‎commitizen/bump.py

Copy file name to clipboardExpand all lines: commitizen/bump.py
+1-29Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from commitizen.defaults import MAJOR, MINOR, PATCH, bump_message, encoding
1111
from commitizen.exceptions import CurrentVersionNotFoundError
1212
from commitizen.git import GitCommit, smart_open
13-
from commitizen.version_schemes import DEFAULT_SCHEME, Increment, Version, VersionScheme
13+
from commitizen.version_schemes import Increment, Version
1414

1515
VERSION_TYPES = [None, PATCH, MINOR, MAJOR]
1616

@@ -131,34 +131,6 @@ def _version_to_regex(version: str) -> str:
131131
return version.replace(".", r"\.").replace("+", r"\+")
132132

133133

134-
def normalize_tag(
135-
version: Version | str,
136-
tag_format: str,
137-
scheme: VersionScheme | None = None,
138-
) -> str:
139-
"""The tag and the software version might be different.
140-
141-
That's why this function exists.
142-
143-
Example:
144-
| tag | version (PEP 0440) |
145-
| --- | ------- |
146-
| v0.9.0 | 0.9.0 |
147-
| ver1.0.0 | 1.0.0 |
148-
| ver1.0.0.a0 | 1.0.0a0 |
149-
"""
150-
scheme = scheme or DEFAULT_SCHEME
151-
version = scheme(version) if isinstance(version, str) else version
152-
153-
major, minor, patch = version.release
154-
prerelease = version.prerelease or ""
155-
156-
t = Template(tag_format)
157-
return t.safe_substitute(
158-
version=version, major=major, minor=minor, patch=patch, prerelease=prerelease
159-
)
160-
161-
162134
def create_commit_message(
163135
current_version: Version | str,
164136
new_version: Version | str,

‎commitizen/changelog.py

Copy file name to clipboardExpand all lines: commitizen/changelog.py
+26-58Lines changed: 26 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,13 @@
4242
Template,
4343
)
4444

45-
from commitizen import out
46-
from commitizen.bump import normalize_tag
4745
from commitizen.cz.base import ChangelogReleaseHook
48-
from commitizen.defaults import get_tag_regexes
4946
from commitizen.exceptions import InvalidConfigurationError, NoCommitsFoundError
5047
from commitizen.git import GitCommit, GitTag
51-
from commitizen.version_schemes import (
52-
DEFAULT_SCHEME,
53-
BaseVersion,
54-
InvalidVersion,
55-
)
48+
from commitizen.tags import TagRules
5649

5750
if TYPE_CHECKING:
5851
from commitizen.cz.base import MessageBuilderHook
59-
from commitizen.version_schemes import VersionScheme
6052

6153

6254
@dataclass
@@ -69,50 +61,19 @@ class Metadata:
6961
unreleased_end: int | None = None
7062
latest_version: str | None = None
7163
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
7271

7372

7473
def get_commit_tag(commit: GitCommit, tags: list[GitTag]) -> GitTag | None:
7574
return next((tag for tag in tags if tag.rev == commit.rev), None)
7675

7776

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-
11677
def generate_tree_from_commits(
11778
commits: list[GitCommit],
11879
tags: list[GitTag],
@@ -122,13 +83,13 @@ def generate_tree_from_commits(
12283
change_type_map: dict[str, str] | None = None,
12384
changelog_message_builder_hook: MessageBuilderHook | None = None,
12485
changelog_release_hook: ChangelogReleaseHook | None = None,
125-
merge_prerelease: bool = False,
126-
scheme: VersionScheme = DEFAULT_SCHEME,
86+
rules: TagRules | None = None,
12787
) -> Iterable[dict]:
12888
pat = re.compile(changelog_pattern)
12989
map_pat = re.compile(commit_parser, re.MULTILINE)
13090
body_map_pat = re.compile(commit_parser, re.MULTILINE | re.DOTALL)
13191
current_tag: GitTag | None = None
92+
rules = rules or TagRules()
13293

13394
# Check if the latest commit is not tagged
13495
if commits:
@@ -148,8 +109,10 @@ def generate_tree_from_commits(
148109
for commit in commits:
149110
commit_tag = get_commit_tag(commit, tags)
150111

151-
if commit_tag is not None and tag_included_in_changelog(
152-
commit_tag, used_tags, merge_prerelease, scheme=scheme
112+
if (
113+
commit_tag
114+
and commit_tag not in used_tags
115+
and rules.include_in_changelog(commit_tag)
153116
):
154117
used_tags.append(commit_tag)
155118
release = {
@@ -343,8 +306,7 @@ def get_smart_tag_range(
343306
def get_oldest_and_newest_rev(
344307
tags: list[GitTag],
345308
version: str,
346-
tag_format: str,
347-
scheme: VersionScheme | None = None,
309+
rules: TagRules,
348310
) -> tuple[str | None, str | None]:
349311
"""Find the tags for the given version.
350312
@@ -358,22 +320,28 @@ def get_oldest_and_newest_rev(
358320
oldest, newest = version.split("..")
359321
except ValueError:
360322
newest = version
361-
newest_tag = normalize_tag(newest, tag_format=tag_format, scheme=scheme)
323+
if not (newest_tag := rules.find_tag_for(tags, newest)):
324+
raise NoCommitsFoundError("Could not find a valid revision range.")
362325

363326
oldest_tag = None
327+
oldest_tag_name = None
364328
if oldest:
365-
oldest_tag = normalize_tag(oldest, tag_format=tag_format, scheme=scheme)
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
366332

367-
tags_range = get_smart_tag_range(tags, newest=newest_tag, oldest=oldest_tag)
333+
tags_range = get_smart_tag_range(
334+
tags, newest=newest_tag.name, oldest=oldest_tag_name
335+
)
368336
if not tags_range:
369337
raise NoCommitsFoundError("Could not find a valid revision range.")
370338

371339
oldest_rev: str | None = tags_range[-1].name
372-
newest_rev = newest_tag
340+
newest_rev = newest_tag.name
373341

374342
# check if it's the first tag created
375343
# and it's also being requested as part of the range
376-
if oldest_rev == tags[-1].name and oldest_rev == oldest_tag:
344+
if oldest_rev == tags[-1].name and oldest_rev == oldest_tag_name:
377345
return None, newest_rev
378346

379347
# when they are the same, and it's also the

‎commitizen/changelog_formats/asciidoc.py

Copy file name to clipboardExpand all lines: commitizen/changelog_formats/asciidoc.py
+6-17Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,25 @@
11
from __future__ import annotations
22

33
import re
4+
from typing import TYPE_CHECKING
45

56
from .base import BaseFormat
67

8+
if TYPE_CHECKING:
9+
from commitizen.tags import VersionTag
10+
711

812
class AsciiDoc(BaseFormat):
913
extension = "adoc"
1014

1115
RE_TITLE = re.compile(r"^(?P<level>=+) (?P<title>.*)$")
1216

13-
def parse_version_from_title(self, line: str) -> str | None:
17+
def parse_version_from_title(self, line: str) -> VersionTag | None:
1418
m = self.RE_TITLE.match(line)
1519
if not m:
1620
return None
1721
# Capture last match as AsciiDoc use postfixed URL labels
18-
matches = list(re.finditer(self.version_parser, m.group("title")))
19-
if not matches:
20-
return None
21-
if "version" in matches[-1].groupdict():
22-
return matches[-1].group("version")
23-
partial_matches = matches[-1].groupdict()
24-
try:
25-
partial_version = f"{partial_matches['major']}.{partial_matches['minor']}.{partial_matches['patch']}"
26-
except KeyError:
27-
return None
28-
29-
if partial_matches.get("prerelease"):
30-
partial_version = f"{partial_version}-{partial_matches['prerelease']}"
31-
if partial_matches.get("devrelease"):
32-
partial_version = f"{partial_version}{partial_matches['devrelease']}"
33-
return partial_version
22+
return self.tag_rules.search_version(m.group("title"), last=True)
3423

3524
def parse_title_level(self, line: str) -> int | None:
3625
m = self.RE_TITLE.match(line)

‎commitizen/changelog_formats/base.py

Copy file name to clipboardExpand all lines: commitizen/changelog_formats/base.py
+12-16Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
from __future__ import annotations
22

33
import os
4-
import re
54
from abc import ABCMeta
6-
from re import Pattern
75
from typing import IO, Any, ClassVar
86

97
from commitizen.changelog import Metadata
108
from commitizen.config.base_config import BaseConfig
11-
from commitizen.defaults import get_tag_regexes
9+
from commitizen.tags import TagRules, VersionTag
1210
from commitizen.version_schemes import get_version_scheme
1311

1412
from . import ChangelogFormat
@@ -28,15 +26,12 @@ def __init__(self, config: BaseConfig):
2826
self.config = config
2927
self.encoding = self.config.settings["encoding"]
3028
self.tag_format = self.config.settings["tag_format"]
31-
32-
@property
33-
def version_parser(self) -> Pattern:
34-
tag_regex: str = self.tag_format
35-
version_regex = get_version_scheme(self.config).parser.pattern
36-
TAG_FORMAT_REGEXS = get_tag_regexes(version_regex)
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+
)
4035

4136
def get_metadata(self, filepath: str) -> Metadata:
4237
if not os.path.isfile(filepath):
@@ -63,17 +58,18 @@ def get_metadata_from_file(self, file: IO[Any]) -> Metadata:
6358
meta.unreleased_end = index
6459

6560
# Try to find the latest release done
66-
version = self.parse_version_from_title(line)
67-
if version:
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
6965
meta.latest_version_position = index
7066
break # there's no need for more info
7167
if meta.unreleased_start is not None and meta.unreleased_end is None:
7268
meta.unreleased_end = index
7369

7470
return meta
7571

76-
def parse_version_from_title(self, line: str) -> str | None:
72+
def parse_version_from_title(self, line: str) -> VersionTag | None:
7773
"""
7874
Extract the version from a title line if any
7975
"""

‎commitizen/changelog_formats/markdown.py

Copy file name to clipboardExpand all lines: commitizen/changelog_formats/markdown.py
+6-19Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
from __future__ import annotations
22

33
import re
4+
from typing import TYPE_CHECKING
45

56
from .base import BaseFormat
67

8+
if TYPE_CHECKING:
9+
from commitizen.tags import VersionTag
10+
711

812
class Markdown(BaseFormat):
913
extension = "md"
@@ -12,28 +16,11 @@ class Markdown(BaseFormat):
1216

1317
RE_TITLE = re.compile(r"^(?P<level>#+) (?P<title>.*)$")
1418

15-
def parse_version_from_title(self, line: str) -> str | None:
19+
def parse_version_from_title(self, line: str) -> VersionTag | None:
1620
m = self.RE_TITLE.match(line)
1721
if not m:
1822
return None
19-
m = re.search(self.version_parser, m.group("title"))
20-
if not m:
21-
return None
22-
if "version" in m.groupdict():
23-
return m.group("version")
24-
matches = m.groupdict()
25-
try:
26-
partial_version = (
27-
f"{matches['major']}.{matches['minor']}.{matches['patch']}"
28-
)
29-
except KeyError:
30-
return None
31-
32-
if matches.get("prerelease"):
33-
partial_version = f"{partial_version}-{matches['prerelease']}"
34-
if matches.get("devrelease"):
35-
partial_version = f"{partial_version}{matches['devrelease']}"
36-
return partial_version
23+
return self.tag_rules.search_version(m.group("title"))
3724

3825
def parse_title_level(self, line: str) -> int | None:
3926
m = self.RE_TITLE.match(line)

‎commitizen/changelog_formats/restructuredtext.py

Copy file name to clipboardExpand all lines: commitizen/changelog_formats/restructuredtext.py
+5-26Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
import re
43
import sys
54
from itertools import zip_longest
65
from typing import IO, TYPE_CHECKING, Any, Union
@@ -64,31 +63,11 @@ def get_metadata_from_file(self, file: IO[Any]) -> Metadata:
6463
elif unreleased_title_kind and unreleased_title_kind == kind:
6564
meta.unreleased_end = index
6665
# Try to find the latest release done
67-
m = re.search(self.version_parser, title)
68-
if m:
69-
matches = m.groupdict()
70-
if "version" in matches:
71-
version = m.group("version")
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
9271
if meta.unreleased_start is not None and meta.unreleased_end is None:
9372
meta.unreleased_end = (
9473
meta.latest_version_position if meta.latest_version else index + 1

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.