"""Schlanke Gitea-API-Helfer (stdlib only). - PR-Diff holen - Kommentare IDEMPOTENT posten: ein versteckter HTML-Marker identifiziert den Bot-Kommentar; existiert er schon, wird er editiert statt neu angelegt (kein Zuspammen bei jedem Push). Env-Vars: GITEA_API Basis-URL der API, Default https://git.eulernest.eu/api/v1 GITEA_TOKEN Token fürs Kommentieren (Actions-Auto-Token ODER PAT). Fallback: GITEA_BOT_TOKEN. """ import json import os import urllib.error import urllib.request _BASE = os.environ.get("GITEA_API", "https://git.eulernest.eu/api/v1").rstrip("/") _TOKEN = os.environ.get("GITEA_TOKEN") or os.environ.get("GITEA_BOT_TOKEN", "") def _request(method: str, path: str, *, data=None, raw: bool = False): url = f"{_BASE}{path}" headers = {} if _TOKEN: headers["Authorization"] = f"token {_TOKEN}" body = None if data is not None: body = json.dumps(data).encode("utf-8") headers["Content-Type"] = "application/json" req = urllib.request.Request(url, data=body, headers=headers, method=method) try: with urllib.request.urlopen(req, timeout=60) as resp: content = resp.read().decode("utf-8", "replace") if raw: return content return json.loads(content) if content.strip() else None except urllib.error.HTTPError as exc: detail = exc.read().decode("utf-8", "replace") raise SystemExit(f"[gitea] {method} {path} -> HTTP {exc.code}: {detail[:400]}") except urllib.error.URLError as exc: raise SystemExit(f"[gitea] {method} {path} fehlgeschlagen: {exc.reason}") def get_pr_diff(owner: str, repo: str, index: int) -> str: """Unified Diff eines PRs (Gitea unterstützt den .diff-Suffix).""" return _request("GET", f"/repos/{owner}/{repo}/pulls/{index}.diff", raw=True) def get_issue_thread(owner: str, repo: str, index: int) -> str: """Titel + Body + alle MENSCHLICHEN Kommentare eines Issues/PRs als Text. Eigene Bot-Kommentare (Marker `