# Houndarr developer ergonomics. # # Wraps the five local quality gates documented in AGENTS.md plus a # handful of frequent workflows so contributors do not have to memorise # the exact invocations. Install just via `brew install just` (macOS) # or `cargo install just`; without just, the commands in AGENTS.md # remain the source of truth. # # Usage: # just # list all targets # just check # run every gate: lint + format + type + sast + full pytest # just quick # fast feedback loop: lint + type + non-integration pytest # just fix # apply ruff auto-fixes and reformat python := ".venv/bin/python" pytest := ".venv/bin/pytest" # Worker count for the test recipes that are safe to parallelise. # `auto` picks the physical-CPU count (psutil-aware). Override via # `PYTEST_WORKERS=4 just test` for CI runners with constrained cores # or `PYTEST_WORKERS=0 just test` to fall back to serial when # debugging an ordering-sensitive flake. Browser e2e + visual # baseline recipes ignore this and stay serial because they share a # single Houndarr instance + mock-arr stack on fixed ports (one of # the canonical pytest-xdist anti-patterns). workers := env_var_or_default("PYTEST_WORKERS", "auto") # Default target: list every recipe. default: @just --list # Run all five gates in CI order. Matches the mandatory sequence in AGENTS.md. check: lint fmt-check type sec test # Fast feedback loop: skip format-check, bandit, and integration tests. quick: lint type test-quick # Individual gates lint: {{python}} -m ruff check src/ tests/ fmt-check: {{python}} -m ruff format --check src/ tests/ type: {{python}} -m mypy src/ sec: {{python}} -m bandit -r src/ -c pyproject.toml test: {{pytest}} -n {{workers}} test-quick: {{pytest}} -n {{workers}} -m "not integration" # Run a filtered subset (single file, single test, keyword, etc.) under # the same parallelism + non-integration marker that test-quick uses. # Forwards every remaining positional argument straight to pytest. # When the first forwarded argument starts with a dash, prefix the # command with `just --` so just does not interpret the dash as one of # its own options: # just test-one tests/test_errors.py # just test-one tests/test_errors.py::TestInstanceValidationPublicMessage # just -- test-one -k csrf -v test-one *ARGS: {{pytest}} -n {{workers}} -m "not integration" {{ARGS}} test-integration: {{pytest}} -n {{workers}} -m integration tests/test_e2e/ # Run only characterisation (pinning) tests: the safety net that locks # current behaviour so a later refactor cannot drift it silently. pin: {{pytest}} -n {{workers}} -m pinning # Backwards-compatible alias kept for muscle memory; equivalent to # `just test` now that parallelism is the default. Use # `PYTEST_WORKERS=0 just test` when you need a serial run. test-parallel: {{pytest}} -n auto # Apply ruff auto-fixes and reformat in place. fix: {{python}} -m ruff check --fix src/ tests/ {{python}} -m ruff format src/ tests/ # Hydrate the dev venv (idempotent). Run before `just dev` on a fresh clone # or after dependency edits. Symphony's Stage D bring-up uses this as # `webapp.build_cmd` so the `.venv/bin/python` referenced by `serve` is # guaranteed to exist before the screencast recorder targets the server. sync: uv sync # Start the dev server against ./data-dev with hot-reload and debug logs. dev: {{python}} -m houndarr --data-dir ./data-dev --dev # Start the server without hot-reload, suitable for Stage D recording. # Symphony's screencast catches a gray-flicker frame if uvicorn reloads # mid-recording, so the Stage D bring-up uses this recipe instead of `dev`. serve: {{python}} -m houndarr --data-dir ./data-dev # Launch the seeded mock *arr server. Mounts all six apps under one process # at distinct path prefixes (e.g. http://127.0.0.1:9100/sonarr). `items` # controls the approximate leaf count per app; `seed` makes the data # deterministic so two runs produce identical IDs. mock-arr port='9100' items='500' seed='42': {{python}} -m tests.mock_arr.server --port {{port}} --items {{items}} --seed {{seed}} # Browser e2e against a Docker-Compose stack. Assumes the image is built # and mock-sonarr / mock-radarr are reachable on the shared network. # Host env: HOUNDARR_URL, MOCK_SONARR_URL, MOCK_RADARR_URL, HOUNDARR_E2E_USER, # HOUNDARR_E2E_PASS. test-browser browser="chromium": {{pytest}} tests/e2e_browser/ --confcutdir tests/e2e_browser --browser {{browser}} -q # Build the houndarr:e2e image (idempotent), create the arr-net docker # network, start mock-sonarr + mock-radarr + houndarr-e2e, and wait for # Houndarr health. Leaves the stack running so a maintainer can iterate # manually (pytest, curl, browser inspection). Tear down with `just e2e-down`. e2e-up: bash scripts/e2e_browser/capture_baselines.sh up # Tear the e2e stack down: docker rm -f the three containers, remove the # arr-net network, delete /tmp/houndarr-e2e-data. Idempotent. e2e-down: bash scripts/e2e_browser/capture_baselines.sh down # Print the commit history since the branch last matched main. log: git log --oneline main..HEAD