feat: place the pin against its version tag

--check-version said only that core_version names a tag other than the
pin. It now counts the pin against that tag (after it, before it, or off
its history), and names the latest release when the pin already contains
it. Of 52 warnings, 43 are builds between releases; ares, boytacean,
nesoid and primehack name an older release than their code, vkquake and
vkquake2 a later one.
This commit is contained in:
Abdessamad Derraz committed 2026-10-23 15:24:21 +02:00
1 parent d458cf653a
commit a293887145
3 files changed
+156 -5

No files matched your search

+72 -5
View File
@@ -2216,15 +2216,41 @@ def page_version(profile: dict, cache_dir: str, offline: bool) -> str | None:
return match.group(1) if match else None
def version_warning(report: VersionReport | None, pin: str | None) -> str | None:
"""Flag a declared version that names a tag away from the resolved pin."""
def version_warning(
report: VersionReport | None,
pin: str | None,
relation: tuple[int, int] | None = None,
passed_release: str | None = None,
) -> str | None:
"""Flag a declared version that names a tag away from the resolved pin.
``relation`` is the pin's (ahead, behind) count against the tag commit.
A pin after its tag is a build between two releases; a pin before it
describes code the declared release had already replaced.
``passed_release`` is a later release the pin already contains, which
core_version should name instead.
"""
if report is None or not report.tag_commit or not pin:
return None
if report.tag_commit == pin:
if report.tag_commit == pin and not passed_release:
return None
if passed_release:
return (
f"core_version {report.declared} is older than the code: the pin "
f"{pin[:7]} already contains release {passed_release}"
)
where = ""
if relation is not None:
ahead, behind = relation
if ahead and not behind:
where = f", {ahead} commits after the tag"
elif behind and not ahead:
where = f", {behind} commits before the tag: core_version is later than the code"
elif ahead and behind:
where = f", off the tag's history ({ahead} ahead, {behind} behind)"
return (
f"core_version {report.declared} names tag commit {report.tag_commit[:7]}, "
f"the pin resolved to {pin[:7]}"
f"the pin resolved to {pin[:7]}{where}"
)
@@ -3937,7 +3963,48 @@ def _attach_version(
except upstream.UpstreamError as exc:
print(f"{report.name}: version check skipped: {exc}", file=sys.stderr)
return
report.version_warning = version_warning(report.version, report.pin)
relation = None
passed = None
version = report.version
try:
if version and version.tag_commit and report.pin and version.tag_commit != report.pin:
relation = upstream.ancestry(
repo, version.tag_commit, report.pin, args.cache_dir, args.offline
)
passed = _passed_release(args, repo, version, report.pin)
except upstream.RateLimitError:
raise
except upstream.UpstreamError as exc:
print(f"{report.name}: tag ancestry unread: {exc}", file=sys.stderr)
report.version_warning = version_warning(version, report.pin, relation, passed)
def _passed_release(
args: argparse.Namespace,
repo: upstream.Repo,
version: VersionReport | None,
pin: str | None,
) -> str | None:
"""The latest release, when the pin already contains it and core_version
names another one.
The latest tag is no witness: nightly, continuous and Pre-release tags
sort first on many forges. The latest release is a version the project
published as such.
"""
if not version or not pin or not version.latest_release:
return None
if version.latest_release == version.declared:
return None
commit = upstream.tag_commit(repo, version.latest_release, args.cache_dir, args.offline)
if not commit:
return None
if commit == pin:
return version.latest_release
relation = upstream.ancestry(repo, commit, pin, args.cache_dir, args.offline)
if relation and relation[1] == 0:
return version.latest_release
return None
def _print_extras(
+35
View File
@@ -742,6 +742,41 @@ def compare(
return CompareResult(files, truncated, payload.get("status") == "diverged")
def _commits_ahead(payload: object, family: str) -> int | None:
"""Commits the compare head carries that its base does not."""
if not isinstance(payload, dict):
return None
if family == "github":
value = payload.get("ahead_by")
elif family == "gitlab":
value = len(payload.get("commits") or [])
else:
value = payload.get("total_commits")
return value if isinstance(value, int) else None
def ancestry(
repo: Repo, base: str, head: str, cache_dir: str, offline: bool = False
) -> tuple[int, int] | None:
"""(ahead, behind): commits head has that base lacks, and the reverse.
Two shas never change their history, so both answers are cached for
good. GitHub gives both counts in one answer, GitLab and Forgejo list
one direction only and are asked twice.
"""
forward = _api(_compare_url(repo, base, head), cache_dir, offline)
ahead = _commits_ahead(forward, repo.family)
if ahead is None:
return None
if repo.family == "github":
behind = forward.get("behind_by")
else:
behind = _commits_ahead(
_api(_compare_url(repo, head, base), cache_dir, offline), repo.family
)
return (ahead, behind) if isinstance(behind, int) else None
def find_renamed(result: CompareResult, path: str) -> str | None:
"""New path of a file the comparison reports as renamed."""
for change in result.files:
+49
View File
@@ -3171,6 +3171,55 @@ class TestCheckVersion(unittest.TestCase):
result = check_version({"core_version": "v3.0.0"}, self.repo, self.dir, False)
self.assertIsNone(version_warning(result, "tagsha"))
def test_warning_says_which_side_of_the_tag_the_pin_is(self):
# 52 warnings read alike: a build after its release and a pin older
# than the release it claims could not be told apart.
result = check_version({"core_version": "v3.0.0"}, self.repo, self.dir, False)
self.assertIn("4 commits after the tag", version_warning(result, "p", (4, 0)))
self.assertIn("core_version is later than the code",
version_warning(result, "p", (0, 9)))
self.assertIn("off the tag's history", version_warning(result, "p", (2, 3)))
def test_warning_names_a_release_the_pin_already_contains(self):
result = check_version({"core_version": "v3.0.0"}, self.repo, self.dir, False)
warning = version_warning(result, "tagsha", None, "v3.1.0")
self.assertIn("already contains release v3.1.0", warning)
class TestAncestry(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.saved = profile_sync.upstream._http_json
def tearDown(self):
profile_sync.upstream._http_json = self.saved
self.tmp.cleanup()
def test_github_answers_both_directions_at_once(self):
calls = []
def answer(url):
calls.append(url)
return {"ahead_by": 3, "behind_by": 0}
profile_sync.upstream._http_json = answer
repo = profile_sync.upstream.parse_repo("https://github.com/o/n")
self.assertEqual(
profile_sync.upstream.ancestry(repo, "tag", "pin", self.tmp.name), (3, 0)
)
self.assertEqual(len(calls), 1)
def test_gitlab_is_asked_both_ways(self):
def answer(url):
forward = "from=tag&to=pin" in url
return {"commits": [{}] * (0 if forward else 5)}
profile_sync.upstream._http_json = answer
repo = profile_sync.upstream.parse_repo("https://gitlab.com/o/n")
self.assertEqual(
profile_sync.upstream.ancestry(repo, "tag", "pin", self.tmp.name), (0, 5)
)
HASH_PROFILE = {
"files": [