# ============================================================================= # Die Pruefung bei jedem Push. # # Bis Phase 10 gab es 581 Unit- und 266 E2E-Tests — und nichts, was sie # ausfuehrte ausser einem Menschen, der daran dachte. In der Sitzung, in der # die Kassenverwaltung entstand, haben die Tests vier echte Fehler gefunden, # zwei davon in Code, der eine Stunde alt war. Genau das soll hier von allein # passieren. # # Zwei Auftraege, bewusst getrennt: # # pruefung typecheck, lint und die Unit-Tests. Braucht eine Datenbank, # weil ein Teil der Tests die Trigger und RLS gegen echtes # Postgres prueft — mit einer Attrappe waeren sie wertlos. # # oberflaeche die E2E-Tests. Dauern eine Dreiviertelstunde und brauchen den # halben Stack, deshalb laufen sie nur auf main und in Pull # Requests, nicht bei jedem Zwischenstand auf einem Zweig. # ============================================================================= name: Pruefung on: push: branches: [main] pull_request: env: # Dieselben Werte wie in .env.example. Es sind Testdaten in einem # Wegwerf-Container; echte Geheimnisse haben in einer Pipeline nichts zu # suchen und stehen im Betrieb in der .env. POSTGRES_USER: florian POSTGRES_PASSWORD: pruefung POSTGRES_DB: florian POSTGRES_APP_PASSWORD: pruefung_app DATABASE_URL: postgresql://florian_app:pruefung_app@localhost:5432/florian?schema=public DIRECT_DATABASE_URL: postgresql://florian:pruefung@localhost:5432/florian?schema=public AUTH_SECRET: nur-fuer-die-pruefung-nicht-fuer-den-betrieb AUTH_TRUST_HOST: "true" APP_URL: http://localhost:3100 S3_ENDPOINT: localhost S3_PORT: "9000" S3_USE_SSL: "false" S3_ACCESS_KEY: florian S3_SECRET_KEY: pruefung_minio S3_BUCKET: florian REDIS_URL: redis://localhost:6379 TZ: Europe/Berlin jobs: pruefung: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: npm # Das eigene Postgres-Image statt eines fertigen: FLORIAN braucht # PostGIS **und** pgvector, und kein oeffentliches Image bringt beides # mit. Ein Dienst-Container mit postgres:17 wuerde die Migrationen # durchlassen und erst bei der ersten Umkreissuche scheitern. - name: Datenbank bauen und starten run: | docker build -t florian-postgres:pruefung ./docker/postgres docker run -d --name postgres -p 5432:5432 \ -e POSTGRES_USER=$POSTGRES_USER \ -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \ -e POSTGRES_DB=$POSTGRES_DB \ -e POSTGRES_APP_PASSWORD=$POSTGRES_APP_PASSWORD \ -e POSTGRES_INITDB_ARGS="--locale-provider=icu --icu-locale=de-DE --locale=C.UTF-8 --encoding=UTF8" \ -v "$(pwd)/docker/postgres:/docker-entrypoint-initdb.d:ro" \ florian-postgres:pruefung - name: Redis und MinIO starten run: | docker run -d --name redis -p 6379:6379 redis:7-alpine docker run -d --name minio -p 9000:9000 \ -e MINIO_ROOT_USER=$S3_ACCESS_KEY \ -e MINIO_ROOT_PASSWORD=$S3_SECRET_KEY \ minio/minio:latest server /data - run: npm ci - name: Auf die Datenbank warten run: | for i in $(seq 1 60); do docker exec postgres pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" && exit 0 sleep 2 done echo "Postgres kam nicht hoch:" docker logs postgres exit 1 - run: npx prisma generate - run: npm run typecheck - run: npm run lint - name: Migrationen einspielen run: npm run db:migrate # Der Seed gehoert dazu: er ist selbst ein Test. Faellt eine Migration # oder ein Standardwert um, merkt man es hier und nicht erst, wenn eine # Wehr ihn zum ersten Mal ausfuehrt. - name: Beispielbestand anlegen run: npm run db:seed - run: npm run test - name: Aufraeumen if: always() run: docker rm -f postgres redis minio || true oberflaeche: runs-on: ubuntu-latest # Nur wo es sich lohnt: ein voller Lauf dauert etwa 45 Minuten. if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: npm - name: Dienste starten run: | docker build -t florian-postgres:pruefung ./docker/postgres docker run -d --name postgres -p 5432:5432 \ -e POSTGRES_USER=$POSTGRES_USER \ -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \ -e POSTGRES_DB=$POSTGRES_DB \ -e POSTGRES_APP_PASSWORD=$POSTGRES_APP_PASSWORD \ -e POSTGRES_INITDB_ARGS="--locale-provider=icu --icu-locale=de-DE --locale=C.UTF-8 --encoding=UTF8" \ -v "$(pwd)/docker/postgres:/docker-entrypoint-initdb.d:ro" \ florian-postgres:pruefung docker run -d --name redis -p 6379:6379 redis:7-alpine docker run -d --name minio -p 9000:9000 \ -e MINIO_ROOT_USER=$S3_ACCESS_KEY \ -e MINIO_ROOT_PASSWORD=$S3_SECRET_KEY \ minio/minio:latest server /data docker run -d --name gotenberg -p 3001:3000 gotenberg/gotenberg:8 - run: npm ci - run: npx playwright install --with-deps chromium - name: Auf die Datenbank warten run: | for i in $(seq 1 60); do docker exec postgres pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" && exit 0 sleep 2 done docker logs postgres exit 1 - run: npx prisma generate - run: npm run db:migrate # Die E2E-Tests laufen seit Phase 8 gegen eine eigene Wehr, nicht gegen # den Beispielbestand. Das Skript legt beide an. - name: Testwehr anlegen run: npm run db:test-reset - run: npm run build - run: npx playwright test env: GOTENBERG_URL: http://localhost:3001 - name: Fehlerbilder sichern if: failure() uses: actions/upload-artifact@v4 with: name: playwright-bericht path: | playwright-report/ test-results/ retention-days: 7 - name: Aufraeumen if: always() run: docker rm -f postgres redis minio gotenberg || true