"""Garde-fous du workflow CI Gitea (BUG-082, BUG-083). Sans dépendance (pas de PyYAML) : analyse ligne à ligne de `.gitea/workflows/ci.yml`, suffisante pour les conventions de ce fichier. """ from __future__ import annotations import re from pathlib import Path CI_YML = Path(__file__).resolve().parent.parent / ".gitea" / "workflows" / "ci.yml" def _run_bodies() -> list[tuple[int, str]]: """Toutes les lignes shell de chaque bloc `run:` → [(n° ligne, code)].""" lines = CI_YML.read_text(encoding="utf-8").splitlines() bodies: list[tuple[int, str]] = [] i = 0 while i < len(lines): m = re.match(r"^(\s*)run:(?:\s*\|\s*)?$", lines[i]) inline = re.match(r"^(\s*)run:\s+(\S.*)$", lines[i]) if m: base = len(m.group(1)) i += 1 while i < len(lines): cur = lines[i] if not cur.strip(): i += 1 continue if len(cur) - len(cur.lstrip()) <= base: break bodies.append((i + 1, cur.strip())) i += 1 elif inline: bodies.append((i + 1, inline.group(2).strip())) i += 1 else: i += 1 return bodies class TestRunnerProofScripts: def test_no_hash_inside_run_bodies(self): """BUG-083 : aucun `#` dans le code shell des `run:`. Le runner Gitea Act tronque naïvement au premier `#` (même entre guillemets) : `echo "... see #87)"` devenait une citation non fermée → `unexpected EOF while looking for matching '"'` (job `security` rouge). Les lignes-commentaires shell (`# ...`) restent autorisées : leur troncature est sémantiquement neutre. """ offenders = [ f"L{n}: {code}" for n, code in _run_bodies() if not code.startswith("#") and "#" in code ] assert not offenders, ( "BUG-083 : `#` interdit dans le code des `run:` " f"(tronqué par le runner) :\n" + "\n".join(offenders) ) class TestUploadInJsdomStep: def test_upload_runs_with_jsdom_available(self): """BUG-082 : `upload.test.mjs` (import statique `jsdom`) ne tourne que dans l'étape JSDOM, où `tests/frontend/node_modules` existe.""" text = CI_YML.read_text(encoding="utf-8") assert "Frontend JSDOM tests" in text root_part, jsdom_part = text.split("Frontend JSDOM tests", 1) root_steps = root_part.split("Frontend unit tests", 1)[1] assert "upload.test" not in root_steps, ( "BUG-082 : `upload.test.mjs` ne doit pas tourner dans l'étape " "racine (jsdom indisponible)" ) assert jsdom_part.count("node upload.test.mjs") >= 2, ( "BUG-082 : `node upload.test.mjs` attendu dans les deux branches " "de l'étape JSDOM" )