Files
computer-playbook/cli/administration/deploy/development/down.py
T
kevinveenbirkenbachandClaude Opus 4.7 13c93ad6d5 refactor(compose): drop the ci profile and its --profile ci arg everywhere
compose.yml no longer hides services behind \`profiles: ["ci"]\`. The
profile existed solely as a no-op safety net against a bare
\`docker compose up\` in the repo root, but the top-level compose.yml is
already explicitly scoped to local dev / CI testing (production goes
through the Ansible roles under roles/<role>/templates/), so the safety
net is redundant with the documented scope.

Every \`--profile ci\` callsite collapses:
- compose.yml: \`profiles: ["ci"]\` removed from coredns + infinito
- Profile.args() deleted; Profile keeps is_ci() and
  registry_cache_active() for the cache-override gating
- compose.py / down.py: profile.args() splat removed from the
  docker-compose command builder; down.py drops its now-unused
  Profile import
- 5 shell wrappers (install, lint, tests/code, meta/resolve/apps,
  meta/resolve/diff/affected_roles): plain \`docker compose\` instead
  of \`docker compose --profile ci\`
- tests/unit/.../test_profile.py: TestProfileArgs class removed
- tests/unit/.../test_compose.py: two cmd-shape asserts updated to
  reflect the missing --profile pair

Docs:
- docs/contributing/artefact/files/compose.yml.md: the
  \"every service MUST be behind a profiles: entry\" rule is gone
- docs/contributing/actions/debugging/ci.md: the
  \`docker compose ... --profile ci config\` debug snippet drops the
  flag; while touching the file the two em-dash clause separators in
  the reproduction-profiles shell block are rewritten to colons
  (documentation.md em-dash rule), and one list-item in
  compose.yml.md is collapsed to one sentence per line for
  consistency with its siblings

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 16:22:33 +02:00

77 lines
2.2 KiB
Python

from __future__ import annotations
import os
import shutil
import subprocess
from pathlib import Path
from typing import TYPE_CHECKING
from . import PROJECT_ROOT
from .common import compose_file_args, resolve_distro
if TYPE_CHECKING:
import argparse
CI_DOCKER_ROOT = Path("/mnt/docker")
CI_DOCKER_ROOT_STR = str(CI_DOCKER_ROOT)
def _base_env(*, distro: str) -> dict[str, str]:
env = dict(os.environ)
env["INFINITO_DISTRO"] = distro
return env
def _compose_run(*, repo_root: Path, distro: str, args: list[str]) -> None:
cmd = ["docker", "compose", *compose_file_args(), *args]
env = _base_env(distro=distro)
env.setdefault("NIX_CONFIG", "")
subprocess.run(cmd, cwd=repo_root, env=env, check=True, text=True)
def _cleanup_docker_root() -> None:
docker_root = CI_DOCKER_ROOT
if os.environ.get("INFINITO_RUNNING_ON_GITHUB") != "true":
print(f">>> Not on GitHub - No bind volumes will be deleted: {docker_root}")
return
docker_root_env = os.environ["INFINITO_DOCKER_VOLUME"].strip().rstrip("/")
if docker_root_env and docker_root_env != CI_DOCKER_ROOT_STR:
raise RuntimeError(
"SECURITY VIOLATION: "
f"INFINITO_DOCKER_VOLUME={docker_root_env} is not allowed on GitHub runner. "
f"Only {CI_DOCKER_ROOT_STR} is permitted."
)
if not docker_root.exists():
print(f">>> Docker root does not exist, nothing to clean: {docker_root}")
return
print(f">>> CI cleanup: wiping Docker root: {docker_root}")
shutil.rmtree(docker_root, ignore_errors=True)
docker_root.mkdir(parents=True, exist_ok=True)
def down_stack(*, repo_root: Path, distro: str) -> None:
print(">>> Stopping compose stack and removing volumes")
try:
_compose_run(
repo_root=repo_root,
distro=distro,
args=["down", "--remove-orphans", "-v"],
)
finally:
_cleanup_docker_root()
def add_parser(sub: argparse._SubParsersAction) -> None:
p = sub.add_parser("down", help="Stop compose stack and remove volumes.")
p.set_defaults(_handler=handler)
def handler(args: argparse.Namespace) -> int:
down_stack(repo_root=PROJECT_ROOT, distro=resolve_distro())
return 0