La forge du site fait autorite et n etait nourrie que par un geste a part, genome-pousser, qu on oublie. make publier pousse, porte, et verifie ; il refuse si eregion porte des commits absents du poste. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
115 lines
5.3 KiB
Python
115 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Publier le genome : eregion ET la forge du site, en un seul geste.
|
|
|
|
POURQUOI (2026-09-28). La forge du SITE fait autorite (D-81) : un ecosysteme s'y reproduit.
|
|
Mais les commits naissent sur le poste, et n'y arrivent que par `make genome-pousser` — un
|
|
geste A PART, que rien ne force ni ne signale. Un `git push` vers eregion ne la met pas a
|
|
jour. Le 2026-08-26, elle avait quatre commits de retard, dont le correctif du pare-feu
|
|
Proxmox : un ecosysteme reconstruit ce jour-la aurait reproduit le defaut qu'on croyait
|
|
repare. Le 2026-09-28 encore, `make genome-etat` la trouvait en retard d'un commit.
|
|
|
|
Le retard vient d'un geste qu'on oublie : on fait du geste un seul geste.
|
|
|
|
CE QUE CA FAIT, pour chaque depot que le runner du site porte (`serveur_ops_depots`, la MEME
|
|
liste que `genome-pousser` — lue, pas recopiee) :
|
|
1. recuperer eregion, et REFUSER si eregion porte des commits que le poste n'a pas (une
|
|
demande de fusion acceptee, par exemple) : publier sans les integrer les ecraserait
|
|
sur la forge du site ;
|
|
2. signaler ce qui n'est pas committe — cela ne part pas ;
|
|
3. pousser sur eregion ;
|
|
puis `make genome-pousser`, puis `make genome-etat` : la forge du site doit porter la meme
|
|
tete que le poste, sinon on le dit.
|
|
|
|
make publier tous les depots du genome
|
|
make publier DEPOT=ops-chezlepro
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
RACINE = Path(__file__).resolve().parent.parent
|
|
DEPOTS = RACINE.parent
|
|
|
|
|
|
def git(depot: Path, *args: str) -> subprocess.CompletedProcess:
|
|
return subprocess.run(["git", "-C", str(depot), *args], capture_output=True, text=True)
|
|
|
|
|
|
def genome() -> list[dict]:
|
|
r = subprocess.run(["ansible-inventory", "-i", "scripts/site_inventaire.py", "--host", "site-ops-01"],
|
|
capture_output=True, text=True, cwd=RACINE, env=os.environ)
|
|
try:
|
|
return json.loads(r.stdout).get("serveur_ops_depots") or []
|
|
except ValueError:
|
|
raise SystemExit("Inventaire du site illisible : la liste du genome est inconnue.\n" + r.stderr[:300])
|
|
|
|
|
|
def main() -> int:
|
|
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
ap.add_argument("--depot", default="", help="un seul depot (nom sur la forge)")
|
|
args = ap.parse_args()
|
|
|
|
liste = [d for d in genome() if not args.depot or d["depot"] == args.depot]
|
|
if not liste:
|
|
raise SystemExit(f"Aucun depot du genome ne s'appelle « {args.depot} ».")
|
|
|
|
refus = []
|
|
for d in liste:
|
|
depot = DEPOTS / d["dest"]
|
|
if not (depot / ".git").is_dir():
|
|
print(f" - {d['depot']:<17} pas de copie sur ce poste — rien a publier")
|
|
continue
|
|
branche = git(depot, "branch", "--show-current").stdout.strip()
|
|
if git(depot, "remote", "get-url", "eregion").returncode != 0:
|
|
print(f" - {d['depot']:<17} aucun remote `eregion`")
|
|
continue
|
|
git(depot, "fetch", "-q", "eregion")
|
|
distant = f"eregion/{branche}"
|
|
if git(depot, "rev-parse", "--verify", "-q", distant).returncode == 0:
|
|
manquants = git(depot, "rev-list", "--count", f"HEAD..{distant}").stdout.strip()
|
|
if manquants not in ("", "0"):
|
|
refus.append(d["depot"])
|
|
print(f" !! {d['depot']:<17} eregion porte {manquants} commit(s) absent(s) du poste "
|
|
f"— les integrer d'abord (`git pull --rebase eregion {branche}`)")
|
|
continue
|
|
sale = [l for l in git(depot, "status", "--porcelain").stdout.splitlines() if l.strip()]
|
|
if sale:
|
|
print(f" ~ {d['depot']:<17} {len(sale)} changement(s) NON committe(s) — ils ne partent pas")
|
|
avance = git(depot, "rev-list", "--count", f"{distant}..HEAD").stdout.strip() or "?"
|
|
r = git(depot, "push", "-q", "eregion", branche)
|
|
if r.returncode != 0:
|
|
refus.append(d["depot"])
|
|
print(f" !! {d['depot']:<17} push refuse : {r.stderr.strip()[:120]}")
|
|
continue
|
|
print(f" ok {d['depot']:<17} eregion a jour ({avance} commit(s) pousse(s))")
|
|
|
|
if refus:
|
|
print(f"\nREFUS : {', '.join(refus)}. Rien n'a ete porte a la forge du site — la corriger "
|
|
f"en retard vaut mieux que la corriger avec un depot incomplet.")
|
|
return 2
|
|
|
|
print("\nPorter a la forge du site (runner) :")
|
|
env = dict(os.environ, **({"DEPOT": args.depot} if args.depot else {}))
|
|
if subprocess.run(["make", "--no-print-directory", "genome-pousser"] + ([f"DEPOT={args.depot}"] if args.depot else []),
|
|
cwd=RACINE, env=env, capture_output=True).returncode != 0:
|
|
print(" ECHEC de `make genome-pousser` : eregion est a jour, la forge du site NON.")
|
|
return 3
|
|
r = subprocess.run(["make", "--no-print-directory", "genome-etat"], cwd=RACINE,
|
|
capture_output=True, text=True)
|
|
for ligne in r.stdout.splitlines():
|
|
if '"msg": "' in ligne and " : poste " in ligne:
|
|
print(" " + ligne.split('"msg": "', 1)[1].replace("\\n", " ").rstrip('"'))
|
|
if r.returncode != 0:
|
|
print(" La forge du site ne porte PAS la tete du poste — voir `make genome-etat`.")
|
|
return 4
|
|
print("Publie : eregion et la forge du site portent la tete du poste.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|