From a7f64063d60aee38349f62c1e63f5290dca7323b Mon Sep 17 00:00:00 2001 From: Yu-Ting Hsiung Date: Thu, 12 Jun 2025 16:31:42 +0800 Subject: [PATCH 1/2] refactor(changelog): simplify logic for get_oldest_and_newest_rev --- commitizen/changelog.py | 45 ++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index ba6fbbc6b..c7e965a79 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -318,39 +318,28 @@ def get_oldest_and_newest_rev( - `0.1.0..0.4.0`: as a range - `0.3.0`: as a single version """ - oldest: str | None = None - newest: str | None = None - try: - oldest, newest = version.split("..") - except ValueError: - newest = version - if not (newest_tag := rules.find_tag_for(tags, newest)): + oldest_version, sep, newest_version = version.partition("..") + if not sep: + newest_version = version + oldest_version = "" + + def get_tag_name(v: str) -> str: + if tag := rules.find_tag_for(tags, v): + return tag.name raise NoCommitsFoundError("Could not find a valid revision range.") - oldest_tag = None - oldest_tag_name = None - if oldest: - if not (oldest_tag := rules.find_tag_for(tags, oldest)): - raise NoCommitsFoundError("Could not find a valid revision range.") - oldest_tag_name = oldest_tag.name + newest_tag_name = get_tag_name(newest_version) + oldest_tag_name = get_tag_name(oldest_version) if oldest_version else None - tags_range = get_smart_tag_range( - tags, newest=newest_tag.name, oldest=oldest_tag_name - ) + tags_range = get_smart_tag_range(tags, newest_tag_name, oldest_tag_name) if not tags_range: raise NoCommitsFoundError("Could not find a valid revision range.") oldest_rev: str | None = tags_range[-1].name - newest_rev = newest_tag.name - - # check if it's the first tag created - # and it's also being requested as part of the range - if oldest_rev == tags[-1].name and oldest_rev == oldest_tag_name: - return None, newest_rev - - # when they are the same, and it's also the - # first tag created - if oldest_rev == newest_rev: - return None, newest_rev - return oldest_rev, newest_rev + # Return None for oldest_rev if: + # 1. The oldest tag is the last tag in the list and matches the requested oldest tag + # 2. The oldest and the newest tag are the same + if oldest_rev == oldest_tag_name == tags[-1].name or oldest_rev == newest_tag_name: + oldest_rev = None + return oldest_rev, newest_tag_name From 1d9f4abacb8885aec5d4c31e68bcdf194a1368f2 Mon Sep 17 00:00:00 2001 From: Yu-Ting Hsiung Date: Thu, 12 Jun 2025 21:24:30 +0800 Subject: [PATCH 2/2] refactor(changelog): add get_next_tag_name_after_version and test, mark unused for get_smart_tag_range --- commitizen/changelog.py | 25 +++++++++++++++++-------- tests/test_changelog.py | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index c7e965a79..4920b75a5 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -32,6 +32,7 @@ from collections.abc import Generator, Iterable, Mapping, Sequence from dataclasses import dataclass from datetime import date +from itertools import chain, tee from typing import TYPE_CHECKING, Any from jinja2 import ( @@ -281,6 +282,16 @@ def incremental_build( return output_lines +def get_next_tag_name_after_version(tags: Iterable[GitTag], version: str) -> str | None: + a, b = tee(chain((tag.name for tag in tags), [None])) + next(b, None) + try: + return next(y for x, y in zip(a, b) if x == version) + except StopIteration: + raise NoCommitsFoundError(f"Could not find a valid revision range. {version=}") + + +# TODO: unused, deprecate this? def get_smart_tag_range( tags: Sequence[GitTag], newest: str, oldest: str | None = None ) -> list[GitTag]: @@ -308,7 +319,7 @@ def get_smart_tag_range( def get_oldest_and_newest_rev( - tags: Sequence[GitTag], + tags: Iterable[GitTag], version: str, rules: TagRules, ) -> tuple[str | None, str]: @@ -331,15 +342,13 @@ def get_tag_name(v: str) -> str: newest_tag_name = get_tag_name(newest_version) oldest_tag_name = get_tag_name(oldest_version) if oldest_version else None - tags_range = get_smart_tag_range(tags, newest_tag_name, oldest_tag_name) - if not tags_range: - raise NoCommitsFoundError("Could not find a valid revision range.") - - oldest_rev: str | None = tags_range[-1].name + oldest_rev = get_next_tag_name_after_version( + tags, oldest_tag_name or newest_tag_name + ) # Return None for oldest_rev if: # 1. The oldest tag is the last tag in the list and matches the requested oldest tag # 2. The oldest and the newest tag are the same - if oldest_rev == oldest_tag_name == tags[-1].name or oldest_rev == newest_tag_name: - oldest_rev = None + if oldest_rev == newest_tag_name: + return None, newest_tag_name return oldest_rev, newest_tag_name diff --git a/tests/test_changelog.py b/tests/test_changelog.py index ed90ed08e..4465fcccb 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -1535,6 +1535,24 @@ def test_get_smart_tag_range_returns_an_extra_for_a_single_tag(tags): assert 2 == len(res) +def test_get_next_tag_name_after_version(tags): + # Test finding next tag after a version + next_tag_name = changelog.get_next_tag_name_after_version(tags, "v1.2.0") + assert next_tag_name == "v1.1.1" + + next_tag_name = changelog.get_next_tag_name_after_version(tags, "v1.1.0") + assert next_tag_name == "v1.0.0" + + # Test finding last tag when given version is last + last_tag_name = changelog.get_next_tag_name_after_version(tags, "v0.9.1") + assert last_tag_name is None + + # Test error when version not found + with pytest.raises(changelog.NoCommitsFoundError) as exc_info: + changelog.get_next_tag_name_after_version(tags, "nonexistent") + assert "Could not find a valid revision range" in str(exc_info.value) + + @dataclass class TagDef: name: str