mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-26 05:37:20 -05:00
feat: follow a fork's base as its upstream head
For a port that is a GitHub fork of its upstream, the upstream code it carries is the merge base of the two, not upstream's HEAD. The bump moved upstream_commit to upstream HEAD on snes9x, kronos, np2kai and others whose pin was that base. The upstream view's head is now the merge base GitHub's compare names, the way _follow_submodule already reads a vendored submodule. Outside a fork network the HEAD stays.
This commit is contained in:
1 parent
01a6daf653
commit
861b89dd44
4 files changed
+116
-1
No files matched your search
+29
-1
@@ -1104,7 +1104,7 @@ def select_views(
|
||||
continue
|
||||
seen.add((repo.host, repo.slug))
|
||||
views.append(RepoView(repo, pin, head, origin, field))
|
||||
return _follow_submodule(views, cache_dir, offline)
|
||||
return _follow_fork_base(_follow_submodule(views, cache_dir, offline), cache_dir, offline)
|
||||
|
||||
|
||||
def _follow_submodule(
|
||||
@@ -1144,6 +1144,34 @@ def _follow_submodule(
|
||||
return followed
|
||||
|
||||
|
||||
def _follow_fork_base(
|
||||
views: list[RepoView], cache_dir: str, offline: bool
|
||||
) -> list[RepoView]:
|
||||
"""An upstream the port is a fork of moves with what the port merged.
|
||||
|
||||
snes9x, kronos, np2kai and six others pinned upstream_commit on the merge
|
||||
base of upstream with the fork, the upstream code the port carries. Read
|
||||
against upstream's own HEAD, the bump moved it past anything the port
|
||||
built from. Outside one fork network the HEAD stays the reference.
|
||||
"""
|
||||
source = next((v for v in views if v.field == "source"), None)
|
||||
if source is None:
|
||||
return views
|
||||
followed: list[RepoView] = []
|
||||
for view in views:
|
||||
if view.field != "upstream" or view.pin == view.head or " via " in view.origin:
|
||||
followed.append(view)
|
||||
continue
|
||||
base = upstream.fork_base(
|
||||
view.repo, view.head, source.repo, source.head, cache_dir, offline
|
||||
)
|
||||
followed.append(
|
||||
replace(view, head=base, origin=f"{view.origin}, fork base of {source.repo.slug}")
|
||||
if base else view
|
||||
)
|
||||
return followed
|
||||
|
||||
|
||||
def declared_repositories(profile: dict) -> list[tuple[str, str, str]]:
|
||||
"""Every repository URL the profile declares, source before upstream.
|
||||
|
||||
|
||||
@@ -840,6 +840,26 @@ def _commits_ahead(payload: object, family: str) -> int | None:
|
||||
return value if isinstance(value, int) else None
|
||||
|
||||
|
||||
def fork_base(
|
||||
repo: Repo, sha: str, fork: Repo, fork_sha: str, cache_dir: str,
|
||||
offline: bool = False,
|
||||
) -> str | None:
|
||||
"""The commit of ``repo`` that ``fork`` at ``fork_sha`` has merged up to.
|
||||
|
||||
GitHub compares across a fork network and names the merge base. Two
|
||||
repositories outside one network answer 404, and None is returned.
|
||||
"""
|
||||
if repo.family != "github" or fork.family != "github":
|
||||
return None
|
||||
payload = _api(
|
||||
f"{repo.api_base}/repos/{repo.slug}/compare/"
|
||||
f"{sha}...{fork.owner}:{fork.name}:{fork_sha}",
|
||||
cache_dir, offline,
|
||||
)
|
||||
base = payload.get("merge_base_commit") if isinstance(payload, dict) else None
|
||||
return base.get("sha") if isinstance(base, dict) else None
|
||||
|
||||
|
||||
def ancestry(
|
||||
repo: Repo, base: str, head: str, cache_dir: str, offline: bool = False
|
||||
) -> tuple[int, int] | None:
|
||||
|
||||
@@ -1181,6 +1181,12 @@ class TestBuildReport(unittest.TestCase):
|
||||
profile_sync.upstream._http_text,
|
||||
profile_sync.upstream.list_gitlinks,
|
||||
profile_sync.upstream.current_slug,
|
||||
profile_sync.upstream.fork_base,
|
||||
)
|
||||
self.fork_bases: dict[str, str] = {}
|
||||
profile_sync.upstream.fork_base = (
|
||||
lambda repo, sha, fork, fork_sha, cache_dir, offline=False:
|
||||
self.fork_bases.get(fork_sha)
|
||||
)
|
||||
self.current_slugs: dict[str, str] = {}
|
||||
profile_sync.upstream.current_slug = (
|
||||
@@ -1243,6 +1249,7 @@ class TestBuildReport(unittest.TestCase):
|
||||
profile_sync.upstream._http_text,
|
||||
profile_sync.upstream.list_gitlinks,
|
||||
profile_sync.upstream.current_slug,
|
||||
profile_sync.upstream.fork_base,
|
||||
) = self._orig
|
||||
self.tmp.cleanup()
|
||||
|
||||
@@ -4789,6 +4796,39 @@ class UpstreamVendoredAsASubmodule(unittest.TestCase):
|
||||
self.assertEqual(views[1].head, "nesbox-tip")
|
||||
|
||||
|
||||
class UpstreamForkedByThePort(unittest.TestCase):
|
||||
"""snes9x, kronos and np2kai pinned upstream_commit on the merge base of
|
||||
upstream with the fork. Compared to upstream's own HEAD, a bump moved it
|
||||
past anything the port carries."""
|
||||
|
||||
def _views(self, base):
|
||||
from unittest import mock # noqa: PLC0415
|
||||
|
||||
fork = profile_sync.upstream.make_repo("github.com", "f", "port")
|
||||
self.up = profile_sync.upstream.make_repo("github.com", "o", "up")
|
||||
self.fork = fork
|
||||
views = [
|
||||
profile_sync.RepoView(fork, "src-pin", "src-head", "source_commit", "source"),
|
||||
profile_sync.RepoView(self.up, "old-base", "up-tip", "upstream_commit", "upstream"),
|
||||
]
|
||||
with mock.patch.object(
|
||||
profile_sync.upstream, "fork_base", return_value=base
|
||||
) as asked:
|
||||
followed = profile_sync._follow_fork_base(views, "cache", True)
|
||||
return followed, asked
|
||||
|
||||
def test_the_upstream_head_is_the_fork_base(self):
|
||||
views, asked = self._views("new-base")
|
||||
self.assertEqual(views[1].head, "new-base")
|
||||
self.assertEqual(
|
||||
asked.call_args.args[:4], (self.up, "up-tip", self.fork, "src-head")
|
||||
)
|
||||
|
||||
def test_a_port_outside_the_network_keeps_the_tip(self):
|
||||
views, _ = self._views(None)
|
||||
self.assertEqual(views[1].head, "up-tip")
|
||||
|
||||
|
||||
class OfflineCacheMissIsNotGone(TestBuildReport):
|
||||
"""Offline, a file the cache never stored came back as None and the
|
||||
report read "GONE (absent at HEAD, no rename found)" for files that
|
||||
|
||||
@@ -957,5 +957,32 @@ class TestNamedTagCommit(unittest.TestCase):
|
||||
self.assertEqual(upstream.tag_commit(repo, "1.2.35", self.tmp.name), "c74fc36")
|
||||
self.assertTrue(asked[0].endswith("/repository/tags/1.2.35"))
|
||||
|
||||
|
||||
class TestForkBase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory()
|
||||
self.saved = upstream._http_json
|
||||
|
||||
def tearDown(self):
|
||||
upstream._http_json = self.saved
|
||||
self.tmp.cleanup()
|
||||
|
||||
def test_the_merge_base_github_names(self):
|
||||
asked = []
|
||||
|
||||
def answer(url):
|
||||
asked.append(url)
|
||||
return {"merge_base_commit": {"sha": "base"}, "status": "diverged"}
|
||||
|
||||
upstream._http_json = answer
|
||||
up, fork = make_repo("github.com", "o", "up"), make_repo("github.com", "f", "port")
|
||||
self.assertEqual(upstream.fork_base(up, "tip", fork, "head", self.tmp.name), "base")
|
||||
self.assertTrue(asked[0].endswith("/repos/o/up/compare/tip...f:port:head"))
|
||||
|
||||
def test_no_network_is_none(self):
|
||||
upstream._http_json = lambda url: None
|
||||
up, fork = make_repo("github.com", "o", "up"), make_repo("github.com", "f", "port")
|
||||
self.assertIsNone(upstream.fork_base(up, "tip", fork, "head", self.tmp.name))
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user