#!/usr/bin/env python3 """Run all molecule scenarios on all supported OS platforms. Replaces the previous ``scripts/molecule_all.sh`` with a tested Python equivalent. Sequential execution — CI uses the parallel matrix instead. Usage:: python3 scripts/molecule_all.py python3 scripts/molecule_all.py --bin .venv/bin """ from __future__ import annotations import os import subprocess # nosec B404 import sys from pathlib import Path import click from scripts.ci.platforms import PLATFORMS ROLE_DIR = Path("ansible/roles/gitea-runner") SCENARIOS = ["default", "multi-instance", "lifecycle", "template-content", "deregister", "update"] def _run_molecule(molecule_bin: str, scenario: str, role_dir: Path, env: dict[str, str]) -> int: """Run a single molecule scenario. Returns the exit code.""" cmd = [molecule_bin, "test"] if scenario != "default": cmd.extend(["-s", scenario]) click.echo(f"--- Scenario: {scenario} ---") result = subprocess.run( # nosec B603 cmd, cwd=str(role_dir), env=env, ) return result.returncode def _run_platform( molecule_bin: str, platform: dict[str, str], role_dir: Path, scenarios: list[str], base_env: dict[str, str], ) -> int: """Run all scenarios for a single platform. Returns the first non-zero exit code.""" env = dict(base_env) env["MOLECULE_PLATFORM_NAME"] = platform["name"] env["MOLECULE_PLATFORM_IMAGE"] = platform["image"] if platform.get("command"): env["MOLECULE_PLATFORM_COMMAND"] = platform["command"] else: env.pop("MOLECULE_PLATFORM_COMMAND", None) click.echo(f"=== Platform: {platform['name']} ===") for scenario in scenarios: rc = _run_molecule(molecule_bin, scenario, role_dir, env) if rc != 0: return rc return 0 @click.command() @click.option("--bin", "bin_dir", default=".venv/bin", help="Path to the virtualenv bin directory.") def main(bin_dir: str) -> None: """Run all molecule scenarios on all supported OS platforms sequentially.""" molecule_bin = str(Path(bin_dir) / "molecule") if not Path(molecule_bin).exists(): raise click.ClickException(f"molecule not found at {molecule_bin}. Run 'make setup' first.") if not ROLE_DIR.exists(): raise click.ClickException(f"Role directory not found: {ROLE_DIR}") base_env = dict(os.environ) base_env["ANSIBLE_ALLOW_BROKEN_CONDITIONALS"] = "true" base_env["ANSIBLE_INJECT_INVOCATION"] = "1" for platform in PLATFORMS: rc = _run_platform(molecule_bin, platform, ROLE_DIR, SCENARIOS, base_env) if rc != 0: click.echo(f"FAILED on platform {platform['name']}", err=True) sys.exit(rc) click.echo("All molecule scenarios passed on all platforms.") if __name__ == "__main__": # pragma: no cover main() # pragma: no cover