* chore(MP-21): snapshot pre-refactor state (Epic 1)
* chore(MP-22): scaffold new repo structure, relocate Docker Compose, move frontend/backend modules, update Makefile; add docs mapping and env template
* MP-22 Epic 2: Erfolgreich umgesetzt und verifiziert
* MP-23 Epic 3: Gradle/Build Governance zentralisieren
* MP-23 Epic 3: Gradle/Build Governance zentralisieren
* chore(devops)!: Docker-SSoT (.env) konsolidiert, Compose-Mounts ergänzt, Makefile entfernt
- ENV Single Source of Truth
- docker/.env.example neu (inkl. REDIS_PASSWORD, Ports, Build-Overrides)
- config/.env(.example) als DEPRECATED markiert (Verweis auf docker/.env[.example])
- Docker Compose vereinheitlicht (docker/docker-compose.yaml)
- Postgres: zentralen postgresql.conf mounten (../config/postgres/postgresql.conf)
und Start mit -c config_file=/etc/postgresql/postgresql.conf
- Redis: zentralen redis.conf mounten (../config/redis/redis.conf)
und Start via "redis-server … ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}"
- Web-Nginx: ../config/nginx/nginx.prod.conf → /etc/nginx/nginx.conf (ro)
- Monitoring: Prometheus/Grafana nutzen ../config/monitoring/* als SSoT
- Frontend/DI/Network (MP-23 Grundlage)
- :frontend:core:network Modul mit Koin `apiClient` (Ktor + JSON/Retry/Timeout/Logging)
- Plattform-Basis-URL-Auflösung (JVM: ENV API_BASE_URL; JS: globalThis.API_BASE_URL / Same-Origin)
- Web index.html setzt API_BASE_URL (Query `?apiBaseUrl=…` > Same-Origin > Fallback)
- Build/Gradle & Module-Refs
- settings.gradle.kts: neue Frontend-/Backend-Pfade bereits inkludiert
- Features/Shell: Abhängigkeiten auf :frontend:shared / :frontend:core:* angepasst
- Ping-API-Refs auf :backend:services:ping:ping-api vereinheitlicht
- Dockerfiles angepasst
- backend/infrastructure/gateway/Dockerfile → Tasks/Pfade auf :backend:gateway
- backend/services/ping/Dockerfile → Tasks/Pfade auf :backend:services:ping:ping-service
- Static Analysis / Guards
- config/detekt/detekt.yml hinzugefügt
- Leichter Arch-Guard (Frontend) gegen manuelle Authorization-Header vorbereitet
- Doku
- docs/ARCHITECTURE.md (Struktur, Mapping, Next Steps) ergänzt
- docs/adr/README.md angelegt
BREAKING CHANGES:
- Makefile komplett entfernt (bitte direkt `docker compose` verwenden)
- ENV-Quelle ist jetzt docker/.env (statt config/.env oder Root)
- Compose-Datei unter docker/docker-compose.yaml (nicht mehr compose.yaml im Repo-Root)
Verifikation (lokal):
- ENV anlegen: `cp docker/.env.example docker/.env` (Werte anpassen)
- Compose prüfen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml config`
- Infrastruktur: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle up -d postgres redis keycloak web-app`
- Services bauen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle build api-gateway ping-service --no-cache --progress=plain`
Refs: MP-22 (Epic 2), MP-23 (Epic 3)
* chore(devops)!: Docker-SSoT (.env) konsolidiert, Compose-Mounts ergänzt, Makefile entfernt
- ENV Single Source of Truth
- docker/.env.example neu (inkl. REDIS_PASSWORD, Ports, Build-Overrides)
- config/.env(.example) als DEPRECATED markiert (Verweis auf docker/.env[.example])
- Docker Compose vereinheitlicht (docker/docker-compose.yaml)
- Postgres: zentralen postgresql.conf mounten (../config/postgres/postgresql.conf)
und Start mit -c config_file=/etc/postgresql/postgresql.conf
- Redis: zentralen redis.conf mounten (../config/redis/redis.conf)
und Start via "redis-server … ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}"
- Web-Nginx: ../config/nginx/nginx.prod.conf → /etc/nginx/nginx.conf (ro)
- Monitoring: Prometheus/Grafana nutzen ../config/monitoring/* als SSoT
- Frontend/DI/Network (MP-23 Grundlage)
- :frontend:core:network Modul mit Koin `apiClient` (Ktor + JSON/Retry/Timeout/Logging)
- Plattform-Basis-URL-Auflösung (JVM: ENV API_BASE_URL; JS: globalThis.API_BASE_URL / Same-Origin)
- Web index.html setzt API_BASE_URL (Query `?apiBaseUrl=…` > Same-Origin > Fallback)
- Build/Gradle & Module-Refs
- settings.gradle.kts: neue Frontend-/Backend-Pfade bereits inkludiert
- Features/Shell: Abhängigkeiten auf :frontend:shared / :frontend:core:* angepasst
- Ping-API-Refs auf :backend:services:ping:ping-api vereinheitlicht
- Dockerfiles angepasst
- backend/infrastructure/gateway/Dockerfile → Tasks/Pfade auf :backend:gateway
- backend/services/ping/Dockerfile → Tasks/Pfade auf :backend:services:ping:ping-service
- Static Analysis / Guards
- config/detekt/detekt.yml hinzugefügt
- Leichter Arch-Guard (Frontend) gegen manuelle Authorization-Header vorbereitet
- Doku
- docs/ARCHITECTURE.md (Struktur, Mapping, Next Steps) ergänzt
- docs/adr/README.md angelegt
BREAKING CHANGES:
- Makefile komplett entfernt (bitte direkt `docker compose` verwenden)
- ENV-Quelle ist jetzt docker/.env (statt config/.env oder Root)
- Compose-Datei unter docker/docker-compose.yaml (nicht mehr compose.yaml im Repo-Root)
Verifikation (lokal):
- ENV anlegen: `cp docker/.env.example docker/.env` (Werte anpassen)
- Compose prüfen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml config`
- Infrastruktur: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle up -d postgres redis keycloak web-app`
- Services bauen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle build api-gateway ping-service --no-cache --progress=plain`
Refs: MP-22 (Epic 2), MP-23 (Epic 3)
* chore(devops)!: Docker-SSoT (.env) konsolidiert, Compose-Mounts ergänzt, Makefile entfernt
- ENV Single Source of Truth
- docker/.env.example neu (inkl. REDIS_PASSWORD, Ports, Build-Overrides)
- config/.env(.example) als DEPRECATED markiert (Verweis auf docker/.env[.example])
- Docker Compose vereinheitlicht (docker/docker-compose.yaml)
- Postgres: zentralen postgresql.conf mounten (../config/postgres/postgresql.conf)
und Start mit -c config_file=/etc/postgresql/postgresql.conf
- Redis: zentralen redis.conf mounten (../config/redis/redis.conf)
und Start via "redis-server … ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}"
- Web-Nginx: ../config/nginx/nginx.prod.conf → /etc/nginx/nginx.conf (ro)
- Monitoring: Prometheus/Grafana nutzen ../config/monitoring/* als SSoT
- Frontend/DI/Network (MP-23 Grundlage)
- :frontend:core:network Modul mit Koin `apiClient` (Ktor + JSON/Retry/Timeout/Logging)
- Plattform-Basis-URL-Auflösung (JVM: ENV API_BASE_URL; JS: globalThis.API_BASE_URL / Same-Origin)
- Web index.html setzt API_BASE_URL (Query `?apiBaseUrl=…` > Same-Origin > Fallback)
- Build/Gradle & Module-Refs
- settings.gradle.kts: neue Frontend-/Backend-Pfade bereits inkludiert
- Features/Shell: Abhängigkeiten auf :frontend:shared / :frontend:core:* angepasst
- Ping-API-Refs auf :backend:services:ping:ping-api vereinheitlicht
- Dockerfiles angepasst
- backend/infrastructure/gateway/Dockerfile → Tasks/Pfade auf :backend:gateway
- backend/services/ping/Dockerfile → Tasks/Pfade auf :backend:services:ping:ping-service
- Static Analysis / Guards
- config/detekt/detekt.yml hinzugefügt
- Leichter Arch-Guard (Frontend) gegen manuelle Authorization-Header vorbereitet
- Doku
- docs/ARCHITECTURE.md (Struktur, Mapping, Next Steps) ergänzt
- docs/adr/README.md angelegt
BREAKING CHANGES:
- Makefile komplett entfernt (bitte direkt `docker compose` verwenden)
- ENV-Quelle ist jetzt docker/.env (statt config/.env oder Root)
- Compose-Datei unter docker/docker-compose.yaml (nicht mehr compose.yaml im Repo-Root)
Verifikation (lokal):
- ENV anlegen: `cp docker/.env.example docker/.env` (Werte anpassen)
- Compose prüfen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml config`
- Infrastruktur: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle up -d postgres redis keycloak web-app`
- Services bauen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle build api-gateway ping-service --no-cache --progress=plain`
Refs: MP-22 (Epic 2), MP-23 (Epic 3)
* chore(ci): Workflows an Docker-SSoT & neue Struktur angepasst, minimaler SSoT-Guard
- ssot-guard.yml: Option B (minimal) → `docker compose -f docker/docker-compose.yaml config` als Lint
- integration-tests.yml: `./gradlew staticAnalysis` vor Integrationstests
- docs-kdoc-sync.yml: Dokka-Task Fallback (dokkaGfmAll || dokkaGfm), YouTrack-Sync nur wenn Script vorhanden
- deploy-proxmox.yml: Compose-Pfade auf docker/docker-compose.yaml + `--env-file docker/.env`; Build/Test Schritte vereinheitlicht
- ci-main.yml: SSoT-Skripte per `if: hashFiles(...)` guarded, Compose-Lint Fallback; OpenAPI‑Pfad → backend/gateway; ADR‑Pfade → docs/adr/**; `staticAnalysis` in Build integriert
- youtrack-sync.yml: unverändert (funktional)
Refs: MP-22, MP-23
* chore(ci): Workflows an Docker-SSoT & neue Struktur angepasst, minimaler SSoT-Guard
- ssot-guard.yml: Option B (minimal) → `docker compose -f docker/docker-compose.yaml config` als Lint
- integration-tests.yml: `./gradlew staticAnalysis` vor Integrationstests
- docs-kdoc-sync.yml: Dokka-Task Fallback (dokkaGfmAll || dokkaGfm), YouTrack-Sync nur wenn Script vorhanden
- deploy-proxmox.yml: Compose-Pfade auf docker/docker-compose.yaml + `--env-file docker/.env`; Build/Test Schritte vereinheitlicht
- ci-main.yml: SSoT-Skripte per `if: hashFiles(...)` guarded, Compose-Lint Fallback; OpenAPI‑Pfad → backend/gateway; ADR‑Pfade → docs/adr/**; `staticAnalysis` in Build integriert
- youtrack-sync.yml: unverändert (funktional)
Refs: MP-22, MP-23
* fix(ci): create .env from example before validating compose config
* fix(ci): update ssot-guard filename (.yaml) and sync workflow state
* fixing
* fix(webpack): correct sql.js fallback configuration for webpack 5
230 lines
8.1 KiB
YAML
230 lines
8.1 KiB
YAML
name: Integration Tests
|
||
|
||
permissions:
|
||
contents: read
|
||
|
||
concurrency:
|
||
group: integration-tests-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
on:
|
||
push:
|
||
branches: [ main, develop ]
|
||
pull_request:
|
||
branches: [ main, develop ]
|
||
|
||
jobs:
|
||
integration-tests:
|
||
runs-on: ubuntu-latest
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
keycloak_db: [postgres, dev-file]
|
||
env:
|
||
KEYCLOAK_VERSION: "26.4.2"
|
||
|
||
services:
|
||
postgres:
|
||
image: postgres:16-alpine
|
||
env:
|
||
POSTGRES_USER: meldestelle
|
||
POSTGRES_PASSWORD: meldestelle
|
||
POSTGRES_DB: meldestelle
|
||
ports:
|
||
- 5432:5432
|
||
options: >-
|
||
--health-cmd "pg_isready -U meldestelle -d $${POSTGRES_DB}"
|
||
--health-interval 10s
|
||
--health-timeout 5s
|
||
--health-retries 12
|
||
--health-start-period 20s
|
||
|
||
redis:
|
||
image: redis:7-alpine
|
||
ports:
|
||
- 6379:6379
|
||
options: >-
|
||
--health-cmd "redis-cli ping"
|
||
--health-interval 10s
|
||
--health-timeout 5s
|
||
--health-retries 5
|
||
|
||
|
||
zookeeper:
|
||
image: confluentinc/cp-zookeeper:7.5.0
|
||
env:
|
||
ZOOKEEPER_CLIENT_PORT: 2181
|
||
ports:
|
||
- 2181:2181
|
||
options: >-
|
||
--health-cmd "nc -z localhost 2181 || exit 1"
|
||
--health-interval 10s
|
||
--health-timeout 5s
|
||
--health-retries 3
|
||
--health-start-period 10s
|
||
|
||
kafka:
|
||
image: confluentinc/cp-kafka:7.5.0
|
||
env:
|
||
KAFKA_BROKER_ID: 1
|
||
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
|
||
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
|
||
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
|
||
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
|
||
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
|
||
ports:
|
||
- 9092:9092
|
||
options: >-
|
||
--health-cmd "kafka-topics --bootstrap-server localhost:9092 --list || exit 1"
|
||
--health-interval 10s
|
||
--health-timeout 5s
|
||
--health-retries 3
|
||
--health-start-period 30s
|
||
|
||
zipkin:
|
||
image: openzipkin/zipkin:2
|
||
ports:
|
||
- 9411:9411
|
||
options: >-
|
||
--health-cmd "wget -q -O - http://localhost:9411/health || exit 1"
|
||
--health-interval 10s
|
||
--health-timeout 5s
|
||
--health-retries 3
|
||
--health-start-period 10s
|
||
|
||
steps:
|
||
- uses: actions/checkout@v6
|
||
|
||
- name: Set up JDK 21
|
||
uses: actions/setup-java@v5
|
||
with:
|
||
java-version: 21
|
||
distribution: 'temurin'
|
||
cache: 'gradle'
|
||
|
||
- name: Setup Gradle (modern)
|
||
uses: gradle/actions/setup-gradle@v5
|
||
|
||
- name: Wait for Postgres to be ready (pg_isready in service network)
|
||
if: ${{ matrix.keycloak_db == 'postgres' }}
|
||
run: |
|
||
echo "Waiting for Postgres..."
|
||
for i in {1..40}; do
|
||
if docker run --rm --network ${{ job.services.postgres.network }} \
|
||
postgres:16-alpine pg_isready -h postgres -p 5432 -U meldestelle -d meldestelle; then
|
||
echo "Postgres is ready"; break; fi; echo -n "."; sleep 3; done
|
||
|
||
- name: Start Keycloak with Postgres (dev) and wait for readiness
|
||
if: ${{ matrix.keycloak_db == 'postgres' }}
|
||
run: |
|
||
set -euo pipefail
|
||
echo "Starting Keycloak (DB=postgres)..."
|
||
docker run -d --name keycloak \
|
||
--network ${{ job.services.postgres.network }} \
|
||
-p 8180:8080 \
|
||
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
|
||
-e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
|
||
-e KC_DB=postgres \
|
||
-e KC_DB_URL=jdbc:postgresql://postgres:5432/meldestelle \
|
||
-e KC_DB_USERNAME=meldestelle \
|
||
-e KC_DB_PASSWORD=meldestelle \
|
||
-e KC_HEALTH_ENABLED=true \
|
||
-e JAVA_OPTS="-Xms256m -Xmx1024m -XX:MaxRAMPercentage=60" \
|
||
quay.io/keycloak/keycloak:${{ env.KEYCLOAK_VERSION }} \
|
||
start-dev
|
||
|
||
echo "Giving Keycloak 30s to initialize..."; sleep 30
|
||
|
||
wait_for() {
|
||
local url="$1"; local label="$2"; local timeout="${3:-180}"; local interval="${4:-5}"
|
||
echo "Waiting for $label ($url) ..."
|
||
if ! timeout ${timeout}s bash -c 'until curl -fsS --output /dev/null '"$url"'; do echo -n "."; sleep '"$interval"'; done'; then
|
||
echo "\n[WAIT] Timeout on $url"
|
||
return 1
|
||
fi
|
||
echo "\n[WAIT] $label is up"
|
||
}
|
||
|
||
if ! wait_for http://localhost:8180/ "root" 180 5; then
|
||
docker logs --tail=200 keycloak || true
|
||
exit 1
|
||
fi
|
||
if ! wait_for http://localhost:8180/health "health" 180 5; then
|
||
echo "[INFO] /health nicht erreichbar – versuche /q/health (Quarkus default)"
|
||
wait_for http://localhost:8180/q/health "q-health" 180 5 || true
|
||
fi
|
||
wait_for http://localhost:8180/health/ready "health-ready" 300 5 || true
|
||
wait_for http://localhost:8180/admin/master/console/ "admin-console" 300 5 || (docker logs --tail=400 keycloak && exit 1)
|
||
|
||
- name: Start Keycloak with dev-file (no Postgres) and wait for readiness
|
||
if: ${{ matrix.keycloak_db == 'dev-file' }}
|
||
run: |
|
||
set -euo pipefail
|
||
echo "Starting Keycloak (DB=dev-file, no Postgres)..."
|
||
docker run -d --name keycloak \
|
||
-p 8180:8080 \
|
||
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
|
||
-e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
|
||
-e KC_DB=dev-file \
|
||
-e KC_HEALTH_ENABLED=true \
|
||
-e JAVA_OPTS="-Xms256m -Xmx1024m -XX:MaxRAMPercentage=60" \
|
||
quay.io/keycloak/keycloak:${{ env.KEYCLOAK_VERSION }} \
|
||
start-dev
|
||
|
||
echo "Giving Keycloak 20s to initialize..."; sleep 20
|
||
|
||
wait_for() {
|
||
local url="$1"; local label="$2"; local timeout="${3:-180}"; local interval="${4:-5}"
|
||
echo "Waiting for $label ($url) ..."
|
||
if ! timeout ${timeout}s bash -c 'until curl -fsS --output /dev/null '"$url"'; do echo -n "."; sleep '"$interval"'; done'; then
|
||
echo "\n[WAIT] Timeout on $url"
|
||
return 1
|
||
fi
|
||
echo "\n[WAIT] $label is up"
|
||
}
|
||
|
||
if ! wait_for http://localhost:8180/ "root" 180 5; then
|
||
docker logs --tail=200 keycloak || true
|
||
exit 1
|
||
fi
|
||
if ! wait_for http://localhost:8180/health "health" 180 5; then
|
||
echo "[INFO] /health nicht erreichbar – versuche /q/health (Quarkus default)"
|
||
wait_for http://localhost:8180/q/health "q-health" 180 5 || true
|
||
fi
|
||
wait_for http://localhost:8180/health/ready "health-ready" 300 5 || true
|
||
wait_for http://localhost:8180/admin/master/console/ "admin-console" 300 5 || (docker logs --tail=400 keycloak && exit 1)
|
||
|
||
- name: Grant execute permission for gradlew
|
||
run: chmod +x gradlew
|
||
|
||
- name: Static Analysis
|
||
run: ./gradlew staticAnalysis --no-daemon
|
||
|
||
- name: Run integration tests
|
||
run: ./gradlew integrationTest --no-daemon --parallel
|
||
env:
|
||
# Environment variables for Redis connection
|
||
REDIS_HOST: localhost
|
||
REDIS_PORT: 6379
|
||
# Keycloak base URL for integration tests (manual container)
|
||
KEYCLOAK_AUTH_SERVER_URL: http://localhost:8180
|
||
# Spring profile for integration tests
|
||
SPRING_PROFILES_ACTIVE: integration-test
|
||
|
||
- name: Upload test reports
|
||
uses: actions/upload-artifact@v5
|
||
if: always()
|
||
with:
|
||
name: integration-test-reports
|
||
path: |
|
||
**/build/reports/tests/integrationTest/
|
||
**/build/test-results/integrationTest/
|
||
retention-days: 7
|
||
|
||
- name: Dump service logs (Keycloak, Postgres)
|
||
if: always()
|
||
run: |
|
||
echo "=== Docker ps ===" && docker ps -a || true
|
||
echo "=== Keycloak logs (tail) ===" && docker logs --tail=400 keycloak || true
|
||
echo "=== Postgres logs (tail) ===" && docker logs --tail=200 $(docker ps -a --filter "name=postgres" --format "{{.ID}}") || true
|