[skip ci] fix ots
This commit is contained in:
3 files changed
+107
-6
No files matched your search
@@ -149,7 +149,7 @@ jobs:
|
|||||||
|
|
||||||
APKSIGNER="$(find "$ANDROID_HOME/build-tools" -name apksigner | sort | tail -1)"
|
APKSIGNER="$(find "$ANDROID_HOME/build-tools" -name apksigner | sort | tail -1)"
|
||||||
SIGNER_SHA256="$("$APKSIGNER" verify --print-certs "$APK" \
|
SIGNER_SHA256="$("$APKSIGNER" verify --print-certs "$APK" \
|
||||||
| sed -n 's/^Signer #1 certificate SHA-256 digest: //p' | head -1)"
|
| sed -n 's/.*certificate SHA-256 digest: //p' | head -1)"
|
||||||
|
|
||||||
printf '{\n "version_code": %s,\n "version_name": "%s",\n "commit": "%s",\n "built_at": "%s",\n "size_bytes": %s,\n "sha256": "%s",\n "signer_sha256": "%s"\n}\n' \
|
printf '{\n "version_code": %s,\n "version_name": "%s",\n "commit": "%s",\n "built_at": "%s",\n "size_bytes": %s,\n "sha256": "%s",\n "signer_sha256": "%s"\n}\n' \
|
||||||
"${{ gitea.run_number }}" \
|
"${{ gitea.run_number }}" \
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import tempfile
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import zipfile
|
import zipfile
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass, replace
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@@ -139,8 +139,45 @@ def _artifact(raw: Any) -> Artifact | None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(client: httpx.Client, settings: EnvSettings, run_id: int) -> dict[str, Any]:
|
||||||
|
try:
|
||||||
|
response = client.get(_api(settings, f"/actions/runs/{run_id}"))
|
||||||
|
response.raise_for_status()
|
||||||
|
payload = response.json()
|
||||||
|
except (httpx.HTTPError, ValueError) as exc:
|
||||||
|
raise UpdateUnavailable(f"Could not read Gitea run {run_id}: {exc}") from exc
|
||||||
|
return payload if isinstance(payload, dict) else {}
|
||||||
|
|
||||||
|
|
||||||
|
def _with_run(
|
||||||
|
client: httpx.Client,
|
||||||
|
settings: EnvSettings,
|
||||||
|
artifact: Artifact,
|
||||||
|
runs: dict[int, dict[str, Any]],
|
||||||
|
) -> Artifact:
|
||||||
|
"""Gitea's artifact list can omit the run's branch, number and conclusion."""
|
||||||
|
if artifact.run_number and artifact.branch and artifact.conclusion:
|
||||||
|
return artifact
|
||||||
|
if not artifact.run_id:
|
||||||
|
return artifact
|
||||||
|
run = runs.get(artifact.run_id)
|
||||||
|
if run is None:
|
||||||
|
run = _run(client, settings, artifact.run_id)
|
||||||
|
runs[artifact.run_id] = run
|
||||||
|
return replace(
|
||||||
|
artifact,
|
||||||
|
run_number=int(run.get("run_number") or artifact.run_number),
|
||||||
|
branch=str(run.get("head_branch") or artifact.branch),
|
||||||
|
commit=str(run.get("head_sha") or artifact.commit),
|
||||||
|
conclusion=str(run.get("conclusion") or artifact.conclusion),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _list_artifacts(
|
def _list_artifacts(
|
||||||
client: httpx.Client, settings: EnvSettings, name: str
|
client: httpx.Client,
|
||||||
|
settings: EnvSettings,
|
||||||
|
name: str,
|
||||||
|
runs: dict[int, dict[str, Any]] | None = None,
|
||||||
) -> list[Artifact]:
|
) -> list[Artifact]:
|
||||||
try:
|
try:
|
||||||
response = client.get(_api(settings, "/actions/artifacts"), params={"name": name})
|
response = client.get(_api(settings, "/actions/artifacts"), params={"name": name})
|
||||||
@@ -152,7 +189,9 @@ def _list_artifacts(
|
|||||||
entries = payload.get("artifacts") if isinstance(payload, dict) else None
|
entries = payload.get("artifacts") if isinstance(payload, dict) else None
|
||||||
if not isinstance(entries, list):
|
if not isinstance(entries, list):
|
||||||
return []
|
return []
|
||||||
return [artifact for raw in entries if (artifact := _artifact(raw)) is not None]
|
artifacts = [artifact for raw in entries if (artifact := _artifact(raw)) is not None]
|
||||||
|
run_cache = runs if runs is not None else {}
|
||||||
|
return [_with_run(client, settings, artifact, run_cache) for artifact in artifacts]
|
||||||
|
|
||||||
|
|
||||||
def _successful(artifacts: list[Artifact], branch: str) -> list[Artifact]:
|
def _successful(artifacts: list[Artifact], branch: str) -> list[Artifact]:
|
||||||
@@ -268,12 +307,13 @@ def _resolve(settings: EnvSettings) -> ResolvedUpdate:
|
|||||||
if cached is not None and now - cached[0] < _METADATA_TTL_SECONDS:
|
if cached is not None and now - cached[0] < _METADATA_TTL_SECONDS:
|
||||||
return cached[1]
|
return cached[1]
|
||||||
|
|
||||||
|
runs: dict[int, dict[str, Any]] = {}
|
||||||
with _client(settings) as client:
|
with _client(settings) as client:
|
||||||
metadata_artifacts = _successful(
|
metadata_artifacts = _successful(
|
||||||
_list_artifacts(client, settings, METADATA_ARTIFACT),
|
_list_artifacts(client, settings, METADATA_ARTIFACT, runs),
|
||||||
settings.gitea_update_branch,
|
settings.gitea_update_branch,
|
||||||
)
|
)
|
||||||
apk_artifacts = _list_artifacts(client, settings, APK_ARTIFACT)
|
apk_artifacts = _list_artifacts(client, settings, APK_ARTIFACT, runs)
|
||||||
usable_apk = _successful(apk_artifacts, settings.gitea_update_branch)
|
usable_apk = _successful(apk_artifacts, settings.gitea_update_branch)
|
||||||
|
|
||||||
resolved: ResolvedUpdate | None = None
|
resolved: ResolvedUpdate | None = None
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import zipfile
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from app.config import env_settings
|
from app.config import env_settings
|
||||||
from app.services import android_updates
|
from app.services import android_updates
|
||||||
|
|
||||||
@@ -200,3 +201,63 @@ def test_the_route_reports_503_when_updates_are_not_configured(client, monkeypat
|
|||||||
|
|
||||||
assert response.status_code == 503
|
assert response.status_code == 503
|
||||||
assert "GITEA_TOKEN" in response.json()["detail"]
|
assert "GITEA_TOKEN" in response.json()["detail"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_sparse_artifact_run_metadata_is_fetched_from_the_run(monkeypatch):
|
||||||
|
_configure(monkeypatch)
|
||||||
|
metadata = _artifact(31, run_id=401, run_number=0, branch="", conclusion="")
|
||||||
|
metadata["workflow_run"] = {"id": 401, "head_sha": "sha-88"}
|
||||||
|
apk = _artifact(
|
||||||
|
32,
|
||||||
|
run_id=401,
|
||||||
|
run_number=0,
|
||||||
|
name=android_updates.APK_ARTIFACT,
|
||||||
|
branch="",
|
||||||
|
conclusion="",
|
||||||
|
)
|
||||||
|
apk["workflow_run"] = {"id": 401, "head_sha": "sha-88"}
|
||||||
|
zips = {
|
||||||
|
31: _zip({"update.json": _metadata_body(88, "0.1.0-master.88")}),
|
||||||
|
32: _zip({"app-release.apk": b"sparse apk"}),
|
||||||
|
}
|
||||||
|
run_requests = 0
|
||||||
|
|
||||||
|
def handler(request: httpx.Request) -> httpx.Response:
|
||||||
|
nonlocal run_requests
|
||||||
|
if request.url.path.endswith("/actions/artifacts"):
|
||||||
|
name = request.url.params.get("name")
|
||||||
|
return httpx.Response(
|
||||||
|
200,
|
||||||
|
json={
|
||||||
|
"total_count": 1,
|
||||||
|
"artifacts": [metadata]
|
||||||
|
if name == android_updates.METADATA_ARTIFACT
|
||||||
|
else [apk],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if request.url.path.endswith("/actions/runs/401"):
|
||||||
|
run_requests += 1
|
||||||
|
return httpx.Response(
|
||||||
|
200,
|
||||||
|
json={
|
||||||
|
"id": 401,
|
||||||
|
"run_number": 88,
|
||||||
|
"head_branch": "master",
|
||||||
|
"head_sha": "sha-88",
|
||||||
|
"conclusion": "success",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
artifact_id = int(request.url.path.rstrip("/").split("/")[-2])
|
||||||
|
return httpx.Response(200, content=zips[artifact_id])
|
||||||
|
|
||||||
|
_install_transport(monkeypatch, handler)
|
||||||
|
|
||||||
|
metadata = android_updates.latest_android()
|
||||||
|
assert metadata["version_code"] == 88
|
||||||
|
assert metadata["version_name"] == "0.1.0-master.88"
|
||||||
|
assert metadata["commit"] == "sha-88"
|
||||||
|
assert run_requests == 1
|
||||||
|
|
||||||
|
path, same = android_updates.android_apk()
|
||||||
|
assert path.read_bytes() == b"sparse apk"
|
||||||
|
assert same == metadata
|
||||||
Reference in new issue
Block a user