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

Sign up
Appearance settings

feat(tags): enable version schemes with less than 3 components #1705

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
YazdanRa wants to merge 12 commits into commitizen-tools:master
base: master
Choose a base branch
Loading
from YazdanRa:feature/single-number-version
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
12 commits
Select commit Hold shift + click to select a range
b78e303
build: update dev dependencies
Lee-W Nov 8, 2025
8b1fad6
feat: add custom validation
benediktziegler Dec 1, 2025
8265c90
feat: Drop support for Python 3.9 as EOL reached and add Python 3.14 ...
Lee-W Nov 16, 2025
2072f8e
style: remove Python 3.9 compatible code
Lee-W Nov 16, 2025
6ad0bf1
feat(tags): enable version schemes with less than 3 components
YazdanRa Dec 12, 2025
be4ccc3
Merge branch 'v4-11-0' into feature/single-number-version
YazdanRa Dec 17, 2025
956c8fb
Merge branch 'master' into feature/single-number-version
YazdanRa Dec 29, 2025
6d94ba7
feat(tags): add support for finding latest matching tag for incomplet...
YazdanRa Dec 30, 2025
68cf533
Merge branch 'master' into feature/single-number-version
YazdanRa Dec 30, 2025
80950cd
fix: add tests for finding tags with partial versions
YazdanRa Dec 30, 2025
f91f2ac
Merge branch 'master' into feature/single-number-version
YazdanRa Jan 14, 2026
0f729c4
fix: update the unit test to comply with recent changes
YazdanRa Jan 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion commitizen/tags.py
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def normalize_tag(
version = self.scheme(version) if isinstance(version, str) else version
tag_format = tag_format or self.tag_format

major, minor, patch = version.release
major, minor, patch = (list(version.release) + [0, 0, 0])[:3]
prerelease = version.prerelease or ""

t = Template(tag_format)
Expand All @@ -245,6 +245,25 @@ def find_tag_for(
) -> GitTag | None:
"""Find the first matching tag for a given version."""
version = self.scheme(version) if isinstance(version, str) else version
release = version.release

# If the requested version is incomplete (e.g., "1.2"), try to find the latest
# matching tag that shares the provided prefix.
if len(release) < 3:
matching_versions: list[tuple[Version, GitTag]] = []
for tag in tags:
try:
tag_version = self.extract_version(tag)
except InvalidVersion:
continue
if tag_version.release[: len(release)] != release:
continue
matching_versions.append((tag_version, tag))

if matching_versions:
_, latest_tag = max(matching_versions, key=lambda vt: vt[0])
return latest_tag

possible_tags = set(self.normalize_tag(version, f) for f in self.tag_formats)
candidates = [t for t in tags if t.name in possible_tags]
if len(candidates) > 1:
Expand Down
29 changes: 29 additions & 0 deletions tests/commands/test_bump_command.py
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,8 @@ def test_bump_invalid_manual_version_raises_exception(
"0.1.1",
"0.2.0",
"1.0.0",
"1.2",
"1",
],
)
def test_bump_manual_version(util: UtilFixture, manual_version):
Expand All @@ -842,6 +844,33 @@ def test_bump_manual_version_disallows_major_version_zero(util: UtilFixture):
assert expected_error_message in str(excinfo.value)


@pytest.mark.parametrize(
"initial_version, expected_version_after_bump",
[
("1", "1.1.0"),
("1.2", "1.3.0"),
],
)
def test_bump_version_with_less_components_in_config(
tmp_commitizen_project_initial,
initial_version,
expected_version_after_bump,
util: UtilFixture,
):
tmp_commitizen_project = tmp_commitizen_project_initial(version=initial_version)
util.run_cli("bump", "--yes")

tag_exists = git.tag_exist(expected_version_after_bump)
assert tag_exists is True

for version_file in [
tmp_commitizen_project.join("__version__.py"),
tmp_commitizen_project.join("pyproject.toml"),
]:
with open(version_file) as f:
assert expected_version_after_bump in f.read()


@pytest.mark.parametrize("commit_msg", ("feat: new file", "feat(user): new file"))
def test_bump_with_pre_bump_hooks(
commit_msg, mocker: MockFixture, tmp_commitizen_project, util: UtilFixture
Expand Down
101 changes: 101 additions & 0 deletions tests/test_tags.py
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from commitizen.git import GitTag
from commitizen.tags import TagRules


def _git_tag(name: str) -> GitTag:
return GitTag(name, "rev", "2024年01月01日")


def test_find_tag_for_partial_version_returns_latest_match():
tags = [
_git_tag("1.2.0"),
_git_tag("1.2.2"),
_git_tag("1.2.1"),
_git_tag("1.3.0"),
]

rules = TagRules()

found = rules.find_tag_for(tags, "1.2")

assert found is not None
assert found.name == "1.2.2"


def test_find_tag_for_full_version_remains_exact():
tags = [
_git_tag("1.2.0"),
_git_tag("1.2.2"),
_git_tag("1.2.1"),
]

rules = TagRules()

found = rules.find_tag_for(tags, "1.2.1")

assert found is not None
assert found.name == "1.2.1"


def test_find_tag_for_partial_version_with_prereleases_prefers_latest_version():
tags = [
_git_tag("1.2.0b1"),
_git_tag("1.2.0"),
_git_tag("1.2.1b1"),
]

rules = TagRules()

found = rules.find_tag_for(tags, "1.2")

assert found is not None
# 1.2.1b1 > 1.2.0 so it should be selected
assert found.name == "1.2.1b1"


def test_find_tag_for_partial_version_respects_tag_format():
tags = [
_git_tag("v1.2.0"),
_git_tag("v1.2.1"),
_git_tag("v1.3.0"),
]

rules = TagRules(tag_format="v$version")

found = rules.find_tag_for(tags, "1.2")

assert found is not None
assert found.name == "v1.2.1"

found = rules.find_tag_for(tags, "1")

assert found is not None
assert found.name == "v1.3.0"


def test_find_tag_for_partial_version_returns_none_when_no_match():
tags = [
_git_tag("2.0.0"),
_git_tag("2.1.0"),
]

rules = TagRules()

found = rules.find_tag_for(tags, "1.2")

assert found is None


def test_find_tag_for_partial_version_ignores_invalid_tags():
tags = [
_git_tag("not-a-version"),
_git_tag("1.2.0"),
_git_tag("1.2.1"),
]

rules = TagRules()

found = rules.find_tag_for(tags, "1.2")

assert found is not None
assert found.name == "1.2.1"

AltStyle によって変換されたページ (->オリジナル) /