All checks were successful
CI / lint (pull_request) Successful in 50s
CI / build (pull_request) Successful in 42s
CI / unit (pull_request) Successful in 47s
CI / mutation (pull_request) Successful in 1m31s
CI / integration (pull_request) Successful in 3m43s
CI / compose-smoke (pull_request) Successful in 4m1s
The hosted runner can't reach the stack's published ports (sibling containers), so run the seed and the test as containers joined to the OpenZaak network, reaching it by container IP — a single-label host like 'openzaak' isn't URL-valid for OpenZaak's own URLValidator, but an IPv4 literal is. Code is delivered via image build / docker cp (bind mounts don't reach the daemon either). - infra/run-integration.sh: up -> wait healthy (docker inspect) -> seed published zaaktype (python container on the net) -> build + run the test image on the net -> always tear down. Plain docker primitives only (portable docker/podman). - services/acl/Dockerfile.integration: builds + runs Acl.IntegrationTests; dotnet lives in the image, so the CI job needs only Docker (no setup-dotnet). - make integration now delegates to the script; re-added the Gitea Actions job. Supersedes the local-only gap documented earlier; #55 is no longer needed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
211 lines
9.6 KiB
Makefile
211 lines
9.6 KiB
Makefile
# Developer + CI entrypoints.
|
|
#
|
|
# These targets are the single source of truth for the checks. The Gitea
|
|
# Actions workflow (.gitea/workflows/ci.yaml) invokes the SAME targets, so
|
|
# `make ci` locally runs exactly what the pipeline runs — no drift. Until a
|
|
# self-hosted runner is registered, `make ci` is the gate (see docs/runbooks/ci.md).
|
|
|
|
SLN := register-referentie.slnx
|
|
COMPOSE := infra/docker-compose.yml
|
|
# Long-running services with a healthcheck — the smoke polls these for readiness
|
|
# (infra/wait-healthy.sh). One-shot init jobs (oz-init, nrc-init, flowable-init)
|
|
# are not polled; they only need to have run. See docs/runbooks/gitea-actions-gotchas.md.
|
|
WAIT_SVCS := openzaak nrc-web acl bff
|
|
# Config files (OpenZaak data.yaml, Keycloak realms, Flowable BPMN) are streamed
|
|
# into external named volumes via `docker cp` (infra/seed-config.sh) instead of
|
|
# bind-mounted, because bind mounts don't reach sibling containers on the
|
|
# containerized CI runner. SEED populates them; run it before every `up`. The
|
|
# volumes are `external`, so compose won't remove them — CFG_VOLS lists them for
|
|
# explicit teardown. See docs/runbooks/gitea-actions-gotchas.md.
|
|
SEED := bash infra/seed-config.sh
|
|
CFG_VOLS := rr-oz-config rr-kc-realms rr-fl-bpmn
|
|
# Local-only stack: same services but config is bind-mounted (no seed step), so a
|
|
# plain `docker compose -f infra/docker-compose.local.yml up` works on any local
|
|
# engine. This is the no-make / Windows-friendly path. See that file's header.
|
|
LOCAL_COMPOSE := infra/docker-compose.local.yml
|
|
OZ_COMPOSE := infra/openzaak/docker-compose.yml
|
|
OZ_BASE := http://localhost:8000
|
|
NRC_COMPOSE := infra/opennotificaties/docker-compose.yml
|
|
NRC_BASE := http://localhost:8001
|
|
KC_COMPOSE := infra/keycloak/docker-compose.yml
|
|
KC_BASE := http://localhost:8180
|
|
FL_COMPOSE := infra/flowable/docker-compose.yml
|
|
FL_BASE := http://localhost:8090/flowable-rest/service
|
|
STACK_FILES := -f $(OZ_COMPOSE) -f $(NRC_COMPOSE)
|
|
|
|
# On a rootless Podman dev box, point Docker CLI/Compose at the Podman socket —
|
|
# but only if that socket exists and DOCKER_HOST isn't already set, so real
|
|
# Docker hosts and CI runners are left untouched.
|
|
PODMAN_SOCK := /run/user/$(shell id -u)/podman/podman.sock
|
|
ifeq ($(wildcard $(PODMAN_SOCK)),$(PODMAN_SOCK))
|
|
ifeq ($(origin DOCKER_HOST),undefined)
|
|
export DOCKER_HOST := unix://$(PODMAN_SOCK)
|
|
endif
|
|
endif
|
|
|
|
.PHONY: ci lint build unit mutation integration smoke up down local local-down changelog openzaak-up openzaak-smoke openzaak-seed openzaak-down stack-up stack-smoke stack-down keycloak-up keycloak-smoke keycloak-down flowable-up flowable-smoke flowable-down help
|
|
|
|
## ci: run the full pipeline — lint, build, unit, mutation, smoke (mirrors Gitea Actions)
|
|
ci: lint build unit mutation smoke
|
|
|
|
## lint: verify formatting (no changes)
|
|
lint:
|
|
dotnet format $(SLN) --verify-no-changes
|
|
|
|
## build: release build
|
|
build:
|
|
dotnet build $(SLN) -c Release
|
|
|
|
## unit: run unit tests (excludes the container-backed Integration lane)
|
|
unit:
|
|
dotnet test $(SLN) -c Release --filter "Category!=Integration"
|
|
|
|
## mutation: run the Stryker.NET ratchet on the ACL (fails below the recorded baseline)
|
|
# Stryker is pinned as a local dotnet tool (.config/dotnet-tools.json); `tool restore`
|
|
# makes `make mutation` work from a fresh clone. Config + break threshold (the ratchet,
|
|
# CLAUDE.md §5) live in services/acl/stryker-config.json. The ACL is the first service
|
|
# with branching logic, so it sets the repo-wide baseline; later slices ratchet it up.
|
|
mutation:
|
|
dotnet tool restore
|
|
cd services/acl && dotnet stryker
|
|
|
|
## smoke: seed config, bring the whole stack up, wait for health-checked services, tear down
|
|
# SEED populates the external config volumes first (upstream images used verbatim;
|
|
# only our acl/bff are built). `up -d --build` starts EVERYTHING. Readiness is
|
|
# checked by infra/wait-healthy.sh polling the durable, health-checked services
|
|
# ($(WAIT_SVCS)) via `docker inspect` — portable across docker compose and
|
|
# podman-compose, and needing no `--wait` flag or host port access. The one-shots
|
|
# (oz-init, flowable-init) aren't polled; they just need to have run.
|
|
smoke:
|
|
$(SEED) oz kc fl
|
|
docker compose -f $(COMPOSE) up -d --build
|
|
bash -c 'WAIT_TIMEOUT=420 bash infra/wait-healthy.sh $(WAIT_SVCS); rc=$$?; docker compose -f $(COMPOSE) down --volumes; docker volume rm -f $(CFG_VOLS) >/dev/null 2>&1; exit $$rc'
|
|
|
|
## up: seed config volumes and start the full stack (use instead of bare
|
|
## `docker compose up`, which can't self-seed the external config volumes)
|
|
up:
|
|
$(SEED) oz kc fl
|
|
docker compose -f $(COMPOSE) up -d --build
|
|
|
|
## down: stop and remove the local stack (incl. the external config volumes)
|
|
down:
|
|
docker compose -f $(COMPOSE) down --volumes
|
|
-docker volume rm -f $(CFG_VOLS)
|
|
|
|
## local: bring up the bind-mount stack (no seed step) and wait for health
|
|
## (Windows / no-make users: run `docker compose -f infra/docker-compose.local.yml up -d --build` directly)
|
|
local:
|
|
docker compose -f $(LOCAL_COMPOSE) up -d --build
|
|
WAIT_TIMEOUT=420 bash infra/wait-healthy.sh $(WAIT_SVCS)
|
|
|
|
## local-down: stop and remove the bind-mount stack
|
|
local-down:
|
|
docker compose -f $(LOCAL_COMPOSE) down --volumes
|
|
|
|
## changelog: regenerate CHANGELOG.md from Conventional Commits (git-cliff)
|
|
changelog:
|
|
git-cliff --output CHANGELOG.md
|
|
|
|
## integration: ACL integration tests against a real OpenZaak (S-04a, #46). The
|
|
## seed and the test run inside the compose network (reaching http://openzaak:8000),
|
|
## so this works on the hosted CI runner where a runner process can't reach the
|
|
## stack's published ports. Brings the stack up, seeds a PUBLISHED BIG zaaktype,
|
|
## runs the Integration-category tests, then always tears down. Kept out of
|
|
## `unit`/`mutation` because it needs the live stack. See infra/run-integration.sh + ADR-0006.
|
|
integration:
|
|
bash infra/run-integration.sh
|
|
|
|
## openzaak-up: start the OpenZaak stack (migrations run on first start)
|
|
openzaak-up:
|
|
$(SEED) oz
|
|
docker compose -f $(OZ_COMPOSE) up -d
|
|
|
|
## openzaak-smoke: start OpenZaak, then assert it is up with auth enforced
|
|
openzaak-smoke: openzaak-up
|
|
@bash -c 'set -e; \
|
|
echo "waiting for OpenZaak to respond..."; \
|
|
for i in $$(seq 1 60); do \
|
|
code=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/zaken/api/v1/zaken || true); \
|
|
[ -n "$$code" ] && [ "$$code" != "000" ] && break; sleep 3; \
|
|
done; \
|
|
echo "GET /zaken/api/v1/zaken (unauth) -> $$code (expect 403, auth enforced)"; test "$$code" = "403"; \
|
|
admin=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/admin/); \
|
|
echo "GET /admin/ -> $$admin (expect 302)"; test "$$admin" = "302"; \
|
|
root=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/zaken/api/v1/); \
|
|
echo "GET /zaken/api/v1/ -> $$root (expect 200)"; test "$$root" = "200"; \
|
|
echo "OpenZaak smoke OK"'
|
|
|
|
## openzaak-seed: bring OpenZaak up and seed the BIG catalogus (idempotent)
|
|
openzaak-seed: openzaak-up
|
|
@bash -c 'for i in $$(seq 1 50); do \
|
|
c=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/catalogi/api/v1/ || true); \
|
|
[ "$$c" = "200" ] && break; sleep 3; done; echo "OpenZaak ready ($$c)"'
|
|
python3 infra/openzaak/seed_catalogus.py
|
|
|
|
## openzaak-down: stop and remove the OpenZaak stack (wipes data)
|
|
openzaak-down:
|
|
docker compose -f $(OZ_COMPOSE) down --volumes
|
|
-docker volume rm -f rr-oz-config
|
|
|
|
## stack-up: start OpenZaak + Open Notificaties together (shared network)
|
|
stack-up:
|
|
$(SEED) oz
|
|
docker compose $(STACK_FILES) up -d
|
|
|
|
## stack-smoke: start both, assert OpenZaak (403/302/200) and NRC (302) are reachable
|
|
stack-smoke: stack-up
|
|
@bash -c 'set -e; \
|
|
echo "waiting for OpenZaak + Open Notificaties..."; \
|
|
for i in $$(seq 1 60); do \
|
|
oz=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/admin/ || true); \
|
|
nrc=$$(curl -s -o /dev/null -w "%{http_code}" $(NRC_BASE)/admin/ || true); \
|
|
[ "$$oz" = "302" ] && [ "$$nrc" = "302" ] && break; sleep 3; done; \
|
|
z=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/zaken/api/v1/zaken); \
|
|
echo "OpenZaak /zaken (unauth) -> $$z (expect 403)"; test "$$z" = "403"; \
|
|
echo "OpenZaak /admin/ -> $$oz (expect 302)"; test "$$oz" = "302"; \
|
|
echo "Open Notificaties /admin/-> $$nrc (expect 302)"; test "$$nrc" = "302"; \
|
|
echo "stack smoke OK"'
|
|
|
|
## stack-down: stop and remove both stacks (wipes data)
|
|
stack-down:
|
|
docker compose $(STACK_FILES) down --volumes
|
|
-docker volume rm -f rr-oz-config
|
|
|
|
## keycloak-up: start Keycloak with the four imported realms
|
|
keycloak-up:
|
|
$(SEED) kc
|
|
docker compose -f $(KC_COMPOSE) up -d
|
|
|
|
## keycloak-smoke: start Keycloak, then verify each realm logs in + returns its claim
|
|
keycloak-smoke: keycloak-up
|
|
@bash -c 'for i in $$(seq 1 60); do \
|
|
c=$$(curl -s -o /dev/null -w "%{http_code}" $(KC_BASE)/realms/digid/.well-known/openid-configuration || true); \
|
|
[ "$$c" = "200" ] && break; sleep 3; done; echo "Keycloak ready ($$c)"'
|
|
python3 infra/keycloak/check_realms.py
|
|
|
|
## keycloak-down: stop and remove Keycloak
|
|
keycloak-down:
|
|
docker compose -f $(KC_COMPOSE) down --volumes
|
|
-docker volume rm -f rr-kc-realms
|
|
|
|
## flowable-up: start Flowable (deploys registratie.bpmn on boot)
|
|
flowable-up:
|
|
$(SEED) fl
|
|
docker compose -f $(FL_COMPOSE) up -d
|
|
|
|
## flowable-smoke: start Flowable, then verify a started instance waits on the external task
|
|
flowable-smoke: flowable-up
|
|
@bash -c 'for i in $$(seq 1 80); do \
|
|
c=$$(curl -s -o /dev/null -w "%{http_code}" -u rest-admin:test $(FL_BASE)/repository/process-definitions?key=registratie || true); \
|
|
[ "$$c" = "200" ] && break; sleep 3; done; echo "Flowable ready ($$c)"'
|
|
python3 infra/flowable/verify.py
|
|
|
|
## flowable-down: stop and remove Flowable
|
|
flowable-down:
|
|
docker compose -f $(FL_COMPOSE) down --volumes
|
|
-docker volume rm -f rr-fl-bpmn
|
|
|
|
## help: list available targets
|
|
help:
|
|
@grep -E '^## ' $(MAKEFILE_LIST) | sed 's/^## //'
|