name: CI on: push: pull_request: permissions: contents: read jobs: compose: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Validate Compose configuration run: docker compose config - name: Compile stdlib container code run: python3 -m compileall -q apps/api apps/web - name: Run API tests run: python3 -m unittest discover -s apps/api/tests -t apps/api - name: Build images run: docker compose build - name: Start services run: docker compose up -d - name: Wait for healthy services and smoke test run: | set -eu for i in $(seq 1 30); do api_status=$(docker inspect --format '{{.State.Health.Status}}' "$(docker compose ps -q api)") web_status=$(docker inspect --format '{{.State.Health.Status}}' "$(docker compose ps -q web)") if [ "$api_status" = healthy ] && [ "$web_status" = healthy ]; then docker compose exec -T api python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/v1/health/live', timeout=2)" docker compose exec -T web python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/healthz', timeout=2)" exit 0 fi sleep 2 done docker compose ps docker compose logs exit 1 - name: Tear down if: always() run: docker compose down -v