From 66fea705640e863041e33cfe37570d6261f4a9a1 Mon Sep 17 00:00:00 2001 From: maziggy Date: Sun, 24 May 2026 13:31:50 +0200 Subject: [PATCH] ci(docker): full backend suite in Docker, 4-way matrix shard, GHA cache backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Earlier patch trimmed the duplicate unit-test re-run from docker-test to drop a 5-10 min job that wasn't adding coverage. But "wasn't adding coverage" only holds for pure-logic tests — system-touching tests (ffmpeg version probes, ftp clients, subprocess shell-outs, locale/ timezone-sensitive assertions, paths) genuinely can pass on the GHA host and fail in python:3.13-slim. Curation via a `docker_env` marker is fragile (new tests get forgotten); gating on `main` only defers the cost without removing it. Instead, run the full backend suite IN Docker on every PR but make it fast: - New docker-backend-tests job runs the same 4-way pytest-split matrix as the host backend-tests, just inside the test image. - docker/setup-buildx-action + docker/build-push-action@v5 with cache-from/cache-to: type=gha,scope=backend-test persist the BuildKit cache (pip-install layer included) across CI runs and across the 4 sibling shards. Cold build is ~150s/shard; warm build drops to ~10s/shard. - fail-fast: false so a single failing shard surfaces the rest's output too. Total CI wall-clock for a PR push is now gated by docker-test (the image-build + integration HTTP smoke + integration test suite job) at ~3 min, not by the unit-test re-run anymore. The earlier ci.yml step that ran `docker compose run --rm backend-test` synchronously in the docker-test job stays removed — the new docker-backend-tests matrix covers the same ground and is much faster. --- .github/workflows/ci.yml | 63 +++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03e202eae..5bf8e925a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -279,6 +279,56 @@ jobs: # Docker Tests (matches test_docker.sh) # ============================================================================ + # Run the FULL backend test suite inside the test image, sharded 4-way + # so wall-clock matches the host-side backend-tests job. Catches the + # rare-but-real cases where a test passes on the GHA host but fails in + # the python:3.13-slim test image (system-binary version differences, + # locale/timezone, container vs host user, cwd assumptions). Without + # sharding this was a 5-10 min single-runner job; with sharding it's + # ~120-150s per shard running in parallel, gated by max(shard). + docker-backend-tests: + name: Docker Backend Tests (shard ${{ matrix.shard }}/4) + runs-on: ubuntu-latest + if: github.event_name == 'push' || github.event.pull_request.user.login != github.repository_owner + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Build the backend-test image with GHA BuildKit cache backend so + # the pip-install layer is shared across the 4 matrix shards AND + # across CI runs. First run on a given requirements.txt is cold + # (~60-90s); subsequent runs are ~5-10s. + - name: Build backend test image (cached) + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile.test + target: backend-test + load: true + tags: bambuddy-backend-test:latest + cache-from: type=gha,scope=backend-test + cache-to: type=gha,scope=backend-test,mode=max + + - name: Run backend tests in Docker (shard ${{ matrix.shard }}/4) + run: | + docker run --rm \ + -e TESTING=1 \ + -e PYTHONUNBUFFERED=1 \ + bambuddy-backend-test:latest \ + pytest backend/tests/ \ + --tb=short \ + --timeout=60 --timeout-method=thread \ + -p no:cacheprovider \ + -n auto \ + --splits 4 --group ${{ matrix.shard }} + docker-test: name: Docker Build runs-on: ubuntu-latest @@ -298,19 +348,6 @@ jobs: - name: Verify static files exist run: docker run --rm bambuddy:test test -d /app/static - # NOTE: Tests 2 and 3 from test_docker.sh (backend / frontend unit - # tests inside the test image) used to run here. They've been removed - # from the CI pipeline because the host-side `backend-tests` and - # `frontend-tests` jobs already exercise the exact same test code - # against the exact same Python version + requirements.txt the test - # image installs — on 2-vCPU GHA runners a re-run inside Docker - # added 5-10 min of wall-clock for zero new coverage. The - # image-validation purpose of this job (does it build, do imports - # resolve, does the integration container come up and answer HTTP) - # lives in the surrounding steps. test_docker.sh keeps the unit-test - # runs because devs running it locally don't have a separate host- - # side pytest job to compare against. - # Test 4: Integration Tests - name: Build integration container run: docker compose -f docker-compose.test.yml build integration