From 0bb7e4c72355c0f6bbafe7c87580d01447f756f2 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Sat, 21 Feb 2026 21:26:44 +0000 Subject: [PATCH] Parallelize API tests and build, gate publish on test pass Same pattern as the frontend pipeline: build pushes to a staging tag (build-N) in parallel with tests. Tests split into unit and integration shards using a shared venv from the workspace. Publish step uses skopeo to copy the manifest to final tags (:N, :latest, :builder) only after all tests and the build succeed. Named the final Dockerfile stage 'production' so target skips the test stage. --- .drone.yml | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++---- Dockerfile | 4 ++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/.drone.yml b/.drone.yml index 77c3815..051b162 100644 --- a/.drone.yml +++ b/.drone.yml @@ -188,8 +188,44 @@ steps: exit 1 - git checkout "$DRONE_COMMIT" - - name: Build and test API image + - name: install-api-deps + image: python:3.13-slim + depends_on: + - clone + commands: + - apt-get update && apt-get install -y --no-install-recommends libglib2.0-0 + - python -m venv .venv + - .venv/bin/pip install --quiet --upgrade pip + - >- + .venv/bin/pip install --quiet + pytest pytest-asyncio pytest-cov httpx fakeredis aioresponses + fastapi uvicorn sqlmodel sqlalchemy alembic pyjwt cryptography + celery redis click aiohttp aiohttp-socks pillow numpy pytesseract + opentelemetry-api opentelemetry-sdk opentelemetry-exporter-prometheus + opentelemetry-instrumentation-fastapi opentelemetry-instrumentation-sqlalchemy + python-dotenv webauthn apprise tenacity prometheus-client + email-validator opencv-python-headless tqdm pandas cachetools watchdog + + - name: test-unit + image: python:3.13-slim + depends_on: + - install-api-deps + commands: + - apt-get update && apt-get install -y --no-install-recommends libglib2.0-0 + - .venv/bin/pytest tests/unit/ -v --tb=short + + - name: test-integration + image: python:3.13-slim + depends_on: + - install-api-deps + commands: + - apt-get update && apt-get install -y --no-install-recommends libglib2.0-0 + - .venv/bin/pytest tests/integration/ tests/regression/ tests/e2e/ tests/test_listing_geojson.py -v --tb=short + + - name: build-api-image image: plugins/docker + depends_on: + - clone environment: DOCKER_BUILDKIT: 1 settings: @@ -199,16 +235,32 @@ steps: repo: viktorbarzin/realestatecrawler dockerfile: Dockerfile context: . + target: production cache_from: - viktorbarzin/realestatecrawler:latest - viktorbarzin/realestatecrawler:builder tags: - - latest - - builder - - "${DRONE_BUILD_NUMBER}" + - "build-${DRONE_BUILD_NUMBER}" + + - name: publish-api-image + image: alpine + depends_on: + - test-unit + - test-integration + - build-api-image + environment: + DOCKERHUB_TOKEN: + from_secret: dockerhub-token + commands: + - apk add --no-cache skopeo + - 'skopeo copy --src-creds "viktorbarzin:$DOCKERHUB_TOKEN" --dest-creds "viktorbarzin:$DOCKERHUB_TOKEN" "docker://docker.io/viktorbarzin/realestatecrawler:build-${DRONE_BUILD_NUMBER}" "docker://docker.io/viktorbarzin/realestatecrawler:${DRONE_BUILD_NUMBER}"' + - 'skopeo copy --src-creds "viktorbarzin:$DOCKERHUB_TOKEN" --dest-creds "viktorbarzin:$DOCKERHUB_TOKEN" "docker://docker.io/viktorbarzin/realestatecrawler:build-${DRONE_BUILD_NUMBER}" "docker://docker.io/viktorbarzin/realestatecrawler:latest"' + - 'skopeo copy --src-creds "viktorbarzin:$DOCKERHUB_TOKEN" --dest-creds "viktorbarzin:$DOCKERHUB_TOKEN" "docker://docker.io/viktorbarzin/realestatecrawler:build-${DRONE_BUILD_NUMBER}" "docker://docker.io/viktorbarzin/realestatecrawler:builder"' - name: Update deployment image: alpine + depends_on: + - publish-api-image commands: - apk add curl - 'curl -s -X PATCH "https://kubernetes:6443/apis/apps/v1/namespaces/realestate-crawler/deployments/realestate-crawler-api" -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -H "Content-Type: application/json-patch+json" -k -d ''[{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"viktorbarzin/realestatecrawler:''"$DRONE_BUILD_NUMBER"''"}]'' | head' @@ -217,6 +269,8 @@ steps: - name: verify-deploy image: alpine + depends_on: + - Update deployment commands: - apk add --no-cache curl jq - | diff --git a/Dockerfile b/Dockerfile index 002ce9e..724748d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ COPY requirements.txt ./ # Install dependencies into a venv using uv (10-25x faster than pip) RUN --mount=type=cache,target=/root/.cache/uv \ python -m venv /app/.venv && \ - /app/.venv/bin/uv pip install -r requirements.txt + uv pip install --python /app/.venv/bin/python -r requirements.txt # Stage 2: Runtime system dependencies (runs in parallel with builder) FROM python:3.13-slim AS runtime-base @@ -53,7 +53,7 @@ COPY . . RUN pytest tests/ -x -q # Stage 4: Final image — combine venv from builder + runtime base -FROM runtime-base +FROM runtime-base AS production RUN adduser --system --no-create-home appuser