fix: ask again for a tip older than the pin

A branch tip is cached for six hours. scummvm-standalone was pinned on
6f7b060d while the cache still held 77d80d7, its ancestor, so profile_sync
showed a HEAD behind the pin and a bump would have moved it backwards. A
tip that is a strict ancestor of the pin is now asked for again.
This commit is contained in:
Abdessamad Derraz committed 2026-10-24 02:00:21 +02:00
1 parent fecfa6be4f
commit fa7977d2c3
3 files changed
+33 -4

No files matched your search

+7
View File
@@ -1141,6 +1141,13 @@ def select_views(
continue continue
if not head: if not head:
continue continue
if head != pin and not offline:
# A tip cached before the pin was written is older than the pin:
# scummvm-standalone pinned 6f7b060d while the cache still held
# 77d80d7, and a bump would have moved the pin backwards.
relation = upstream.ancestry(repo, pin, head, cache_dir, offline)
if relation and relation[0] == 0 and relation[1] > 0:
head = upstream.resolve_head(repo, cache_dir, offline, branch, fresh=True) or head
seen.add((repo.host, repo.slug)) seen.add((repo.host, repo.slug))
views.append(RepoView(repo, pin, head, origin, field)) views.append(RepoView(repo, pin, head, origin, field))
if gone and not views: if gone and not views:
+5 -3
View File
@@ -527,16 +527,18 @@ def current_slug(repo: Repo, cache_dir: str, offline: bool = False) -> str | Non
def resolve_head( def resolve_head(
repo: Repo, cache_dir: str, offline: bool = False, branch: str | None = None repo: Repo, cache_dir: str, offline: bool = False, branch: str | None = None,
fresh: bool = False,
) -> str | None: ) -> str | None:
"""Sha of a branch tip, the default branch unless one is named. """Sha of a branch tip, the default branch unless one is named.
A libretro port often lives on a branch of a fork rather than on the A libretro port often lives on a branch of a fork rather than on the
default branch, so the code a profile documents can be absent from the default branch, so the code a profile documents can be absent from the
tip the forge serves by default. tip the forge serves by default. ``fresh`` asks the forge again whatever
the cache holds.
""" """
return _first_sha( return _first_sha(
_api(_commits_url(repo, None, branch), cache_dir, offline, MOVING_TTL) _api(_commits_url(repo, None, branch), cache_dir, offline, 0 if fresh else MOVING_TTL)
) )
+21 -1
View File
@@ -1182,7 +1182,10 @@ class TestBuildReport(unittest.TestCase):
profile_sync.upstream.list_gitlinks, profile_sync.upstream.list_gitlinks,
profile_sync.upstream.current_slug, profile_sync.upstream.current_slug,
profile_sync.upstream.fork_base, profile_sync.upstream.fork_base,
profile_sync.upstream.ancestry,
) )
# Pin and tip are unrelated shas in these fixtures: no ancestry.
profile_sync.upstream.ancestry = lambda *a, **k: None
self.fork_bases: dict[str, str] = {} self.fork_bases: dict[str, str] = {}
profile_sync.upstream.fork_base = ( profile_sync.upstream.fork_base = (
lambda repo, sha, fork, fork_sha, cache_dir, offline=False: lambda repo, sha, fork, fork_sha, cache_dir, offline=False:
@@ -1226,7 +1229,7 @@ class TestBuildReport(unittest.TestCase):
) )
) )
profile_sync.upstream.resolve_head = ( profile_sync.upstream.resolve_head = (
lambda repo, cache_dir, offline=False, branch=None: "headsha" lambda repo, cache_dir, offline=False, branch=None, fresh=False: "headsha"
) )
profile_sync.upstream.resolve_commit_at = ( profile_sync.upstream.resolve_commit_at = (
lambda repo, date, cache_dir, offline=False, branch=None: "pinsha" lambda repo, date, cache_dir, offline=False, branch=None: "pinsha"
@@ -1250,6 +1253,7 @@ class TestBuildReport(unittest.TestCase):
profile_sync.upstream.list_gitlinks, profile_sync.upstream.list_gitlinks,
profile_sync.upstream.current_slug, profile_sync.upstream.current_slug,
profile_sync.upstream.fork_base, profile_sync.upstream.fork_base,
profile_sync.upstream.ancestry,
) = self._orig ) = self._orig
self.tmp.cleanup() self.tmp.cleanup()
@@ -5034,6 +5038,22 @@ class UpstreamForkedByThePort(unittest.TestCase):
self.assertEqual(views[1].head, "up-tip") self.assertEqual(views[1].head, "up-tip")
class ACachedTipOlderThanThePin(TestBuildReport):
"""scummvm-standalone was pinned on 6f7b060d while the cached tip was
77d80d7, its ancestor: a bump would have moved the pin backwards."""
def test_the_tip_is_asked_again(self):
profile_sync.upstream.ancestry = lambda *a, **k: (0, 3)
profile_sync.upstream.resolve_head = (
lambda repo, cache_dir, offline=False, branch=None, fresh=False:
"newtip" if fresh else "staletip"
)
self.files[("pinsha", "a.c")] = ["x", "hit"]
self.files[("newtip", "a.c")] = ["x", "hit"]
report = build_report("test", self._profile(["a.c:2"]), self.dir)
self.assertEqual(report.head, "newtip")
class OfflineCacheMissIsNotGone(TestBuildReport): class OfflineCacheMissIsNotGone(TestBuildReport):
"""Offline, a file the cache never stored came back as None and the """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 report read "GONE (absent at HEAD, no rename found)" for files that