Skip to content

Commit 1bad904

Browse files
fix(init): dedupe duplicate third-party provider names
Address GitHub Copilot review feedback on PR #1971: when two distributions register a third-party provider under the same name in the `commitizen.provider` entry-point group, the user previously saw two ambiguous choices in `cz init`. Track names in a `seen_names` set (seeded with the built-in names) and skip subsequent matches so each name appears at most once. The conflict is not silenced — `commitizen.providers.get_provider` already raises `VersionProviderUnknown` if more than one entry point shares the name, so the user gets a clear error if they pick the duplicated provider, instead of a confusing UI showing two identical choices that resolve the same way. Add `test_construct_version_provider_choices_dedupes_duplicate_third_party` which simulates two `EntryPoint(name="duplicated", ...)` values and asserts only one appears in the choice list. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent e4dcc5b commit 1bad904

2 files changed

Lines changed: 58 additions & 7 deletions

File tree

commitizen/commands/init.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ def _construct_version_provider_choices() -> list[questionary.Choice]:
8383
third-party providers that register themselves under the
8484
`commitizen.provider` entry-point group. Third-party providers are
8585
not loaded — only their entry-point name is used for the choice.
86+
87+
Names already registered as built-ins are skipped to avoid showing
88+
them twice (commitizen's own providers register under the same
89+
entry-point group). When two distributions register a third-party
90+
provider under the same name, the choice list deduplicates by name
91+
so the user does not see ambiguous duplicate entries; the conflict
92+
will surface with a clear error from `get_provider()` if the user
93+
actually selects that name.
8694
"""
8795
builtin_names = {
8896
option.provider_name for option in _BUILTIN_VERSION_PROVIDER_OPTIONS
@@ -91,14 +99,18 @@ def _construct_version_provider_choices() -> list[questionary.Choice]:
9199
questionary.Choice(title=option.title, value=option.provider_name)
92100
for option in _BUILTIN_VERSION_PROVIDER_OPTIONS
93101
]
94-
third_party_choices = [
95-
questionary.Choice(
96-
title=f"{ep.name}: third-party version provider",
97-
value=ep.name,
102+
third_party_choices: list[questionary.Choice] = []
103+
seen_names: set[str] = set(builtin_names)
104+
for ep in metadata.entry_points(group=PROVIDER_ENTRYPOINT):
105+
if ep.name in seen_names:
106+
continue
107+
seen_names.add(ep.name)
108+
third_party_choices.append(
109+
questionary.Choice(
110+
title=f"{ep.name}: third-party version provider",
111+
value=ep.name,
112+
)
98113
)
99-
for ep in metadata.entry_points(group=PROVIDER_ENTRYPOINT)
100-
if ep.name not in builtin_names
101-
]
102114
return [*builtin_choices, *third_party_choices]
103115

104116

tests/commands/test_init_command.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,3 +551,42 @@ def fake_entry_points(*args: Any, **kwargs: Any):
551551
# with the generic third-party suffix.
552552
assert values.count("pep621") == 1
553553
assert "pep621: third-party version provider" not in titles
554+
555+
556+
def test_construct_version_provider_choices_dedupes_duplicate_third_party(
557+
mocker: MockFixture,
558+
):
559+
"""Two distributions registering the same provider name only show once."""
560+
from commitizen.commands.init import _construct_version_provider_choices
561+
from commitizen.providers import PROVIDER_ENTRYPOINT
562+
563+
real_entry_points = metadata.entry_points
564+
565+
duplicate_eps = [
566+
metadata.EntryPoint(
567+
name="duplicated",
568+
value="dist_a.module:Provider",
569+
group=PROVIDER_ENTRYPOINT,
570+
),
571+
metadata.EntryPoint(
572+
name="duplicated",
573+
value="dist_b.module:Provider",
574+
group=PROVIDER_ENTRYPOINT,
575+
),
576+
]
577+
578+
def fake_entry_points(*args: Any, **kwargs: Any):
579+
eps = real_entry_points(*args, **kwargs)
580+
if kwargs.get("group") == PROVIDER_ENTRYPOINT:
581+
return list(eps) + duplicate_eps
582+
return eps
583+
584+
mocker.patch(
585+
"commitizen.commands.init.metadata.entry_points",
586+
side_effect=fake_entry_points,
587+
)
588+
589+
choices = _construct_version_provider_choices()
590+
values = [choice.value for choice in choices]
591+
592+
assert values.count("duplicated") == 1

0 commit comments

Comments
 (0)