mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-11 12:27:47 +01:00
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
Three findings from proving the JitPack fix on the TachiyomiSY gate:
- The first repository with a stable answer used to win. Central still
carries com.github.ben-manes:gradle-versions-plugin 0.11.1 (2016) while
the plugin portal has 0.54.0, so a 0.51.0 pin graded "current". Every
repository is now asked and the newest stable across the pooled lists is
the answer.
- ~900 lookups, eight at a time, each resolving the registry host (A+AAAA)
per connection: the LAN router's forwarder started dropping queries for
every client on the LAN and the gate degraded itself. socket.getaddrinfo
is memoised per (host, port, hints) for the run, and the per-host probe
runs under a lock so eight workers make one probe, not eight.
- A resolver EAI_AGAIN ("temporary failure") during the probe marked the
registry unreachable for the whole run. The probe retries it
HTTP_ATTEMPTS times; a permanent failure still fails immediately.
Both retry loops lost their unreachable `return` sentinel (http.py is at
100% branch now); the resolver tests live in test_http_resolver.py to keep
test_http.py under the 250-line cap.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016P4KZw1E2sXJjYqfcZWf1x
205 lines
7.6 KiB
Python
205 lines
7.6 KiB
Python
"""Maven metadata across four repositories, and the Gradle release feed."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from dep_freshness import discover
|
|
from dep_freshness.registries import maven
|
|
from dep_freshness.registries import toolchain as tc
|
|
from dep_freshness.registries.http import Offline
|
|
from dep_freshness.resolve import _toolchain_latest
|
|
from dep_freshness.tests.conftest import write
|
|
|
|
GOOGLE, CENTRAL, PORTAL = maven.MAVEN_REPOS
|
|
|
|
|
|
def metadata(*versions: str, latest: str | None = None) -> str:
|
|
body = "".join(f"<version>{v}</version>" for v in versions)
|
|
head = f"<latest>{latest}</latest>" if latest else ""
|
|
return f"<metadata><versioning>{head}<versions>{body}</versions></versioning></metadata>"
|
|
|
|
|
|
@pytest.fixture
|
|
def repos(monkeypatch):
|
|
"""Canned bodies per metadata URL; anything unlisted is a 404."""
|
|
table: dict[str, str] = {}
|
|
monkeypatch.setattr(maven, "get_text", lambda url, *a, **k: table.get(url))
|
|
return table
|
|
|
|
|
|
def test_metadata_url_shape():
|
|
assert (
|
|
maven.metadata_url(CENTRAL, "io.coil-kt:coil")
|
|
== f"{CENTRAL}io/coil-kt/coil/maven-metadata.xml"
|
|
)
|
|
assert maven.metadata_url(CENTRAL, "nocolon") is None
|
|
assert maven.metadata_url(CENTRAL, ":artifact") is None
|
|
|
|
|
|
def test_versions_in_ignores_blank_nodes_and_bad_xml():
|
|
assert maven.versions_in(metadata("1.0", " ", "2.0")) == ["1.0", "2.0"]
|
|
assert maven.versions_in("<metadata><versions>") == []
|
|
|
|
|
|
def test_google_is_asked_first_and_latest_tag_is_not_trusted(repos):
|
|
repos[maven.metadata_url(GOOGLE, "androidx.core:core-ktx")] = metadata(
|
|
"1.16.0", "1.17.0", "1.18.0-alpha03", latest="1.18.0-alpha03"
|
|
)
|
|
assert maven.latest("androidx.core:core-ktx") == "1.17.0"
|
|
|
|
|
|
def test_central_answers_when_google_has_no_such_artifact(repos):
|
|
repos[maven.metadata_url(CENTRAL, "io.coil-kt:coil")] = metadata("2.6.0", "2.7.0")
|
|
assert maven.latest("io.coil-kt:coil") == "2.7.0"
|
|
|
|
|
|
def test_plugin_markers_come_from_the_portal(repos):
|
|
name = "org.example.plugin:org.example.plugin.gradle.plugin"
|
|
repos[maven.metadata_url(PORTAL, name)] = metadata("0.5.0")
|
|
assert maven.latest(name) == "0.5.0"
|
|
|
|
|
|
def test_a_repo_with_only_prereleases_does_not_stop_the_search(repos):
|
|
repos[maven.metadata_url(GOOGLE, "g:a")] = metadata("1.0.0-beta01")
|
|
repos[maven.metadata_url(CENTRAL, "g:a")] = metadata("0.9.0")
|
|
assert maven.latest("g:a") == "0.9.0"
|
|
|
|
|
|
def test_every_repository_is_asked_and_the_newest_stable_across_them_wins(repos):
|
|
"""gradle-versions-plugin: Central stopped at 0.11.1 in 2016, the plugin
|
|
portal carries 0.54.0. The first answer is not the answer."""
|
|
name = "com.github.ben-manes:gradle-versions-plugin"
|
|
repos[maven.metadata_url(CENTRAL, name)] = metadata("0.11", "0.11.1")
|
|
repos[maven.metadata_url(PORTAL, name)] = metadata("0.53.0", "0.54.0")
|
|
assert maven.latest(name) == "0.54.0"
|
|
|
|
|
|
def tags(monkeypatch, remote_tags: dict[str, list[str]]):
|
|
"""Serve `git ls-remote --tags --refs` for the GitHub remotes in `remote_tags`."""
|
|
calls: list[tuple[str, ...]] = []
|
|
|
|
def fake(remote, *args):
|
|
calls.append((remote, *args))
|
|
repo = remote.removeprefix("https://github.com/")
|
|
if repo not in remote_tags:
|
|
raise Offline(remote)
|
|
return [f"{'0' * 40}\trefs/tags/{tag}" for tag in remote_tags[repo]]
|
|
|
|
monkeypatch.setattr(maven, "ls_remote", fake)
|
|
return calls
|
|
|
|
|
|
def test_jitpack_artifact_is_answered_from_the_repo_tags(repos, monkeypatch):
|
|
"""PhotoView was never published anywhere but JitPack, whose metadata
|
|
endpoint now answers 401; the repo's tags are the same list. `v`-tags and
|
|
bare tags both appear and the newest STABLE wins: a newer pre-release
|
|
tag is skipped exactly as it would be in maven-metadata."""
|
|
name = "com.github.chrisbanes:PhotoView"
|
|
calls = tags(
|
|
monkeypatch,
|
|
{"chrisbanes/PhotoView": ["v1.3.1", "2.2.0", "2.3.0", "v3.0.0-beta1"]},
|
|
)
|
|
assert maven.latest(name) == "2.3.0"
|
|
assert calls == [("https://github.com/chrisbanes/PhotoView", "--tags", "--refs")]
|
|
|
|
|
|
def test_a_project_named_tag_is_read_as_its_version(repos, monkeypatch):
|
|
"""`java-nat-sort` is tagged `natural-comparator-1.1`, not `1.1`."""
|
|
name = "com.github.gpanther:java-nat-sort"
|
|
tags(
|
|
monkeypatch,
|
|
{
|
|
"gpanther/java-nat-sort": [
|
|
"natural-comparator-1.0",
|
|
"natural-comparator-1.1",
|
|
]
|
|
},
|
|
)
|
|
assert maven.latest(name) == "natural-comparator-1.1"
|
|
|
|
|
|
def test_a_repository_answer_wins_over_the_tags(repos, monkeypatch):
|
|
"""A `com.github.*` artifact that Central knows is not a JitPack build."""
|
|
name = "com.github.ben-manes.caffeine:caffeine"
|
|
repos[maven.metadata_url(CENTRAL, name)] = metadata("3.1.8", "3.2.0")
|
|
calls = tags(monkeypatch, {})
|
|
assert maven.latest(name) == "3.2.0"
|
|
assert calls == []
|
|
|
|
|
|
def test_prereleases_from_a_repository_skip_the_tag_lookup(repos, monkeypatch):
|
|
"""Something was found, just nothing stable: the repo answered, so the
|
|
pre-release fallback applies and the tags are never consulted."""
|
|
name = "com.github.x:y"
|
|
repos[maven.metadata_url(CENTRAL, name)] = metadata("1.0.0-beta1")
|
|
calls = tags(monkeypatch, {})
|
|
assert maven.latest(name) == "1.0.0-beta1"
|
|
assert calls == []
|
|
|
|
|
|
def test_a_tagless_repo_and_a_non_jitpack_name_are_none(repos, monkeypatch):
|
|
calls = tags(monkeypatch, {"o/r": [], "o/s": ["HEAD-not-a-tag"]})
|
|
assert maven.latest("com.github.o:r") is None
|
|
assert maven.github_tags("g:a") == []
|
|
assert calls == [("https://github.com/o/r", "--tags", "--refs")]
|
|
|
|
|
|
def test_an_unreachable_repo_is_offline(repos, monkeypatch):
|
|
tags(monkeypatch, {})
|
|
with pytest.raises(Offline):
|
|
maven.latest("com.github.o:gone")
|
|
|
|
|
|
def test_a_package_with_no_stable_anywhere_falls_back_to_newest_prerelease(repos):
|
|
"""biometric-ktx has been alpha-only since 2021: the newest alpha is the
|
|
reference, and a stable release in ANY repo would still win over it."""
|
|
name = "androidx.biometric:biometric-ktx"
|
|
repos[maven.metadata_url(GOOGLE, name)] = metadata(
|
|
"1.2.0-alpha05", "1.4.0-alpha02", "1.3.0-alpha01"
|
|
)
|
|
assert maven.latest(name) == "1.4.0-alpha02"
|
|
|
|
|
|
def test_unknown_everywhere_or_malformed_name_is_none(repos):
|
|
assert maven.latest("g:nowhere") is None
|
|
assert maven.latest("bare") is None
|
|
|
|
|
|
def test_offline_propagates_from_the_transport(monkeypatch):
|
|
def down(*_a, **_k):
|
|
raise Offline("down")
|
|
|
|
monkeypatch.setattr(maven, "get_text", down)
|
|
with pytest.raises(Offline):
|
|
maven.latest("g:a")
|
|
|
|
|
|
def test_gradle_latest_from_the_release_feed(monkeypatch):
|
|
monkeypatch.setattr(tc, "get_json", lambda *_a, **_k: {"version": "9.7.1"})
|
|
assert tc.gradle_latest() == "9.7.1"
|
|
monkeypatch.setattr(tc, "get_json", lambda *_a, **_k: {"version": "10.0.0-rc-1"})
|
|
assert tc.gradle_latest() is None
|
|
monkeypatch.setattr(tc, "get_json", lambda *_a, **_k: None)
|
|
assert tc.gradle_latest() is None
|
|
|
|
|
|
def test_the_resolver_routes_gradle_to_the_toolchain_feed(monkeypatch):
|
|
monkeypatch.setattr(tc, "gradle_latest", lambda: "9.7.1")
|
|
assert _toolchain_latest("gradle") == "9.7.1"
|
|
|
|
|
|
def test_discovery_routes_catalog_and_wrapper(tmp_path: Path):
|
|
catalog = write(
|
|
tmp_path, "gradle/libs.versions.toml", '[libraries]\nc = "g:a:1.0.0"\n'
|
|
)
|
|
wrapper = write(
|
|
tmp_path,
|
|
"gradle/wrapper/gradle-wrapper.properties",
|
|
"distributionUrl=https\\://x/gradle-9.6.1-bin.zip\n",
|
|
)
|
|
assert [d.name for d in discover.parse_manifest(catalog)] == ["g:a"]
|
|
assert [d.name for d in discover.parse_manifest(wrapper)] == ["gradle"]
|