Skip to content

Commit 9751140

Browse files
mnriemCopilot
andcommitted
fix: prioritize bundle catalog URL matches
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 43d16dc commit 9751140

2 files changed

Lines changed: 44 additions & 6 deletions

File tree

‎src/specify_cli/bundles/catalog_config.py‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,22 +196,26 @@ def add_source(
196196
},
197197
Scope.PROJECT,
198198
)
199+
id_collision = False
199200
for existing in catalogs:
200201
existing_source = CatalogSource.from_dict(existing, Scope.PROJECT)
201-
if (
202-
existing_source.id == requested_source.id
203-
or existing_source.url == requested_source.url
204-
):
202+
if existing_source.url == requested_source.url:
205203
if (
206-
existing_source.url == requested_source.url
207-
and (not requested_id or existing_source.id == requested_source.id)
204+
(not requested_id or existing_source.id == requested_source.id)
208205
and existing_source.priority == requested_source.priority
209206
and existing_source.install_policy is requested_source.install_policy
210207
):
211208
return existing_source, "unchanged"
212209
raise BundlerError(
213210
f"Catalog source '{resolved_id}' (or url) already exists in this project."
214211
)
212+
if existing_source.id == requested_source.id:
213+
id_collision = True
214+
215+
if id_collision:
216+
raise BundlerError(
217+
f"Catalog source '{resolved_id}' (or url) already exists in this project."
218+
)
215219

216220
entry = requested_source.to_dict()
217221
catalogs.append(entry)

‎tests/specify_cli/bundles/test_catalog_config.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,40 @@ def test_add_source_uses_existing_id_when_id_is_omitted(tmp_path: Path):
153153
assert second == first
154154

155155

156+
def test_add_source_prefers_url_match_over_derived_id_collision(tmp_path: Path):
157+
project = tmp_path / "proj"
158+
(project / ".specify").mkdir(parents=True)
159+
cc._write(
160+
project,
161+
[
162+
{
163+
"id": "example-com-target",
164+
"url": "https://other.example/catalog.json",
165+
"priority": 50,
166+
"install_policy": "install-allowed",
167+
},
168+
{
169+
"id": "custom",
170+
"url": "https://example.com/target.json",
171+
"priority": 50,
172+
"install_policy": "install-allowed",
173+
},
174+
],
175+
)
176+
original = cc._config_path(project).read_bytes()
177+
178+
source, status = cc.add_source(
179+
project,
180+
"https://example.com/target.json",
181+
policy="install-allowed",
182+
priority=50,
183+
)
184+
185+
assert status == "unchanged"
186+
assert source.id == "custom"
187+
assert cc._config_path(project).read_bytes() == original
188+
189+
156190
def test_remove_source_accepts_relative_local_path(tmp_path: Path, monkeypatch):
157191
"""add_source stores a local path as an absolute url, so remove_source must
158192
accept the same relative path the caller added; otherwise `remove ./cat.json`

0 commit comments

Comments
 (0)