#!/usr/bin/env python3 """Schreibt badge-data.json aus der Releases-API (Gitea/GitHub-kompatibel).""" from __future__ import annotations import json import os import re import sys import urllib.error import urllib.request BADGE_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "badge-data.json") def api_get(url: str, token: str) -> bytes: req = urllib.request.Request(url) if token: req.add_header("Authorization", f"Bearer {token}") req.add_header("Accept", "application/json") with urllib.request.urlopen(req, timeout=120) as resp: return resp.read() def fetch_releases(api_base: str, repo: str, token: str) -> list: out: list = [] page = 1 while True: url = f"{api_base}/repos/{repo}/releases?limit=100&page={page}" batch = json.loads(api_get(url, token)) if not batch: break out.extend(batch) if len(batch) < 100: break page += 1 return out def sum_zip_downloads(releases: list) -> int: total = 0 for rel in releases: for asset in rel.get("assets") or []: name = str(asset.get("name", "")) if name.endswith(".zip"): total += int(asset.get("download_count") or 0) return total def parse_firmware_from_body(body: str) -> str | None: if not body: return None patterns = ( r"Firmware\s+Version\s*\*\*(\d+\.\d+\.\d+)\*\*", r"mit\s+Firmware\s+Version\s*\*\*(\d+\.\d+\.\d+)\*\*", r"\*\*(\d+\.\d+\.\d+)\*\*\s+in\s+der\s+CFW", ) for p in patterns: m = re.search(p, body, re.I | re.MULTILINE) if m: return m.group(1) return None def load_existing_firmware() -> str | None: if not os.path.isfile(BADGE_PATH): return None try: with open(BADGE_PATH, encoding="utf-8") as f: return json.load(f).get("switch_firmware") except (OSError, json.JSONDecodeError, TypeError): return None def main() -> int: api_base = os.environ.get("GITHUB_API_URL", "").rstrip("/") repo = os.environ.get("GITHUB_REPOSITORY", "") token = os.environ.get("GITHUB_TOKEN", "") if not api_base or not repo: print("GITHUB_API_URL und GITHUB_REPOSITORY werden benötigt.", file=sys.stderr) return 1 try: releases = fetch_releases(api_base, repo, token) except urllib.error.HTTPError as e: print(f"API: HTTP {e.code} — {e.reason}", file=sys.stderr) return 1 if not releases: print("Keine Releases gefunden.", file=sys.stderr) return 1 latest = next((r for r in releases if not r.get("draft")), None) if not latest: print("Kein nicht-Draft-Release.", file=sys.stderr) return 1 tag = str(latest.get("tag_name") or "").strip() body = str(latest.get("body") or "") fw = parse_firmware_from_body(body) or load_existing_firmware() or "unknown" data = { "switch_firmware": fw, "release_zip_downloads_total": sum_zip_downloads(releases), "omninx_pack_version": tag, } with open(BADGE_PATH, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) f.write("\n") print(json.dumps(data, indent=2)) return 0 if __name__ == "__main__": sys.exit(main())