Skip to content

Commit 9c98974

Browse files
fix(changelog_merge_prerelease): changelog not merged during cz bump
1 parent 4ade721 commit 9c98974

File tree

5 files changed

+62
-4
lines changed

5 files changed

+62
-4
lines changed

commitizen/changelog.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,17 @@ def __post_init__(self) -> None:
7272
self.latest_version_tag = self.latest_version
7373

7474

75+
@dataclass
76+
class IncrementalMergeInfo:
77+
"""
78+
Information regarding the last non-pre-release, parsed from the changelog. Required to merge pre-releases on bump.
79+
Separate from Metadata to not mess with the interface.
80+
"""
81+
82+
name: str | None = None
83+
index: int | None = None
84+
85+
7586
def get_commit_tag(commit: GitCommit, tags: list[GitTag]) -> GitTag | None:
7687
return next((tag for tag in tags if tag.rev == commit.rev), None)
7788

@@ -86,15 +97,18 @@ def generate_tree_from_commits(
8697
changelog_message_builder_hook: MessageBuilderHook | None = None,
8798
changelog_release_hook: ChangelogReleaseHook | None = None,
8899
rules: TagRules | None = None,
100+
during_version_bump: bool = False,
89101
) -> Generator[dict[str, Any], None, None]:
90102
pat = re.compile(changelog_pattern)
91103
map_pat = re.compile(commit_parser, re.MULTILINE)
92104
body_map_pat = re.compile(commit_parser, re.MULTILINE | re.DOTALL)
93105
rules = rules or TagRules()
94106

95107
# Check if the latest commit is not tagged
96-
97-
current_tag = get_commit_tag(commits[0], tags) if commits else None
108+
if during_version_bump and rules.merge_prereleases:
109+
current_tag = None
110+
else:
111+
current_tag = get_commit_tag(commits[0], tags) if commits else None
98112
current_tag_name = unreleased_version or "Unreleased"
99113
current_tag_date = (
100114
date.today().isoformat() if unreleased_version is not None else ""

commitizen/changelog_formats/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
else:
99
import importlib_metadata as metadata
1010

11-
from commitizen.changelog import Metadata
11+
from commitizen.changelog import IncrementalMergeInfo, Metadata
1212
from commitizen.config.base_config import BaseConfig
1313
from commitizen.exceptions import ChangelogFormatUnknown
1414

@@ -48,6 +48,12 @@ def get_metadata(self, filepath: str) -> Metadata:
4848
"""
4949
raise NotImplementedError
5050

51+
def get_latest_full_release(self, filepath: str) -> IncrementalMergeInfo:
52+
"""
53+
Extract metadata for the last non-pre-release.
54+
"""
55+
raise NotImplementedError
56+
5157

5258
KNOWN_CHANGELOG_FORMATS: dict[str, type[ChangelogFormat]] = {
5359
ep.name: ep.load()

commitizen/changelog_formats/base.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
from abc import ABCMeta
55
from typing import IO, Any, ClassVar
66

7-
from commitizen.changelog import Metadata
7+
from commitizen.changelog import IncrementalMergeInfo, Metadata
88
from commitizen.config.base_config import BaseConfig
9+
from commitizen.git import GitTag
910
from commitizen.tags import TagRules, VersionTag
1011
from commitizen.version_schemes import get_version_scheme
1112

@@ -69,6 +70,27 @@ def get_metadata_from_file(self, file: IO[Any]) -> Metadata:
6970

7071
return meta
7172

73+
def get_latest_full_release(self, filepath: str) -> IncrementalMergeInfo:
74+
if not os.path.isfile(filepath):
75+
return IncrementalMergeInfo()
76+
77+
with open(
78+
filepath, encoding=self.config.settings["encoding"]
79+
) as changelog_file:
80+
return self.get_latest_full_release_from_file(changelog_file)
81+
82+
def get_latest_full_release_from_file(self, file: IO[Any]) -> IncrementalMergeInfo:
83+
for index, line in enumerate(file):
84+
line = line.strip().lower()
85+
86+
parsed = self.parse_version_from_title(line)
87+
if parsed:
88+
if not self.tag_rules.extract_version(
89+
GitTag(parsed.tag, "", "")
90+
).is_prerelease:
91+
return IncrementalMergeInfo(name=parsed.tag, index=index)
92+
return IncrementalMergeInfo()
93+
7294
def parse_version_from_title(self, line: str) -> VersionTag | None:
7395
"""
7496
Extract the version from a title line if any

commitizen/commands/bump.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ def __call__(self) -> None:
311311
"extras": self.extras,
312312
"incremental": True,
313313
"dry_run": dry_run,
314+
"during_version_bump": prerelease
315+
is None, # We let the changelog implementation know that we want to replace prereleases while staying incremental AND the new tag does not exist already
314316
}
315317
if self.changelog_to_stdout:
316318
changelog_cmd = Changelog(self.config, {**args, "dry_run": True}) # type: ignore[typeddict-item]

commitizen/commands/changelog.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class ChangelogArgs(TypedDict, total=False):
4141
template: str
4242
extras: dict[str, Any]
4343
export_template: str
44+
during_version_bump: bool | None
4445

4546

4647
class Changelog:
@@ -121,6 +122,8 @@ def __init__(self, config: BaseConfig, arguments: ChangelogArgs) -> None:
121122
self.extras = arguments.get("extras") or {}
122123
self.export_template_to = arguments.get("export_template")
123124

125+
self.during_version_bump: bool = arguments.get("during_version_bump") or False
126+
124127
def _find_incremental_rev(self, latest_version: str, tags: Iterable[GitTag]) -> str:
125128
"""Try to find the 'start_rev'.
126129
@@ -218,6 +221,16 @@ def __call__(self) -> None:
218221
self.tag_rules,
219222
)
220223

224+
if self.during_version_bump and self.tag_rules.merge_prereleases:
225+
latest_full_release_info = self.changelog_format.get_latest_full_release(
226+
self.file_name
227+
)
228+
start_rev = latest_full_release_info.name or ""
229+
if latest_full_release_info.index:
230+
changelog_meta.unreleased_start = 0
231+
changelog_meta.latest_version_position = latest_full_release_info.index
232+
changelog_meta.unreleased_end = latest_full_release_info.index - 1
233+
221234
commits = git.get_commits(start=start_rev, end=end_rev, args="--topo-order")
222235
if not commits and (
223236
self.current_version is None or not self.current_version.is_prerelease
@@ -234,6 +247,7 @@ def __call__(self) -> None:
234247
changelog_message_builder_hook=self.cz.changelog_message_builder_hook,
235248
changelog_release_hook=self.cz.changelog_release_hook,
236249
rules=self.tag_rules,
250+
during_version_bump=self.during_version_bump,
237251
)
238252
if self.change_type_order:
239253
tree = changelog.generate_ordered_changelog_tree(

0 commit comments

Comments
 (0)