79 lines
2.9 KiB
Python
79 lines
2.9 KiB
Python
"""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"
|
|
)
|