diff --git a/commitizen/providers/scm_provider.py b/commitizen/providers/scm_provider.py index 687775da30..e9bc20e9db 100644 --- a/commitizen/providers/scm_provider.py +++ b/commitizen/providers/scm_provider.py @@ -18,7 +18,13 @@ def get_version(self) -> str: rules = TagRules.from_settings(self.config.settings) tags = get_tags(reachable_only=True) version_tags = rules.get_version_tags(tags) - version = max((rules.extract_version(t) for t in version_tags), default=None) + # Floating tags (e.g. `v1.0` next to `v1.0.0`) compare equal. Among equal + # versions, prefer the most specific (longest) spelling. + version = max( + (rules.extract_version(t) for t in version_tags), + key=lambda v: (v, len(str(v))), + default=None, + ) return str(version) if version is not None else "0.0.0" def set_version(self, version: str) -> None: diff --git a/tests/providers/test_scm_provider.py b/tests/providers/test_scm_provider.py index d3f0299f47..ef4451fb7c 100644 --- a/tests/providers/test_scm_provider.py +++ b/tests/providers/test_scm_provider.py @@ -140,3 +140,23 @@ def test_scm_provider_detect_legacy_tags(config: BaseConfig, util: UtilFixture): util.create_file_and_commit("test: fake commit") util.create_tag("v0.5.0") assert provider.get_version() == "0.5.0" + + +@pytest.mark.usefixtures("tmp_git_project") +def test_scm_provider_prefers_full_version_over_floating_tags( + config: BaseConfig, util: UtilFixture +): + """Floating tags (`v1.0`, `v1`) must not hide the full `v1.0.0` version.""" + # Arrange + util.create_file_and_commit("feat: initial commit") + util.create_tag("v1.0.0") + util.create_tag("v1.0") + util.create_tag("v1") + config.settings["version_provider"] = "scm" + config.settings["tag_format"] = "v$version" + + # Act + provider = get_provider(config) + + # Assert + assert provider.get_version() == "1.0.0"