publier : eregion et la forge du site en un seul geste, verifie
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>
This commit is contained in:
parent
974fabc40a
commit
91dc90f22b
4 changed files with 144 additions and 0 deletions
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -1,5 +1,21 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-09-28 (20) — `make publier` : eregion ET la forge du site, en un geste
|
||||
|
||||
**Le défaut.** La forge du site fait autorité (D-81), mais les commits naissent sur le poste
|
||||
et n'y arrivent que par `make genome-pousser` — un geste à part, que rien ne force ni ne
|
||||
signale. Un `git push` vers eregion la laisse en retard. Le 2026-08-26 : quatre commits,
|
||||
dont le correctif du pare-feu Proxmox. Aujourd'hui même, `make genome-etat` la trouvait en
|
||||
retard d'un commit.
|
||||
|
||||
**`make publier`** (`scripts/publier.py`), pour chaque dépôt que le runner du site porte —
|
||||
la liste de `genome-pousser` (`serveur_ops_depots`), lue et non recopiée : refuse si
|
||||
eregion porte des commits absents du poste (une fusion acceptée serait écrasée sur la forge
|
||||
du site), signale ce qui n'est pas committé, pousse sur eregion ; puis `genome-pousser`,
|
||||
puis `genome-etat`, et dit si la forge du site porte bien la tête du poste. Un refus arrête
|
||||
tout AVANT la forge du site : mieux vaut la laisser en retard que la nourrir d'un dépôt
|
||||
incomplet. Ce commit est le premier publié ainsi.
|
||||
|
||||
## 2026-09-28 (19) — Chaque semaine, chaque sauvegarde est rouverte pour de vrai
|
||||
|
||||
**Le trou.** `sauvegarde` disait qu'un instantané existe, récent et non vide ; rien ne disait
|
||||
|
|
|
|||
7
Makefile
7
Makefile
|
|
@ -1269,6 +1269,13 @@ genome-etat: ## Ce que la forge du site porte, face au poste — ne corrige rien
|
|||
playbooks/maintenance/genome_etat.yml "$${supp[@]}" $(ARGS)
|
||||
|
||||
.PHONY: genome-pousser
|
||||
publier: ## Publie le genome d'un geste : eregion PUIS la forge du site, et le verifie — DEPOT=<nom> pour un seul
|
||||
@# LE RETARD VIENT D'UN GESTE QU'ON OUBLIE (2026-09-28) : un `git push` vers eregion ne
|
||||
@# met pas la forge du site a jour, et c'est elle qui fait autorite. Refuse si eregion
|
||||
@# porte des commits absents du poste (une fusion acceptee) — ne pas les ecraser.
|
||||
python3 scripts/publier.py $(if $(DEPOT),--depot "$(DEPOT)")
|
||||
|
||||
.PHONY: publier
|
||||
genome-pousser: ## Le runner du site pousse le genome sur la forge du site — DEPOT=<nom> pour un seul
|
||||
@set -e; \
|
||||
voute="$$(dirname "$$(readlink -f underlay.yml)")/underlay.vault.yml"; \
|
||||
|
|
|
|||
|
|
@ -144,6 +144,12 @@ runbooks:
|
|||
pourquoi: >-
|
||||
Second passage. Celui-ci doit finir a zero echec ; s'il n'y arrive pas, c'est
|
||||
un vrai defaut, plus un maillon manquant.
|
||||
- cible: publier
|
||||
nature: ecriture
|
||||
variables: [DEPOT]
|
||||
pourquoi: >-
|
||||
Le geste quotidien : eregion ET la forge du site, puis la verification. Un
|
||||
`git push` seul laisse la forge du site en retard sans que rien le dise.
|
||||
- cible: genome-pousser
|
||||
nature: ecriture
|
||||
variables: [DEPOT]
|
||||
|
|
|
|||
115
scripts/publier.py
Normal file
115
scripts/publier.py
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#!/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())
|
||||
Loading…
Reference in a new issue