refactor(mirror): enforce primary origin URL and align mirror resolution logic
Some checks failed
Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / linter-shell (push) Has been cancelled
Mark stable commit / linter-python (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled

- Resolve primary remote via RepoMirrorContext (origin → file order → config → default)
- Always set origin fetch and push URL to primary
- Add additional mirrors as extra push URLs without duplication
- Update remote provisioning and setup commands to use context-based resolution
- Adjust and extend unit tests to cover new origin/push behavior

https://chatgpt.com/share/693f4538-42d4-800f-98c2-2ec264fd2e19
This commit is contained in:
Kevin Veen-Birkenbach
2025-12-15 00:16:04 +01:00
parent 48a0d1d458
commit 1a13fcaa4e
6 changed files with 246 additions and 344 deletions

View File

@@ -1,6 +1,3 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations
import unittest
@@ -9,117 +6,61 @@ from unittest.mock import patch
from pkgmgr.actions.mirror.git_remote import (
build_default_ssh_url,
determine_primary_remote_url,
current_origin_url,
has_origin_remote,
)
from pkgmgr.actions.mirror.types import MirrorMap, Repository
from pkgmgr.actions.mirror.types import RepoMirrorContext
class TestMirrorGitRemote(unittest.TestCase):
"""
Unit tests for SSH URL and primary remote selection logic.
"""
def _ctx(self, *, file=None, config=None) -> RepoMirrorContext:
return RepoMirrorContext(
identifier="repo",
repo_dir="/tmp/repo",
config_mirrors=config or {},
file_mirrors=file or {},
)
def test_build_default_ssh_url_without_port(self) -> None:
repo: Repository = {
def test_build_default_ssh_url(self) -> None:
repo = {
"provider": "github.com",
"account": "kevinveenbirkenbach",
"repository": "package-manager",
"account": "alice",
"repository": "repo",
}
self.assertEqual(
build_default_ssh_url(repo),
"git@github.com:alice/repo.git",
)
url = build_default_ssh_url(repo)
self.assertEqual(url, "git@github.com:kevinveenbirkenbach/package-manager.git")
def test_determine_primary_prefers_origin(self) -> None:
repo = {"provider": "github.com", "account": "alice", "repository": "repo"}
ctx = self._ctx(config={"origin": "git@github.com:alice/repo.git"})
self.assertEqual(
determine_primary_remote_url(repo, ctx),
"git@github.com:alice/repo.git",
)
def test_build_default_ssh_url_with_port(self) -> None:
repo: Repository = {
"provider": "code.cymais.cloud",
"account": "kevinveenbirkenbach",
"repository": "pkgmgr",
"port": 2201,
}
def test_determine_primary_uses_file_order(self) -> None:
repo = {"provider": "github.com", "account": "alice", "repository": "repo"}
ctx = self._ctx(
file={
"first": "git@a/first.git",
"second": "git@a/second.git",
}
)
self.assertEqual(
determine_primary_remote_url(repo, ctx),
"git@a/first.git",
)
url = build_default_ssh_url(repo)
self.assertEqual(url, "ssh://git@code.cymais.cloud:2201/kevinveenbirkenbach/pkgmgr.git")
def test_determine_primary_fallback_default(self) -> None:
repo = {"provider": "github.com", "account": "alice", "repository": "repo"}
ctx = self._ctx()
self.assertEqual(
determine_primary_remote_url(repo, ctx),
"git@github.com:alice/repo.git",
)
def test_build_default_ssh_url_missing_fields_returns_none(self) -> None:
repo: Repository = {
"provider": "github.com",
"account": "kevinveenbirkenbach",
}
url = build_default_ssh_url(repo)
self.assertIsNone(url)
def test_determine_primary_remote_url_prefers_origin_in_resolved_mirrors(self) -> None:
repo: Repository = {
"provider": "github.com",
"account": "kevinveenbirkenbach",
"repository": "package-manager",
}
mirrors: MirrorMap = {
"origin": "git@github.com:kevinveenbirkenbach/package-manager.git",
"backup": "ssh://git@git.veen.world:2201/kevinveenbirkenbach/pkgmgr.git",
}
url = determine_primary_remote_url(repo, mirrors)
self.assertEqual(url, "git@github.com:kevinveenbirkenbach/package-manager.git")
def test_determine_primary_remote_url_uses_any_mirror_if_no_origin(self) -> None:
repo: Repository = {
"provider": "github.com",
"account": "kevinveenbirkenbach",
"repository": "package-manager",
}
mirrors: MirrorMap = {
"backup": "ssh://git@git.veen.world:2201/kevinveenbirkenbach/pkgmgr.git",
"mirror2": "ssh://git@code.cymais.cloud:2201/kevinveenbirkenbach/pkgmgr.git",
}
url = determine_primary_remote_url(repo, mirrors)
self.assertEqual(url, "ssh://git@git.veen.world:2201/kevinveenbirkenbach/pkgmgr.git")
def test_determine_primary_remote_url_falls_back_to_default_ssh(self) -> None:
repo: Repository = {
"provider": "github.com",
"account": "kevinveenbirkenbach",
"repository": "package-manager",
}
mirrors: MirrorMap = {}
url = determine_primary_remote_url(repo, mirrors)
self.assertEqual(url, "git@github.com:kevinveenbirkenbach/package-manager.git")
@patch("pkgmgr.actions.mirror.git_remote.run_git")
def test_current_origin_url_returns_value(self, mock_run_git) -> None:
mock_run_git.return_value = "git@github.com:alice/repo.git\n"
self.assertEqual(current_origin_url("/tmp/repo"), "git@github.com:alice/repo.git")
mock_run_git.assert_called_once_with(["remote", "get-url", "origin"], cwd="/tmp/repo")
@patch("pkgmgr.actions.mirror.git_remote.run_git")
def test_current_origin_url_returns_none_on_git_error(self, mock_run_git) -> None:
from pkgmgr.core.git import GitError
mock_run_git.side_effect = GitError("fail")
self.assertIsNone(current_origin_url("/tmp/repo"))
@patch("pkgmgr.actions.mirror.git_remote.run_git")
def test_has_origin_remote_true(self, mock_run_git) -> None:
mock_run_git.return_value = "origin\nupstream\n"
@patch("pkgmgr.actions.mirror.git_remote._safe_git_output")
def test_has_origin_remote(self, m_out) -> None:
m_out.return_value = "origin\nupstream\n"
self.assertTrue(has_origin_remote("/tmp/repo"))
mock_run_git.assert_called_once_with(["remote"], cwd="/tmp/repo")
@patch("pkgmgr.actions.mirror.git_remote.run_git")
def test_has_origin_remote_false_on_missing_remote(self, mock_run_git) -> None:
mock_run_git.return_value = "upstream\n"
self.assertFalse(has_origin_remote("/tmp/repo"))
@patch("pkgmgr.actions.mirror.git_remote.run_git")
def test_has_origin_remote_false_on_git_error(self, mock_run_git) -> None:
from pkgmgr.core.git import GitError
mock_run_git.side_effect = GitError("fail")
self.assertFalse(has_origin_remote("/tmp/repo"))
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,50 @@
from __future__ import annotations
import unittest
from unittest.mock import patch
from pkgmgr.actions.mirror.git_remote import ensure_origin_remote
from pkgmgr.actions.mirror.types import RepoMirrorContext
class TestGitRemotePrimaryPush(unittest.TestCase):
def test_origin_created_and_extra_push_added(self) -> None:
repo = {"provider": "github.com", "account": "alice", "repository": "repo"}
ctx = RepoMirrorContext(
identifier="repo",
repo_dir="/tmp/repo",
config_mirrors={},
file_mirrors={
"primary": "git@github.com:alice/repo.git",
"backup": "git@github.com:alice/repo-backup.git",
},
)
executed: list[str] = []
def fake_run(cmd: str, cwd: str, preview: bool) -> None:
executed.append(cmd)
def fake_git(args, cwd):
if args == ["remote"]:
return ""
if args == ["remote", "get-url", "--push", "--all", "origin"]:
return "git@github.com:alice/repo.git\n"
return ""
with patch("os.path.isdir", return_value=True), patch(
"pkgmgr.actions.mirror.git_remote.run_command", side_effect=fake_run
), patch(
"pkgmgr.actions.mirror.git_remote._safe_git_output", side_effect=fake_git
):
ensure_origin_remote(repo, ctx, preview=False)
self.assertEqual(
executed,
[
"git remote add origin git@github.com:alice/repo.git",
"git remote set-url origin git@github.com:alice/repo.git",
"git remote set-url --push origin git@github.com:alice/repo.git",
"git remote set-url --add --push origin git@github.com:alice/repo-backup.git",
],
)

View File

@@ -1,123 +1,101 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations
import unittest
from unittest.mock import MagicMock, PropertyMock, patch
from unittest.mock import patch
from pkgmgr.actions.mirror.setup_cmd import setup_mirrors
from pkgmgr.actions.mirror.types import RepoMirrorContext
class TestMirrorSetupCmd(unittest.TestCase):
"""
Unit tests for mirror setup orchestration (local + remote).
"""
@patch("pkgmgr.actions.mirror.setup_cmd.ensure_origin_remote")
@patch("pkgmgr.actions.mirror.setup_cmd.build_context")
def test_setup_mirrors_local_calls_ensure_origin_remote(
def _ctx(
self,
mock_build_context,
mock_ensure_origin,
) -> None:
ctx = MagicMock()
ctx.identifier = "repo-id"
ctx.repo_dir = "/tmp/repo"
ctx.config_mirrors = {}
ctx.file_mirrors = {}
type(ctx).resolved_mirrors = PropertyMock(return_value={})
mock_build_context.return_value = ctx
*,
repo_dir: str = "/tmp/repo",
resolved: dict[str, str] | None = None,
) -> RepoMirrorContext:
# RepoMirrorContext derives resolved via property (config + file)
# We feed mirrors via file_mirrors to keep insertion order realistic.
return RepoMirrorContext(
identifier="repo-id",
repo_dir=repo_dir,
config_mirrors={},
file_mirrors=resolved or {},
)
repo = {"provider": "github.com", "account": "alice", "repository": "repo"}
@patch("pkgmgr.actions.mirror.setup_cmd.build_context")
@patch("pkgmgr.actions.mirror.setup_cmd.ensure_origin_remote")
def test_setup_mirrors_local_calls_ensure_origin_remote(self, m_ensure, m_ctx) -> None:
m_ctx.return_value = self._ctx(repo_dir="/tmp/repo", resolved={"primary": "git@x/y.git"})
repos = [{"provider": "github.com", "account": "alice", "repository": "repo"}]
setup_mirrors(
selected_repos=[repo],
repositories_base_dir="/base",
all_repos=[repo],
selected_repos=repos,
repositories_base_dir="/tmp",
all_repos=repos,
preview=True,
local=True,
remote=False,
ensure_remote=False,
)
mock_ensure_origin.assert_called_once()
args, kwargs = mock_ensure_origin.call_args
self.assertEqual(args[0], repo)
self.assertEqual(kwargs.get("preview"), True)
self.assertEqual(m_ensure.call_count, 1)
args, kwargs = m_ensure.call_args
# ensure_origin_remote(repo, ctx, preview) may be positional or kw.
# Accept both to avoid coupling tests to call style.
if "preview" in kwargs:
self.assertTrue(kwargs["preview"])
else:
# args: (repo, ctx, preview)
self.assertTrue(args[2])
@patch("pkgmgr.actions.mirror.setup_cmd.ensure_remote_repository")
@patch("pkgmgr.actions.mirror.setup_cmd.probe_mirror")
@patch("pkgmgr.actions.mirror.setup_cmd.build_context")
def test_setup_mirrors_remote_provisions_when_enabled(
self,
mock_build_context,
mock_probe,
mock_ensure_remote_repository,
) -> None:
ctx = MagicMock()
ctx.identifier = "repo-id"
ctx.repo_dir = "/tmp/repo"
ctx.config_mirrors = {"origin": "git@github.com:alice/repo.git"}
ctx.file_mirrors = {}
type(ctx).resolved_mirrors = PropertyMock(return_value={"origin": "git@github.com:alice/repo.git"})
mock_build_context.return_value = ctx
mock_probe.return_value = (True, "")
repo = {"provider": "github.com", "account": "alice", "repository": "repo"}
setup_mirrors(
selected_repos=[repo],
repositories_base_dir="/base",
all_repos=[repo],
preview=False,
local=False,
remote=True,
ensure_remote=True,
)
mock_ensure_remote_repository.assert_called_once()
mock_probe.assert_called_once()
@patch("pkgmgr.actions.mirror.setup_cmd.ensure_remote_repository")
@patch("pkgmgr.actions.mirror.setup_cmd.probe_mirror")
@patch("pkgmgr.actions.mirror.setup_cmd.build_context")
def test_setup_mirrors_remote_probes_all_resolved_mirrors(
self,
mock_build_context,
mock_probe,
mock_ensure_remote_repository,
) -> None:
ctx = MagicMock()
ctx.identifier = "repo-id"
ctx.repo_dir = "/tmp/repo"
ctx.config_mirrors = {}
ctx.file_mirrors = {}
type(ctx).resolved_mirrors = PropertyMock(
return_value={
"mirror": "git@github.com:alice/repo.git",
"backup": "ssh://git@git.veen.world:2201/alice/repo.git",
}
)
mock_build_context.return_value = ctx
mock_probe.return_value = (True, "")
repo = {"provider": "github.com", "account": "alice", "repository": "repo"}
@patch("pkgmgr.actions.mirror.setup_cmd.determine_primary_remote_url")
def test_setup_mirrors_remote_no_mirrors_probes_primary(self, m_primary, m_probe, m_ctx) -> None:
m_ctx.return_value = self._ctx(repo_dir="/tmp/repo", resolved={})
m_primary.return_value = "git@github.com:alice/repo.git"
m_probe.return_value = (True, "")
repos = [{"provider": "github.com", "account": "alice", "repository": "repo"}]
setup_mirrors(
selected_repos=[repo],
repositories_base_dir="/base",
all_repos=[repo],
preview=False,
selected_repos=repos,
repositories_base_dir="/tmp",
all_repos=repos,
preview=True,
local=False,
remote=True,
ensure_remote=False,
)
mock_ensure_remote_repository.assert_not_called()
self.assertEqual(mock_probe.call_count, 2)
m_primary.assert_called()
m_probe.assert_called_with("git@github.com:alice/repo.git", "/tmp/repo")
@patch("pkgmgr.actions.mirror.setup_cmd.build_context")
@patch("pkgmgr.actions.mirror.setup_cmd.probe_mirror")
def test_setup_mirrors_remote_with_mirrors_probes_each(self, m_probe, m_ctx) -> None:
m_ctx.return_value = self._ctx(
repo_dir="/tmp/repo",
resolved={
"origin": "git@github.com:alice/repo.git",
"backup": "ssh://git@git.veen.world:2201/alice/repo.git",
},
)
m_probe.return_value = (True, "")
repos = [{"provider": "github.com", "account": "alice", "repository": "repo"}]
setup_mirrors(
selected_repos=repos,
repositories_base_dir="/tmp",
all_repos=repos,
preview=True,
local=False,
remote=True,
ensure_remote=False,
)
self.assertEqual(m_probe.call_count, 2)
if __name__ == "__main__":