#!/usr/bin/env python3 """Project setup: install Python deps, Ansible collections, and pre-commit hooks. Also configures the ``tea`` Gitea CLI login profile from ``.env`` so that CI scripts and dev tools can use ``tea`` for Gitea API operations. Usage:: python3 scripts/setup.py --bin .venv/bin """ from __future__ import annotations import os import shutil import subprocess # nosec B404 from pathlib import Path import click from dotenv import load_dotenv # pyright: ignore[reportMissingImports,reportUnknownVariableType] load_dotenv(override=True) def _run(cmd: list[str], bin_dir: str) -> None: """Run a command, streaming output to stdout/stderr.""" click.echo(f" $ {' '.join(cmd)}") subprocess.run(cmd, check=True) # nosec B603 def _install_python_deps(bin_dir: str) -> None: """Install the project with dev extras in editable mode.""" pip = str(Path(bin_dir) / "pip") _run([pip, "install", "-e", ".[dev]"], bin_dir) def _install_ansible_collections(bin_dir: str) -> None: """Install required Ansible Galaxy collections.""" galaxy = str(Path(bin_dir) / "ansible-galaxy") requirements = Path("ansible/requirements.yml") if not requirements.exists(): click.echo(" ansible/requirements.yml not found — skipping collections.") return _run([galaxy, "collection", "install", "-r", str(requirements)], bin_dir) def _install_pre_commit_hooks(bin_dir: str) -> None: """Install pre-commit hooks for commit-msg, pre-commit, and pre-push.""" pre_commit = str(Path(bin_dir) / "pre-commit") for hook_type in ["pre-commit", "commit-msg", "pre-push"]: _run([pre_commit, "install", "--hook-type", hook_type], bin_dir) def _configure_tea_login() -> None: """Configure tea CLI login from .env if REPO_TOKEN is set. Idempotent: if a login with the same name already exists, it is not re-added. Skips silently if tea is not installed or REPO_TOKEN is not set. """ tea_bin = shutil.which("tea") if tea_bin is None: click.echo("tea: not installed — skipping login configuration.") return token = os.environ.get("REPO_TOKEN", "") if not token: click.echo("tea: REPO_TOKEN not set — skipping login configuration.") return # Derive the Gitea URL from the API URL (strip /api/v1 suffix) api_url = os.environ.get("GRM_GITEA_API_URL", "https://git.oblachno.oblachno.fyi/api/v1") gitea_url = api_url.replace("/api/v1", "") login_name = "grm" # Check if login already exists result = subprocess.run( # nosec B603 [tea_bin, "login", "list", "--output", "simple"], capture_output=True, text=True, check=False, ) if result.returncode == 0 and login_name in result.stdout: click.echo(f"tea: login '{login_name}' already configured.") return # Add login profile click.echo(f"tea: configuring login '{login_name}' for {gitea_url}...") add_result = subprocess.run( # nosec B603 [tea_bin, "login", "add", "--name", login_name, "--url", gitea_url, "--token", token], capture_output=True, text=True, check=False, ) if add_result.returncode != 0: click.echo(f"tea: login configuration failed: {add_result.stderr.strip()}", err=True) else: # Set as default login subprocess.run( # nosec B603 [tea_bin, "login", "default", login_name], capture_output=True, text=True, check=False, ) click.echo(f"tea: login '{login_name}' configured and set as default.") def _verify(bin_dir: str) -> None: """Print versions of installed tools for verification.""" grm = str(Path(bin_dir) / "grm") pre_commit = str(Path(bin_dir) / "pre-commit") for tool in [grm, pre_commit]: try: result = subprocess.run([tool, "--version"], capture_output=True, text=True, timeout=10) # nosec B603 if result.returncode == 0: click.echo(f" {result.stdout.strip()}") except (FileNotFoundError, subprocess.TimeoutExpired): pass @click.command() @click.option("--bin", "bin_dir", default=".venv/bin", help="Path to the virtualenv bin directory.") def main(bin_dir: str) -> None: """Install Python deps, Ansible collections, and pre-commit hooks.""" if not Path(bin_dir).exists(): raise click.ClickException(f"Bin directory not found: {bin_dir}. Run 'python3 -m venv .venv' first.") click.echo("Installing Python dependencies...") _install_python_deps(bin_dir) click.echo("Installing Ansible collections...") _install_ansible_collections(bin_dir) click.echo("Installing pre-commit hooks...") _install_pre_commit_hooks(bin_dir) click.echo("Configuring tea CLI login...") _configure_tea_login() click.echo("") click.echo("Setup complete.") click.echo("Activate the virtual environment with one of:") click.echo(" source .venv/bin/activate (generic)") click.echo(" source activate.sh (bash)") click.echo(" source activate.fish (fish)") click.echo(" source activate.zsh (zsh)") click.echo("") _verify(bin_dir) if __name__ == "__main__": # pragma: no cover main() # pragma: no cover