fix(manifest): avoid KeyError when override bottle has repos absent from base
merge_bottles_runtime used .get(n, base_repos_by_name[n]) which eagerly evaluates the default, crashing when a repo exists only in the override bottle. Replaced with a conditional expression so the base lookup only runs when needed. Adds three regression tests covering override-only, base-only, and name-collision cases. Closes #457 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -57,7 +57,7 @@ def _merge_two_bottles_runtime(base: "ManifestBottle", override: "ManifestBottle
|
|||||||
n for n in override_repos_by_name if n not in base_repos_by_name
|
n for n in override_repos_by_name if n not in base_repos_by_name
|
||||||
]
|
]
|
||||||
merged_git = tuple(
|
merged_git = tuple(
|
||||||
override_repos_by_name.get(n, base_repos_by_name[n])
|
override_repos_by_name[n] if n in override_repos_by_name else base_repos_by_name[n]
|
||||||
for n in merged_repos_names
|
for n in merged_repos_names
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,30 @@ class TestMergeBottlesRuntime(unittest.TestCase):
|
|||||||
self.assertEqual("2", result.env["B"])
|
self.assertEqual("2", result.env["B"])
|
||||||
self.assertEqual("3", result.env["C"])
|
self.assertEqual("3", result.env["C"])
|
||||||
|
|
||||||
|
def test_git_repo_only_in_override_does_not_raise(self):
|
||||||
|
# Regression for issue #457: override bottle declares a repo that the
|
||||||
|
# base doesn't have → KeyError on base_repos_by_name[n].
|
||||||
|
_repo = lambda url: {"url": url, "key": {"provider": "gitea", "forge_token_env": "TOK"}}
|
||||||
|
base = _bottle(env={"X": "base"})
|
||||||
|
override = _bottle(**{"git-gate": {"repos": {"myrepo": _repo("ssh://git@example.com/repo.git")}}})
|
||||||
|
result = merge_bottles_runtime([base, override])
|
||||||
|
self.assertIn("myrepo", [e.Name for e in result.git])
|
||||||
|
|
||||||
|
def test_git_repo_only_in_base_survives_override(self):
|
||||||
|
_repo = lambda url: {"url": url, "key": {"provider": "gitea", "forge_token_env": "TOK"}}
|
||||||
|
base = _bottle(**{"git-gate": {"repos": {"myrepo": _repo("ssh://git@example.com/repo.git")}}})
|
||||||
|
override = _bottle(env={"X": "override"})
|
||||||
|
result = merge_bottles_runtime([base, override])
|
||||||
|
self.assertIn("myrepo", [e.Name for e in result.git])
|
||||||
|
|
||||||
|
def test_git_repo_override_wins_by_name(self):
|
||||||
|
_repo = lambda url: {"url": url, "key": {"provider": "gitea", "forge_token_env": "TOK"}}
|
||||||
|
base = _bottle(**{"git-gate": {"repos": {"myrepo": _repo("ssh://git@base.example.com/repo.git")}}})
|
||||||
|
override = _bottle(**{"git-gate": {"repos": {"myrepo": _repo("ssh://git@override.example.com/repo.git")}}})
|
||||||
|
result = merge_bottles_runtime([base, override])
|
||||||
|
self.assertEqual(1, len(result.git))
|
||||||
|
self.assertEqual("ssh://git@override.example.com/repo.git", result.git[0].Upstream)
|
||||||
|
|
||||||
def test_empty_list_raises(self):
|
def test_empty_list_raises(self):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
merge_bottles_runtime([])
|
merge_bottles_runtime([])
|
||||||
|
|||||||
Reference in New Issue
Block a user