diff --git a/dep_freshness/_tables.py b/dep_freshness/_tables.py index 2bf35be..3aa7390 100644 --- a/dep_freshness/_tables.py +++ b/dep_freshness/_tables.py @@ -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.:` or # `com.github..:`; the GitHub repo is what "HEAD" means. diff --git a/dep_freshness/registries/maven.py b/dep_freshness/registries/maven.py index b1cbb9a..983a261 100644 --- a/dep_freshness/registries/maven.py +++ b/dep_freshness/registries/maven.py @@ -16,7 +16,9 @@ artifacts published nowhere else (PhotoView, DirectionalViewPager). Since themselves still download, so a `com.github.:` 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. `` and `` in the metadata are not trusted: AndroidX writes `1.2.0-alpha03` into `` routinely. The full `` 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) diff --git a/dep_freshness/tests/test_gradle_registry.py b/dep_freshness/tests/test_gradle_registry.py index de02002..e7834a0 100644 --- a/dep_freshness/tests/test_gradle_registry.py +++ b/dep_freshness/tests/test_gradle_registry.py @@ -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):