Set-OPS-Public/scripts/tests/test_genome_colis.py
Daniel Allaire e8907285d5 publier : les releases voyagent jusqu'aux deux forges ; wiki publie sur la forge du site
Le colis du genome ne portait que la branche : les etiquettes de release
n'arrivaient jamais sur la forge du site. Il les porte desormais, le runner les
pousse sans forcer, et la forge est relue par son API. publier.py pousse aussi
les etiquettes vers eregion. Le wiki, jamais publie sur la forge du site, l'est.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 19:04:31 -04:00

112 lines
4.7 KiB
Python

#!/usr/bin/env python3
"""`genome_colis.py` : le colis porte la branche ET les releases jusqu'à la forge du site.
POURQUOI (2026-10-07). Le colis ne portait que `main`. Les étiquettes de release
n'arrivaient donc jamais sur la forge du site, qui fait autorité (D-81) : `v2026.08.21` et
`v2026.10.07` y manquaient, et il a fallu les pousser à la main.
Sur de vrais dépôts git, dans un répertoire jetable (aucun réseau) :
- un poste, une forge nue, un runner cloné depuis la forge ;
- le poste fait un commit et étiquette une release ; `emballer`, puis `recevoir` sur le
runner, avec la forge pour `pushurl` ;
- la forge porte la nouvelle tête ET l'étiquette ; un dépôt sans étiquette passe aussi ;
- une étiquette déplacée sur le poste est REFUSÉE : une release ne bouge pas.
"""
from __future__ import annotations
import json
import os
import subprocess
import sys
import tempfile
from pathlib import Path
RACINE = Path(__file__).resolve().parents[2]
COLIS = RACINE / "scripts" / "genome_colis.py"
ENV = {**os.environ, "GIT_AUTHOR_NAME": "t", "GIT_AUTHOR_EMAIL": "t@t", "GIT_COMMITTER_NAME": "t",
"GIT_COMMITTER_EMAIL": "t@t", "GIT_CONFIG_GLOBAL": os.devnull, "GIT_CONFIG_NOSYSTEM": "1"}
ECHECS: list[str] = []
def verifier(cond: bool, msg: str) -> None:
print(("OK " if cond else "ECHEC ") + msg)
if not cond:
ECHECS.append(msg)
def git(*args: str, cwd: Path | None = None) -> str:
r = subprocess.run(["git", *args], cwd=cwd, capture_output=True, text=True, env=ENV)
if r.returncode != 0:
raise RuntimeError(f"git {' '.join(args)} : {r.stderr.strip()}")
return r.stdout.strip()
def colis(*args: str) -> subprocess.CompletedProcess:
return subprocess.run([sys.executable, str(COLIS), *args], capture_output=True, text=True, env=ENV)
def monter(d: Path) -> tuple[Path, Path, Path]:
forge, poste, runner = d / "forge.git", d / "poste", d / "runner"
git("init", "-q", "--bare", "-b", "main", str(forge))
git("init", "-q", "-b", "main", str(poste))
(poste / "a").write_text("1")
git("add", "a", cwd=poste)
git("commit", "-q", "-m", "un", cwd=poste)
git("push", "-q", str(forge), "main", cwd=poste)
git("clone", "-q", str(forge), str(runner))
return forge, poste, runner
def porter(poste: Path, runner: Path, forge: Path, d: Path) -> subprocess.CompletedProcess:
paquet = d / "x.bundle"
e = colis("emballer", str(poste), str(paquet))
if e.returncode != 0:
return e
return colis("recevoir", str(runner), str(paquet), str(forge))
def main() -> int:
with tempfile.TemporaryDirectory() as d:
d = Path(d)
forge, poste, runner = monter(d)
# Un depot sans etiquette : rien ne change pour lui.
(poste / "a").write_text("2")
git("commit", "-q", "-am", "deux", cwd=poste)
r = porter(poste, runner, forge, d)
verifier(r.returncode == 0 and git("rev-parse", "main", cwd=forge) == git("rev-parse", "HEAD", cwd=poste),
f"sans etiquette : la forge porte la tete du poste ({r.stderr.strip()[-160:]})")
# Une release annotee.
(poste / "a").write_text("3")
git("commit", "-q", "-am", "trois", cwd=poste)
git("tag", "-a", "v1", "-m", "release v1", cwd=poste)
r = porter(poste, runner, forge, d)
recu = json.loads(r.stdout) if r.returncode == 0 else {}
verifier(r.returncode == 0 and "v1" in git("tag", "-l", cwd=forge).split(),
f"la release voyage jusqu'a la forge ({r.stderr.strip()[-160:]})")
verifier(git("rev-parse", "v1", cwd=forge) == git("rev-parse", "v1", cwd=poste),
"la forge porte le MEME objet d'etiquette que le poste (annotee, pas recreee)")
verifier(recu.get("etiquettes") == ["v1"], f"le runner dit les etiquettes qu'il porte ({recu.get('etiquettes')})")
e = json.loads(colis("emballer", str(poste), str(d / "y.bundle")).stdout)
verifier(e.get("etiquettes") == ["v1"], "l'emballage dit les etiquettes du poste")
# Une release deplacee sur le poste : refusee, la forge garde l'ancienne.
ancienne = git("rev-parse", "v1", cwd=forge)
(poste / "a").write_text("4")
git("commit", "-q", "-am", "quatre", cwd=poste)
git("tag", "-f", "-a", "v1", "-m", "v1 deplacee", cwd=poste)
r = porter(poste, runner, forge, d)
verifier(r.returncode != 0 and git("rev-parse", "v1", cwd=forge) == ancienne,
f"une etiquette deplacee est refusee, la forge garde la release ({r.stderr.strip()[-120:]})")
if ECHECS:
print(f"\n{len(ECHECS)} echec(s).")
return 1
print("\nLe colis porte la branche et les releases ; une release ne bouge pas.")
return 0
if __name__ == "__main__":
sys.exit(main())