Files
wehub-resource-sync 3e779be6f3
CI / lint (push) Failing after 13m4s
CI / test (3.11, ubuntu-latest) (push) Failing after 2m4s
CI / test (3.13, ubuntu-latest) (push) Successful in 13m30s
CI / test (3.14, ubuntu-latest) (push) Successful in 17m21s
CI / test (3.12, ubuntu-latest) (push) Successful in 17m55s
CI / discover-apps-ps (push) Successful in 1m56s
CI / test (3.9, ubuntu-latest) (push) Successful in 13m17s
CI / test (3.10, ubuntu-latest) (push) Successful in 26m21s
CI / audit (push) Successful in 13m38s
Deploy site / deploy (push) Has been cancelled
CI / test (3.14, ubuntu-24.04-arm) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:37 +08:00

83 lines
2.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""Reduce OBS `_result` XML to a per-shipping-repo terminal-state verdict.
Reads the OBS API response on stdin and exits:
0 — all shipping repos READY (succeeded, or every arch is excluded/broken/blocked)
1 — any shipping repo FAILED (any arch is failed/unresolvable)
2 — any shipping repo still PENDING / MISSING data
A one-line per-repo summary is printed on stdout for the workflow log,
regardless of exit code.
The "shipping repos" list defines which (repo, arch) combinations we
actually care about for GitHub Release uploads — niche arches like
openSUSE_Factory_RISCV / Factory_PowerPC / Slowroll-aarch64 sit in
`blocked`/`broken` indefinitely and would otherwise hold the publish
workflow hostage until the 60-minute deadline. This script lets the
wait loop exit the moment our seven shipping repos are done.
"""
from __future__ import annotations
import re
import sys
# OBS reports the Leap repos under their bare-version names (`15.6`, `16.0`)
# rather than the `openSUSE_Leap_*` prefix used in the publish artefact
# filenames. obs-publish.yml's discover/upload step normalises them back.
SHIP_REPOS = [
"openSUSE_Tumbleweed",
"15.6", # → published as openSUSE_Leap_15.6
"16.0", # → published as openSUSE_Leap_16.0
"openSUSE_Slowroll",
"Fedora_42",
"Fedora_43",
"Fedora_44",
]
def reduce_codes(codes: list[str]) -> str:
if not codes:
return "MISSING"
if any(c in ("failed", "unresolvable") for c in codes):
return "FAILED"
if any(c == "succeeded" for c in codes):
return "READY"
if all(c in ("excluded", "broken", "blocked") for c in codes):
return "READY"
return "PENDING"
def main() -> int:
xml = sys.stdin.read()
blocks = re.findall(r"<result\b[^>]*>.*?</result>", xml, re.DOTALL)
per_repo: dict[str, list[str]] = {}
for block in blocks:
repo_m = re.search(r'repository="([^"]+)"', block)
if not repo_m:
continue
repo = repo_m.group(1)
if repo not in SHIP_REPOS:
continue
code_m = re.search(r'<status\s+package="winpodx"\s+code="([^"]+)"', block)
if not code_m:
continue
per_repo.setdefault(repo, []).append(code_m.group(1))
states = {r: reduce_codes(per_repo.get(r, [])) for r in SHIP_REPOS}
summary = " ".join(f"{r}={s}" for r, s in states.items())
if any(s == "FAILED" for s in states.values()):
print(f"FAILED {summary}")
return 1
if any(s in ("PENDING", "MISSING") for s in states.values()):
print(f"PENDING {summary}")
return 2
print(f"READY {summary}")
return 0
if __name__ == "__main__":
sys.exit(main())