Updated by fix-consistency on 2026-03-27: - update .custodian-brief.md for the-custodian
62 lines
1.7 KiB
Python
62 lines
1.7 KiB
Python
"""
|
|
Parse and validate e2e.yml — the per-repo test contract.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import yaml
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
from typing import Literal
|
|
|
|
|
|
@dataclass
|
|
class HealthCheck:
|
|
name: str
|
|
url: str
|
|
timeout: int = 120 # seconds
|
|
|
|
|
|
@dataclass
|
|
class E2EConfig:
|
|
name: str
|
|
compose_file: str # relative to repo root
|
|
test_command: str
|
|
health_checks: list[HealthCheck] = field(default_factory=list)
|
|
timeout: int = 300 # hard limit for test_command
|
|
cleanup: Literal["always", "on_success", "never"] = "always"
|
|
env: dict[str, str] = field(default_factory=dict)
|
|
|
|
@classmethod
|
|
def load(cls, repo_root: Path) -> "E2EConfig":
|
|
config_path = repo_root / "e2e" / "e2e.yml"
|
|
if not config_path.exists():
|
|
raise FileNotFoundError(f"No e2e.yml found at {config_path}")
|
|
|
|
raw = yaml.safe_load(config_path.read_text())
|
|
|
|
health_checks = [
|
|
HealthCheck(
|
|
name=hc.get("name", hc["url"]),
|
|
url=hc["url"],
|
|
timeout=int(hc.get("timeout", 120)),
|
|
)
|
|
for hc in raw.get("health_checks", [])
|
|
]
|
|
|
|
env = {}
|
|
for item in raw.get("env", []):
|
|
if isinstance(item, dict) and "key" in item:
|
|
env[item["key"]] = str(item.get("value", ""))
|
|
elif isinstance(item, dict):
|
|
env.update(item)
|
|
|
|
return cls(
|
|
name=raw["name"],
|
|
compose_file=raw["compose_file"],
|
|
test_command=raw["test_command"],
|
|
health_checks=health_checks,
|
|
timeout=int(raw.get("timeout", 300)),
|
|
cleanup=raw.get("cleanup", "always"),
|
|
env=env,
|
|
)
|