Skip to content

cli

cli

terok-matrix — run a repo's multi-distro test matrix.

The operator-facing entry point: load the repo's matrix.yml, then walk the selected slots — build every image first (a failed build is recorded, not fatal, so one run surfaces every distro's problems), run each slot's test container, and close with the classic PASS/SKIP/FAIL summary.

Teardown (sweep leftover containers, prune dangling image generations) runs however the walk ends — failure, --build-only, Ctrl-C. Every rebuild retags the slot images, so a walk that skips teardown strands the previous multi-GB generation of the whole fleet; only --keep-dangling opts out, deliberately.

--slots-json exists for CI: a workflow derives its strategy.matrix from the same matrix.yml the local runs use, so the slot list has a single home.

DEFAULT_CONFIG = Path('tests/containers/matrix.yml') module-attribute

EXIT_INTERRUPTED = 130 module-attribute

BOLD = '\x1b[1m' if _TTY else '' module-attribute

CYAN = '\x1b[1;36m' if _TTY else '' module-attribute

YELLOW = '\x1b[1;33m' if _TTY else '' module-attribute

GREEN = '\x1b[1;32m' if _TTY else '' module-attribute

RED = '\x1b[1;31m' if _TTY else '' module-attribute

DIM = '\x1b[2m' if _TTY else '' module-attribute

TAG = '\x1b[2;38;5;67m' if _TTY and '256color' in os.environ.get('TERM', '') else DIM module-attribute

RESET = '\x1b[0m' if _TTY else '' module-attribute

main(argv=None)

Run the matrix; exit 1 when any slot failed, 130 after a Ctrl-C.

Source code in src/terok_util/matrix/cli.py
def main(argv: list[str] | None = None) -> int:
    """Run the matrix; exit 1 when any slot failed, 130 after a Ctrl-C."""
    args = _parse_args(argv)
    try:
        config = load_config(args.config)
    except (OSError, MatrixConfigError) as error:
        print(f"{RED}Error: {error}{RESET}", file=sys.stderr)
        return 2

    targets = list(args.slots or config.slots)
    unknown = [name for name in targets if name not in config.slots]
    if unknown:
        print(
            f"{RED}Error: unknown slot(s) {unknown}. Available: {list(config.slots)}{RESET}",
            file=sys.stderr,
        )
        return 2

    if args.list:
        for name in sorted(targets):
            expectation = _version_expectation(config, name)
            print(f"{name} ({expectation})" if expectation else name)
        return 0
    if args.slots_json:
        print(json.dumps(targets))
        return 0
    if args.image_prefix:
        print(config.image_prefix)
        return 0

    _warn_keyring()
    with tempfile.TemporaryDirectory(prefix=f"{config.image_prefix}-matrix-") as scratch:
        results_dir = Path(scratch)
        # The container's uid-1000 user (an unknown host subuid) must write
        # its observed-version files here, so the dir is world-writable -
        # with the sticky bit, so other host accounts cannot replace the
        # generated scripts podman is about to execute.
        results_dir.chmod(0o1777)
        try:
            return _run_matrix(config, targets, args, results_dir)
        except OSError as error:
            print(f"{RED}Error: {error}{RESET}", file=sys.stderr)
            return 2