ci(infra): Gitea Actions CI pipeline + full-stack compose smoke (closes #30) #50
17
Makefile
17
Makefile
@@ -7,7 +7,11 @@
|
|||||||
|
|
||||||
SLN := register-referentie.slnx
|
SLN := register-referentie.slnx
|
||||||
COMPOSE := infra/docker-compose.yml
|
COMPOSE := infra/docker-compose.yml
|
||||||
HEALTH_URL := http://localhost:8080/health
|
# Long-running services with a healthcheck — the smoke waits on these. One-shot
|
||||||
|
# init jobs (oz-init, nrc-init, flowable-init) are NOT listed: `--wait` fails when
|
||||||
|
# a one-shot with no `service_completed_successfully` dependant exits (flowable-init),
|
||||||
|
# so we wait on the durable services instead. See docs/runbooks/gitea-actions-gotchas.md.
|
||||||
|
WAIT_SVCS := openzaak nrc-web acl bff
|
||||||
OZ_COMPOSE := infra/openzaak/docker-compose.yml
|
OZ_COMPOSE := infra/openzaak/docker-compose.yml
|
||||||
OZ_BASE := http://localhost:8000
|
OZ_BASE := http://localhost:8000
|
||||||
NRC_COMPOSE := infra/opennotificaties/docker-compose.yml
|
NRC_COMPOSE := infra/opennotificaties/docker-compose.yml
|
||||||
@@ -45,10 +49,15 @@ build:
|
|||||||
unit:
|
unit:
|
||||||
dotnet test $(SLN) -c Release
|
dotnet test $(SLN) -c Release
|
||||||
|
|
||||||
## smoke: compose up (wait for healthy), curl /health, then tear down
|
## smoke: bring the whole stack up, wait for the health-checked services, tear down
|
||||||
|
# Step 1 starts EVERYTHING (incl. one-shot init jobs that deploy and exit 0).
|
||||||
|
# Step 2 waits only for the durable, health-checked services ($(WAIT_SVCS)) — see
|
||||||
|
# WAIT_SVCS above for why the one-shots are excluded. The healthchecks run inside
|
||||||
|
# the containers, so this needs no host port access (the CI runner can't reach
|
||||||
|
# published ports anyway).
|
||||||
smoke:
|
smoke:
|
||||||
docker compose -f $(COMPOSE) up -d --build --wait --wait-timeout 420
|
docker compose -f $(COMPOSE) up -d --build
|
||||||
bash -c 'curl -fsS $(HEALTH_URL); rc=$$?; docker compose -f $(COMPOSE) down --volumes; exit $$rc'
|
bash -c 'docker compose -f $(COMPOSE) up -d --wait --wait-timeout 420 $(WAIT_SVCS); rc=$$?; docker compose -f $(COMPOSE) down --volumes; exit $$rc'
|
||||||
|
|
||||||
## down: stop and remove the local stack
|
## down: stop and remove the local stack
|
||||||
down:
|
down:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ and CI cannot drift:
|
|||||||
| `lint` | `make lint` → `dotnet format … --verify-no-changes` | .NET 10 SDK |
|
| `lint` | `make lint` → `dotnet format … --verify-no-changes` | .NET 10 SDK |
|
||||||
| `build` | `make build` → `dotnet build … -c Release` | .NET 10 SDK |
|
| `build` | `make build` → `dotnet build … -c Release` | .NET 10 SDK |
|
||||||
| `unit` | `make unit` → `dotnet test … -c Release` | .NET 10 SDK |
|
| `unit` | `make unit` → `dotnet test … -c Release` | .NET 10 SDK |
|
||||||
| `compose-smoke` | `make smoke` → compose up `--wait` → `curl /health` → `down` | container engine + compose v2 |
|
| `compose-smoke` | `make smoke` → `up -d` (full stack) → `up --wait` durable services → `down` | container engine + compose v2 |
|
||||||
|
|
||||||
All `uses:` references are absolute, tag-pinned URLs (`https://github.com/actions/checkout@v4`,
|
All `uses:` references are absolute, tag-pinned URLs (`https://github.com/actions/checkout@v4`,
|
||||||
`https://github.com/actions/setup-dotnet@v4`) per CLAUDE.md §8.7 and §15 — Gitea
|
`https://github.com/actions/setup-dotnet@v4`) per CLAUDE.md §8.7 and §15 — Gitea
|
||||||
|
|||||||
@@ -66,6 +66,30 @@ so the SELinux `:z`/`:Z` relabel flag is no longer needed anywhere in `infra/`,
|
|||||||
and rootless Podman no longer needs the files to be world-readable. One mechanism
|
and rootless Podman no longer needs the files to be world-readable. One mechanism
|
||||||
(build) works on both Podman locally and Docker-in-Docker in CI.
|
(build) works on both Podman locally and Docker-in-Docker in CI.
|
||||||
|
|
||||||
|
## `--wait` fails on one-shot containers with no dependant
|
||||||
|
|
||||||
|
`docker compose up --wait` treats a service that **exits** as a failure of the
|
||||||
|
"stay up" condition — **unless** another service depends on it with
|
||||||
|
`condition: service_completed_successfully`. Our init jobs `oz-init` and
|
||||||
|
`nrc-init` are fine (`openzaak`/`nrc-web` depend on their completion), but
|
||||||
|
`flowable-init` deploys the BPMN and exits 0 with **no dependant**, so a
|
||||||
|
whole-project `--wait` fails the moment it exits — even with everything else
|
||||||
|
healthy. The symptom is a `compose-smoke` failure whose last compose line is:
|
||||||
|
|
||||||
|
```
|
||||||
|
container infra-flowable-init-1 exited (0)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix.** The smoke does **not** `--wait` on the whole project. It starts
|
||||||
|
everything with `up -d`, then `up -d --wait <services>` only for the durable,
|
||||||
|
health-checked services (`openzaak nrc-web acl bff` — see `WAIT_SVCS` in the
|
||||||
|
`Makefile`). One-shots still run (and deploy), they just don't gate `--wait`.
|
||||||
|
|
||||||
|
This also removed the old external `curl http://localhost:8080/health` check:
|
||||||
|
the CI job runs in a container and **can't reach published host ports** at
|
||||||
|
`localhost`, and the per-service healthchecks (which run *inside* the
|
||||||
|
containers) already prove readiness, so `--wait` succeeding *is* the smoke.
|
||||||
|
|
||||||
## `--wait` needs an explicit timeout
|
## `--wait` needs an explicit timeout
|
||||||
|
|
||||||
`docker compose up --wait` defaults to a 60-second timeout in some Compose v2
|
`docker compose up --wait` defaults to a 60-second timeout in some Compose v2
|
||||||
|
|||||||
Reference in New Issue
Block a user