dep_freshness: JitPack-hosted own-group artifacts

Ask JitPack metadata last for names no other repo knows and that
are not com.github.* (whose metadata is 401, tags used instead).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWY1k4muZfdVJfb7YGJ
This commit is contained in:
Krzysztof Rudnicki 2026-11-02 09:12:20 +01:00
parent 11c5b2e32b
commit 213537d0ef
3 changed files with 65 additions and 3 deletions

View File

@ -64,6 +64,11 @@ MAVEN_REPOS: Final = (
"https://repo1.maven.org/maven2/",
"https://plugins.gradle.org/m2/",
)
# Asked only when none of the above knows an artifact AND the group is not
# `com.github.*` (whose metadata is the 401 above): JitPack also hosts
# artifacts under their own group, e.g. `cz.adaptech.tesseract4android`,
# whose metadata answers 200 with the full release list.
JITPACK_REPO: Final = "https://jitpack.io/"
UTILS_TAG_REMOTE: Final = "https://github.com/kuhyx/utils"
# JitPack coordinates: `com.github.<owner>:<repo>` or
# `com.github.<owner>.<repo>:<module>`; the GitHub repo is what "HEAD" means.

View File

@ -16,7 +16,9 @@ artifacts published nowhere else (PhotoView, DirectionalViewPager). Since
themselves still download, so a `com.github.<owner>:<repo>` name that no
repository knows is answered from the GitHub repo's tags over `git
ls-remote` (unmetered, no token). JitPack's version IS the tag name, `v`
prefix included, so the tags are compared as they are.
prefix included, so the tags are compared as they are. Artifacts JitPack
hosts under their OWN group (`cz.adaptech.tesseract4android`) still get
200 metadata there, so JitPack is the last resort for any other name.
`<latest>` and `<release>` in the metadata are not trusted: AndroidX writes
`1.2.0-alpha03` into `<latest>` routinely. The full `<versions>` list goes
@ -32,7 +34,12 @@ from __future__ import annotations
from xml.etree import ElementTree
from dep_freshness._tables import GITHUB_REMOTE, MAVEN_REPOS
from dep_freshness._tables import (
GITHUB_REMOTE,
JITPACK_GROUP_PREFIX,
JITPACK_REPO,
MAVEN_REPOS,
)
from dep_freshness.registries._git import ls_remote
from dep_freshness.registries.gitcommit import source_repo
from dep_freshness.registries.http import get_text
@ -69,6 +76,15 @@ def github_tags(name: str) -> list[str]:
return [line.rpartition("refs/tags/")[2] for line in lines if "refs/tags/" in line]
def _jitpack_versions(name: str) -> list[str]:
"""What only JitPack knows: tags for `com.github.*`, metadata otherwise."""
if name.startswith(JITPACK_GROUP_PREFIX):
return github_tags(name)
url = metadata_url(JITPACK_REPO, name)
body = get_text(url) if url else None
return versions_in(body) if body is not None else []
def latest(name: str) -> str | None:
seen: list[str] = []
for repo in MAVEN_REPOS:
@ -79,5 +95,5 @@ def latest(name: str) -> str | None:
if body is not None:
seen.extend(versions_in(body))
if not seen:
seen.extend(github_tags(name))
seen.extend(_jitpack_versions(name))
return reference(seen) or newest_per_generation(seen)

View File

@ -147,6 +147,47 @@ def test_a_tagless_repo_and_a_non_jitpack_name_are_none(repos, monkeypatch):
assert calls == [("https://github.com/o/r", "--tags", "--refs")]
JITPACK = maven.JITPACK_REPO
TESSERACT = "cz.adaptech.tesseract4android:tesseract4android"
def test_a_jitpack_only_artifact_is_answered_by_jitpack_metadata(repos):
"""Tesseract4Android is published on JitPack under its own group, not
`com.github.*`, so there is no source repo to read tags from; JitPack's
metadata for it answers 200 and lists every release."""
repos[maven.metadata_url(JITPACK, TESSERACT)] = metadata(
"4.7.0", "4.9.0", "4.1.1a", latest="4.9.0"
)
assert maven.latest(TESSERACT) == "4.9.0"
def test_jitpack_is_asked_last_and_only_when_nobody_else_knows_the_name(
repos, monkeypatch
):
asked: list[str] = []
monkeypatch.setattr(
maven, "get_text", lambda url, *a, **k: asked.append(url) or repos.get(url)
)
repos[maven.metadata_url(CENTRAL, "io.coil-kt:coil")] = metadata("2.7.0")
assert maven.latest("io.coil-kt:coil") == "2.7.0"
assert not any(url.startswith(JITPACK) for url in asked)
def test_a_github_jitpack_name_never_asks_jitpack_metadata(repos, monkeypatch):
"""That endpoint answers 401 for `com.github.*`; the tags are the answer."""
asked: list[str] = []
monkeypatch.setattr(
maven, "get_text", lambda url, *a, **k: asked.append(url) or None
)
tags(monkeypatch, {"o/r": ["1.0.0"]})
assert maven.latest("com.github.o:r") == "1.0.0"
assert not any(url.startswith(JITPACK) for url in asked)
def test_a_name_jitpack_does_not_know_either_is_none(repos):
assert maven.latest(TESSERACT) is None
def test_an_unreachable_repo_is_offline(repos, monkeypatch):
tags(monkeypatch, {})
with pytest.raises(Offline):