Files
bruno 2f129c3f23 chore(scripts): outil de controle du CI Gitea (runs et jobs par head_sha)
scripts/check_ci.py : interroge l'API Gitea (jeton via git credential fill, User-Agent navigateur) et rapporte l'etat des jobs du run correspondant au HEAD local. Bump automatique de version = demonstration du hook prepare-commit-msg.
2026-09-16 11:20:13 -04:00

80 lines
2.8 KiB
Python

"""Vérifie l'état du dernier run CI Gitea d'ObsiGate (lecture seule)."""
import json
import subprocess
import sys
import urllib.request
REPO = "Projets/ObsiGate"
BASE = f"https://git.dracodev.net/api/v1/repos/{REPO}"
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126 Safari/537.36"
cred = subprocess.run(
["git", "credential", "fill"],
input="protocol=https\nhost=git.dracodev.net\n\n",
capture_output=True,
text=True,
cwd=r"C:\dev\git\python\ObsiGate",
)
token = ""
for line in cred.stdout.splitlines():
if line.startswith("password"):
token = line.split("=", 1)[1]
if not token:
raise SystemExit("pas de jeton git disponible")
sha = subprocess.run(
["git", "rev-parse", "HEAD"],
capture_output=True,
text=True,
cwd=r"C:\dev\git\python\ObsiGate",
).stdout.strip()
def get(path: str):
req = urllib.request.Request(
f"{BASE}{path}",
headers={
"Authorization": f"token {token}",
"Accept": "application/json",
"User-Agent": UA,
},
)
with urllib.request.urlopen(req, timeout=25) as resp:
return json.load(resp)
runs = get("/actions/runs?limit=10").get("workflow_runs", [])
print(f"HEAD local : {sha[:8]} — {len(runs)} run(s) récent(s)")
target = None
for run in runs:
head = str(run.get("head_sha") or "")
title = run.get("display_title") or run.get("name") or "?"
flag = " <== HEAD" if head.startswith(sha[:8]) else ""
print(f" #{run.get('id')} {title[:60]} | {run.get('status')}/{run.get('conclusion')} | {head[:8]}{flag}")
if head.startswith(sha[:8]) and target is None:
target = run
if target is None:
print("Aucun run pour le HEAD courant (encore en file d'attente ?)")
sys.exit(0)
jobs_resp = get(f"/actions/runs/{target['id']}/jobs")
print(f"run #{target['id']} : status={target.get('status')} conclusion={target.get('conclusion')} "
f"started={target.get('run_started_at')} updated={target.get('updated_at')}")
print(f"clés jobs: {list(jobs_resp)[:6]}")
for job in jobs_resp.get("workflow_jobs", jobs_resp.get("jobs", [])) or []:
print(f" - {job.get('name')}: {job.get('status')}/{job.get('conclusion')}")
if job.get("status") != "completed":
for step in job.get("steps", []) or []:
print(f" · {step.get('name')}: {step.get('status')}/{step.get('conclusion')}")
try:
runners = get("/actions/runners")
entries = runners.get("runners", runners) if isinstance(runners, dict) else runners
print(f"runners: {len(entries) if isinstance(entries, list) else entries}")
if isinstance(entries, list):
for runner in entries:
print(f" - {runner.get('name')} status={runner.get('status')} labels={runner.get('labels')}")
except Exception as exc: # noqa: BLE001
print(f"runners indisponibles: {exc}")