mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-16 16:33:27 -05:00
fix: resolve forgejo date pins by walking history
This commit is contained in:
1 parent
7744c21b65
commit
3c04a29d50
2 files changed
+92
-1
No files matched your search
+51
-1
@@ -18,6 +18,7 @@ import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
USER_AGENT = "retrobios-profile-sync/1.0"
|
||||
@@ -388,7 +389,56 @@ def resolve_commit_at(
|
||||
branch: str | None = None,
|
||||
) -> str | None:
|
||||
"""Last commit on or before a date, on the default branch or a named one."""
|
||||
return _first_sha(_api(_commits_url(repo, date, branch), cache_dir, offline))
|
||||
if repo.family in ("github", "gitlab"):
|
||||
return _first_sha(_api(_commits_url(repo, date, branch), cache_dir, offline))
|
||||
return _gitea_commit_at(repo, date, cache_dir, offline, branch)
|
||||
|
||||
|
||||
# Gitea and Forgejo serve 50 commits a page at most.
|
||||
GITEA_PAGE = 50
|
||||
|
||||
|
||||
def _gitea_commit_at(
|
||||
repo: Repo, date: str, cache_dir: str, offline: bool,
|
||||
branch: str | None,
|
||||
) -> str | None:
|
||||
"""Walk the history newest first to the first commit dated by the cutoff.
|
||||
|
||||
The Gitea and Forgejo commits API ignores ``until`` and answers with the
|
||||
tip: gam4980's profiled_date of 2026-03-23 resolved to a commit of July,
|
||||
a revision the profile never read.
|
||||
"""
|
||||
cutoff = datetime.fromisoformat(f"{date}T23:59:59+00:00")
|
||||
base = (
|
||||
f"{repo.api_base}/repos/{repo.slug}/commits?limit={GITEA_PAGE}"
|
||||
"&stat=false&verification=false&files=false"
|
||||
)
|
||||
if branch:
|
||||
base += f"&sha={urllib.parse.quote(branch, safe='')}"
|
||||
page = 1
|
||||
while True:
|
||||
payload = _api(f"{base}&page={page}", cache_dir, offline, MOVING_TTL)
|
||||
if not isinstance(payload, list) or not payload:
|
||||
return None
|
||||
for entry in payload:
|
||||
stamp = _gitea_commit_date(entry)
|
||||
if stamp is not None and stamp <= cutoff:
|
||||
return entry.get("sha")
|
||||
page += 1
|
||||
|
||||
|
||||
def _gitea_commit_date(entry: object) -> datetime | None:
|
||||
if not isinstance(entry, dict):
|
||||
return None
|
||||
commit = entry.get("commit")
|
||||
committer = commit.get("committer") if isinstance(commit, dict) else None
|
||||
raw = committer.get("date") if isinstance(committer, dict) else None
|
||||
if not isinstance(raw, str):
|
||||
return None
|
||||
try:
|
||||
return datetime.fromisoformat(raw.replace("Z", "+00:00"))
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def _tags_url(repo: Repo) -> str:
|
||||
|
||||
@@ -648,5 +648,46 @@ class TestGitlabTree(unittest.TestCase):
|
||||
self.assertTrue(truncated)
|
||||
|
||||
|
||||
class TestGiteaCommitAt(unittest.TestCase):
|
||||
"""Gitea and Forgejo ignore `until` and answer with the tip: the date
|
||||
pin of a Codeberg view was the tip of the day of the first fetch."""
|
||||
|
||||
PAGES = {
|
||||
1: [{"sha": f"t{i}", "commit": {"committer": {"date": "2026-07-04T10:00:00+02:00"}}}
|
||||
for i in range(50)],
|
||||
2: [
|
||||
{"sha": "late", "commit": {"committer": {"date": "2026-03-24T05:00:00+02:00"}}},
|
||||
{"sha": "pin", "commit": {"committer": {"date": "2026-03-17T19:49:15+08:00"}}},
|
||||
],
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.tmp.cleanup)
|
||||
self.urls: list[str] = []
|
||||
original = upstream._http_json
|
||||
|
||||
def fake(url):
|
||||
self.urls.append(url)
|
||||
self.assertNotIn("until=", url)
|
||||
page = int(url.rsplit("page=", 1)[1])
|
||||
return self.PAGES.get(page, [])
|
||||
|
||||
upstream._http_json = fake
|
||||
self.addCleanup(setattr, upstream, "_http_json", original)
|
||||
|
||||
def test_the_first_commit_by_the_cutoff(self):
|
||||
repo = parse_repo("https://codeberg.org/iyzsong/gam4980")
|
||||
sha = upstream.resolve_commit_at(repo, "2026-03-23", self.tmp.name)
|
||||
self.assertEqual(sha, "pin")
|
||||
self.assertEqual(len(self.urls), 2)
|
||||
|
||||
def test_a_date_before_the_history_resolves_nothing(self):
|
||||
repo = parse_repo("https://codeberg.org/iyzsong/gam4980")
|
||||
self.assertIsNone(
|
||||
upstream.resolve_commit_at(repo, "2020-01-01", self.tmp.name)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user