From 89fedc93e2e548d01588ed500cd9f694dff72442 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sun, 30 Aug 2026 14:48:30 +0200 Subject: [PATCH] ci: lance Postgres en conteneur d'arriere-plan, plus en `services:` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le runner Forgejo `act` ne garde pas un conteneur `services:` comme *la meme* instance d'une etape a l'autre : `prisma migrate deploy` posait le schema dans un Postgres, puis le `beforeAll` de Mocha en frappait un vide (« table … does not exist » juste apres « migrations successfully applied »). Trois occurrences en une journee, dont une sur `main` apres le merge de #18 — code identique a `ccec30b` qui, lui, etait vert. Le job `test` demarre desormais Postgres lui-meme via `docker run -d` (socket docker deja monte dans le conteneur de job), sur le reseau du job decouvert dynamiquement, joignable comme `postgres` — exactement la meme posture « vraie dependance lancee par le job » que l'etape uvicorn de `tech-step-intent-service` juste en dessous, que `services:` ne pouvait deja pas couvrir. Un seul conteneur, partage par toutes les etapes. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 73 ++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9be7cad..c3c48e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,15 @@ on: push: env: + # Hostname `postgres` = the container the `test` job starts itself (see + # that job's "Start Postgres" step) — a plain `docker run`, not a + # `services:` block, for the same reason the intent-service below can't be + # one: this repo's Forgejo `act` runner does not keep a `services:` + # container as the *same* instance across a job's steps, so `migrate + # deploy` would land the schema in one Postgres and `pnpm --filter api + # test`'s `beforeAll` would then hit an empty one ("table … does not + # exist" right after "migrations successfully applied"). One long-lived + # container in the job, shared by every step, removes that failure mode. DATABASE_URL: "postgresql://ci:ci@postgres:5432/batchcooking_ci?schema=public" # Test-only secret, never used outside CI — real deployments must set their own. JWT_SECRET: "ci-only-secret-not-used-anywhere-else-32chars+" @@ -24,9 +33,10 @@ env: # secret configured -> 401" path. ADMIN_JWT_SECRET: "ci-only-admin-secret-not-used-anywhere-else-32chars+" # Shared between the `test` job's own uvicorn step (below) and apps/api's - # IntentServiceClient — see the `test` job for why this can't be a - # `services:` container like postgres above (GitHub Actions can only pull - # a published image, not build services/tech-step-intent-service/Dockerfile). + # IntentServiceClient — that step runs `uvicorn` as a plain background + # process (not a `services:` block or even a container) because CI can + # only pull a published image, not build + # services/tech-step-intent-service/Dockerfile from this checkout. INTENT_SERVICE_BASE_URL: "http://localhost:8000" INTENT_SERVICE_SECRET: "ci-only-intent-secret-not-used-anywhere-else-32chars+" @@ -51,22 +61,34 @@ jobs: test: runs-on: ubuntu-latest - services: - postgres: - image: postgres:16-alpine - env: - POSTGRES_USER: ci - POSTGRES_PASSWORD: ci - POSTGRES_DB: batchcooking_ci - options: >- - --health-cmd pg_isready - --health-interval 5s - --health-timeout 5s - --health-retries 10 steps: - - name: Install curl and dependencies + - name: Install curl and the docker CLI run: | - apt-get update && apt-get install -y curl + apt-get update && apt-get install -y curl docker.io + + # Postgres as a plain background container instead of a `services:` + # block — see this workflow's top-level `env.DATABASE_URL` comment for + # why. Reachable as `postgres` from this job (the runner mounts the + # docker socket and runs jobs on a shared user-defined network, so a + # `--name postgres` sibling resolves by name); the network is + # discovered from the job container itself rather than hardcoded. + - name: Start Postgres in the background + run: | + net="$(docker inspect "$(hostname)" \ + --format '{{range $k, $_ := .NetworkSettings.Networks}}{{$k}} {{end}}' \ + | awk '{print $1}')" + echo "job network: ${net:?could not determine the job container network}" + docker rm -f postgres >/dev/null 2>&1 || true + docker run -d --name postgres --network "$net" \ + -e POSTGRES_USER=ci -e POSTGRES_PASSWORD=ci -e POSTGRES_DB=batchcooking_ci \ + postgres:16-alpine + for _ in $(seq 1 60); do + docker exec postgres pg_isready -U ci -d batchcooking_ci && exit 0 + sleep 2 + done + echo "Postgres did not become ready in time" >&2 + docker logs postgres || true + exit 1 - uses: https://github.com/actions/checkout@v4 @@ -82,15 +104,14 @@ jobs: python-version: "3.12" enable-cache: true - # `services:` (like the `postgres` container above) can only pull an - # already-published image — it can't build - # services/tech-step-intent-service/Dockerfile from this checkout. - # Running `uvicorn` as a plain background step instead: it keeps - # running for the rest of this job (GitHub Actions steps in one job - # share the same runner process tree), and `pnpm --filter api test` - # below needs a real instance to talk to per this repo's "never mock - # an internal service" test convention — same reasoning as the real - # `postgres` container just above, not a mock HTTP server. + # A `services:` block can only pull an already-published image — it + # can't build services/tech-step-intent-service/Dockerfile from this + # checkout. Running `uvicorn` as a plain background step instead: it + # keeps running for the rest of this job (steps in one job share the + # same process tree), and `pnpm --filter api test` below needs a real + # instance to talk to per this repo's "never mock an internal service" + # test convention — same "real dependency, started by the job itself" + # posture as the Postgres step above, not a mock HTTP server. - name: Install services/tech-step-intent-service working-directory: services/tech-step-intent-service run: uv sync --frozen