chore: add docker-based test environment (#13)
Reproducible Python 3.12-slim container that installs the project editable with dev deps. Adds pytest-asyncio to dev deps so async tests run cleanly inside the container (host had it installed out-of-band). scripts/docker-test.sh provides build, test, ask, replay, and shell subcommands. The ask/replay/shell commands mount ~/secrets read-only and ~/.marchwarden read-write so end-to-end runs persist traces back to the host. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bca7294ec8
commit
40d0725497
5 changed files with 116 additions and 0 deletions
15
.dockerignore
Normal file
15
.dockerignore
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.venv
|
||||||
|
docs/wiki
|
||||||
|
**/__pycache__
|
||||||
|
**/*.pyc
|
||||||
|
**/*.pyo
|
||||||
|
*.egg-info
|
||||||
|
.pytest_cache
|
||||||
|
.mypy_cache
|
||||||
|
.ruff_cache
|
||||||
|
.coverage
|
||||||
|
htmlcov
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
24
Dockerfile
Normal file
24
Dockerfile
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
||||||
|
PIP_NO_CACHE_DIR=1
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install build deps separately so the layer caches when source changes.
|
||||||
|
COPY pyproject.toml README.md ./
|
||||||
|
RUN pip install --upgrade pip
|
||||||
|
|
||||||
|
# Copy the project and install editable with dev extras.
|
||||||
|
COPY cli ./cli
|
||||||
|
COPY researchers ./researchers
|
||||||
|
COPY orchestrator ./orchestrator
|
||||||
|
COPY tests ./tests
|
||||||
|
RUN pip install -e ".[dev]"
|
||||||
|
|
||||||
|
# Trace files land here; mount a volume to persist across runs.
|
||||||
|
RUN mkdir -p /root/.marchwarden/traces
|
||||||
|
|
||||||
|
CMD ["pytest", "-q"]
|
||||||
14
README.md
14
README.md
|
|
@ -24,6 +24,20 @@ marchwarden ask "What are ideal crops for a garden in Utah?"
|
||||||
marchwarden replay <trace_id>
|
marchwarden replay <trace_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Docker test environment
|
||||||
|
|
||||||
|
A reproducible container is available for running the test suite and the
|
||||||
|
CLI without depending on the host's Python install:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scripts/docker-test.sh build # build the image
|
||||||
|
scripts/docker-test.sh test # run pytest
|
||||||
|
scripts/docker-test.sh ask "question" # run `marchwarden ask` end-to-end
|
||||||
|
# (mounts ~/secrets ro and ~/.marchwarden rw)
|
||||||
|
scripts/docker-test.sh replay <id> # replay a trace from ~/.marchwarden/traces
|
||||||
|
scripts/docker-test.sh shell # interactive bash in the container
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- **[Architecture](https://forgejo.labbity.unbiasedgeek.com/archeious/marchwarden/wiki/Architecture)** — system design, researcher contract, MCP flow
|
- **[Architecture](https://forgejo.labbity.unbiasedgeek.com/archeious/marchwarden/wiki/Architecture)** — system design, researcher contract, MCP flow
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ dependencies = [
|
||||||
dev = [
|
dev = [
|
||||||
"pytest>=7.0",
|
"pytest>=7.0",
|
||||||
"pytest-cov>=4.0",
|
"pytest-cov>=4.0",
|
||||||
|
"pytest-asyncio>=0.21",
|
||||||
"black>=23.0",
|
"black>=23.0",
|
||||||
"ruff>=0.1.0",
|
"ruff>=0.1.0",
|
||||||
"mypy>=1.0",
|
"mypy>=1.0",
|
||||||
|
|
|
||||||
62
scripts/docker-test.sh
Executable file
62
scripts/docker-test.sh
Executable file
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Helper for the dockerized test/run environment.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# scripts/docker-test.sh build Build the image
|
||||||
|
# scripts/docker-test.sh test Run pytest in the container
|
||||||
|
# scripts/docker-test.sh ask "..." Run `marchwarden ask` end-to-end
|
||||||
|
# (mounts ~/secrets ro and ~/.marchwarden rw)
|
||||||
|
# scripts/docker-test.sh shell Drop into a bash shell in the container
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
IMAGE="marchwarden-test"
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
|
||||||
|
cmd="${1:-test}"
|
||||||
|
shift || true
|
||||||
|
|
||||||
|
case "$cmd" in
|
||||||
|
build)
|
||||||
|
docker build -t "$IMAGE" "$ROOT"
|
||||||
|
;;
|
||||||
|
|
||||||
|
test)
|
||||||
|
docker run --rm -v "$ROOT:/app" "$IMAGE" pytest -q "$@"
|
||||||
|
;;
|
||||||
|
|
||||||
|
ask)
|
||||||
|
if [ ! -f "$HOME/secrets" ]; then
|
||||||
|
echo "error: ~/secrets not found on host" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
mkdir -p "$HOME/.marchwarden/traces"
|
||||||
|
docker run --rm -it \
|
||||||
|
-v "$ROOT:/app" \
|
||||||
|
-v "$HOME/secrets:/root/secrets:ro" \
|
||||||
|
-v "$HOME/.marchwarden:/root/.marchwarden" \
|
||||||
|
"$IMAGE" marchwarden ask "$@"
|
||||||
|
;;
|
||||||
|
|
||||||
|
replay)
|
||||||
|
mkdir -p "$HOME/.marchwarden/traces"
|
||||||
|
docker run --rm \
|
||||||
|
-v "$ROOT:/app" \
|
||||||
|
-v "$HOME/.marchwarden:/root/.marchwarden" \
|
||||||
|
"$IMAGE" marchwarden replay "$@"
|
||||||
|
;;
|
||||||
|
|
||||||
|
shell)
|
||||||
|
docker run --rm -it \
|
||||||
|
-v "$ROOT:/app" \
|
||||||
|
-v "$HOME/secrets:/root/secrets:ro" \
|
||||||
|
-v "$HOME/.marchwarden:/root/.marchwarden" \
|
||||||
|
"$IMAGE" bash
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "unknown command: $cmd" >&2
|
||||||
|
echo "usage: $0 {build|test|ask|replay|shell}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Loading…
Reference in a new issue