diff --git a/.config/wt.toml b/.config/wt.toml index a8fe743b..9465379b 100644 --- a/.config/wt.toml +++ b/.config/wt.toml @@ -32,6 +32,7 @@ url = "http://localhost:{{ branch | hash_port }}" [[pre-remove]] server = "lsof -ti :{{ branch | hash_port }} -sTCP:LISTEN | xargs kill 2>/dev/null || true" -# The Python package lives under generator/; this alias runs pytest from the right cwd. +# Tests live in four places (generator/, proxy/, the install-tend scripts, +# worker/); dev/test.sh runs the lot, mirroring ci.yaml's test jobs. [aliases] -test = "cd generator && uv run pytest {{ args }}" +test = "dev/test.sh {{ args }}" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d32bfd81..a797b8c5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,15 +29,16 @@ repos: hooks: - id: actionlint # The composite actions' shared step bodies live in standalone scripts - # (shared/steps/, proxy/) rather than inline `run:` blocks, so - # actionlint's built-in shellcheck doesn't see them. Run shellcheck directly - # to keep that coverage. -S warning matches actionlint's default severity. + # (shared/steps/, proxy/, generator/src/tend/templates/) rather than inline + # `run:` blocks, so actionlint's built-in shellcheck doesn't see them. Run + # shellcheck directly to keep that coverage — and over dev/, which actionlint + # never sees at all. -S warning matches actionlint's default severity. - repo: https://github.com/shellcheck-py/shellcheck-py rev: v0.11.0.1 hooks: - id: shellcheck args: ["-S", "warning"] - files: ^(shared/steps/.*\.sh|generator/src/tend/templates/.*\.sh|proxy/setup-sandbox\.sh)$ + files: ^(shared/steps/.*\.sh|generator/src/tend/templates/.*\.sh|proxy/setup-sandbox\.sh|dev/.*\.sh)$ - repo: local hooks: # The Claude Code slash-command preprocessor treats a backticked token diff --git a/CLAUDE.md b/CLAUDE.md index 0a053d4e..e64fdc04 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,13 +11,16 @@ completely — old formats should fail with a clear error, not silently parse. ## Commands ```bash -wt test # run pytest in generator/ +wt test # every suite (generator/, proxy/, install-tend scripts, worker/) uvx tend@latest init # regenerate workflows from .config/tend.yaml uvx tend@latest init --dry-run # preview without writing uvx tend@latest check # verify branch protection, secrets, bot access -pre-commit run --all-files # lint: ruff, typos, actionlint, uv-lock +pre-commit run --all-files # lint: ruff, typos, actionlint, shellcheck, uv-lock ``` +`wt test` runs [`dev/test.sh`](dev/test.sh), which mirrors the test jobs in +`ci.yaml`; arguments go to the pytest suites (`wt test -k render`). + ## Architecture Four pieces: @@ -106,8 +109,8 @@ from `.config/tend.yaml`. Edit the generator or config, not the workflow files directly. The generator is a Python package under `generator/` — uses the uv_build -backend, requires Python 3.11+. Runtime dependencies: click, ruamel.yaml. -Dev dependencies: pytest, pytest-regtest. +backend, requires Python 3.11+. Runtime dependencies: click, jinja2, +ruamel.yaml. Dev dependencies: pytest, pytest-regtest. Consuming repos regenerate their `tend-*.yaml` workflows nightly (tend itself included — it dogfoods its own workflows). Changes to the generator do not diff --git a/dev/test.sh b/dev/test.sh new file mode 100755 index 00000000..5bd424fe --- /dev/null +++ b/dev/test.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# Every test suite in the repo, mirroring the test jobs in +# .github/workflows/ci.yaml. `wt test` runs this (see .config/wt.toml), so one +# command covers generator/, proxy/, the install-tend scripts, and worker/. +# +# Arguments are forwarded to the pytest suites (`wt test -k render`); a filtered +# run skips worker/, whose vitest CLI takes different flags. Every suite runs +# even if an earlier one fails, and the failures are listed at the end. +set -o pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")/.." || exit 1 + +failed=() + +# suite