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 c1f2e4f

Browse filesBrowse files
committed
feat(tags): adds legacy_tag_formats and ignored_tag_formats settings
1 parent b110988 commit c1f2e4f
Copy full SHA for c1f2e4f

30 files changed

+781
-373
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
+2-17Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,12 @@ class AsciiDoc(BaseFormat):
1010

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

13-
def parse_version_from_title(self, line: str) -> str | None:
13+
def parse_version_from_title(self, line: str) -> tuple[str, str] | None:
1414
m = self.RE_TITLE.match(line)
1515
if not m:
1616
return None
1717
# 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
18+
return self.tag_rules.search_version(m.group("title"), last=True)
3419

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

‎commitizen/changelog_formats/base.py

Copy file name to clipboardExpand all lines: commitizen/changelog_formats/base.py
+10-15Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
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

9-
from commitizen.changelog import Metadata
7+
from commitizen.changelog import Metadata, TagRules
108
from commitizen.config.base_config import BaseConfig
11-
from commitizen.defaults import get_tag_regexes
129
from commitizen.version_schemes import get_version_scheme
1310

1411
from . import ChangelogFormat
@@ -28,15 +25,12 @@ def __init__(self, config: BaseConfig):
2825
self.config = config
2926
self.encoding = self.config.settings["encoding"]
3027
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)
28+
self.tag_rules = TagRules(
29+
scheme=get_version_scheme(self.config.settings),
30+
tag_format=self.tag_format,
31+
legacy_tag_formats=self.config.settings["legacy_tag_formats"],
32+
ignored_tag_formats=self.config.settings["ignored_tag_formats"],
33+
)
4034

4135
def get_metadata(self, filepath: str) -> Metadata:
4236
if not os.path.isfile(filepath):
@@ -65,15 +59,16 @@ def get_metadata_from_file(self, file: IO[Any]) -> Metadata:
6559
# Try to find the latest release done
6660
version = self.parse_version_from_title(line)
6761
if version:
68-
meta.latest_version = version
62+
meta.latest_version = version[0]
63+
meta.latest_version_tag = version[1]
6964
meta.latest_version_position = index
7065
break # there's no need for more info
7166
if meta.unreleased_start is not None and meta.unreleased_end is None:
7267
meta.unreleased_end = index
7368

7469
return meta
7570

76-
def parse_version_from_title(self, line: str) -> str | None:
71+
def parse_version_from_title(self, line: str) -> tuple[str, str] | None:
7772
"""
7873
Extract the version from a title line if any
7974
"""

‎commitizen/changelog_formats/markdown.py

Copy file name to clipboardExpand all lines: commitizen/changelog_formats/markdown.py
+2-19Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,11 @@ class Markdown(BaseFormat):
1212

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

15-
def parse_version_from_title(self, line: str) -> str | None:
15+
def parse_version_from_title(self, line: str) -> tuple[str, str] | None:
1616
m = self.RE_TITLE.match(line)
1717
if not m:
1818
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
19+
return self.tag_rules.search_version(m.group("title"))
3720

3821
def parse_title_level(self, line: str) -> int | None:
3922
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

‎commitizen/changelog_formats/textile.py

Copy file name to clipboardExpand all lines: commitizen/changelog_formats/textile.py
+2-22Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,10 @@ class Textile(BaseFormat):
1010

1111
RE_TITLE = re.compile(r"^h(?P<level>\d)\. (?P<title>.*)$")
1212

13-
def parse_version_from_title(self, line: str) -> str | None:
13+
def parse_version_from_title(self, line: str) -> tuple[str, str] | None:
1414
if not self.RE_TITLE.match(line):
1515
return None
16-
m = re.search(self.version_parser, line)
17-
if not m:
18-
return None
19-
if "version" in m.groupdict():
20-
return m.group("version")
21-
matches = m.groupdict()
22-
if not all(
23-
[
24-
version_segment in matches
25-
for version_segment in ("major", "minor", "patch")
26-
]
27-
):
28-
return None
29-
30-
partial_version = f"{matches['major']}.{matches['minor']}.{matches['patch']}"
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
16+
return self.tag_rules.search_version(line)
3717

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

0 commit comments

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