# CI: every pull request and every push to main must pass these checks # (ADR 0014). The deploy pipeline (CD) lives in cd.yml and only runs on # main after this workflow's quality bar. # # Runner requirements: an act_runner with the `ubuntu-latest` label and # Docker access (see deploy/stages.md, issue #9). name: CI on: pull_request: push: branches: [main] jobs: checks: name: Lint, typecheck, test runs-on: ubuntu-latest services: postgres: image: postgres:17.5-alpine env: POSTGRES_USER: test POSTGRES_PASSWORD: test POSTGRES_DB: test env: # Enables the database-backed test suites (vitest.global-setup.ts). TEST_DATABASE_URL: postgresql://test:test@postgres:5432/test steps: - name: Check out repository uses: actions/checkout@v4 - name: Set up pnpm uses: pnpm/action-setup@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - name: Install dependencies run: pnpm install --frozen-lockfile # Build first: package type checks resolve @dorfteich/shared through # its built dist, and i18n:check imports the built helpers. - name: Build all packages run: pnpm build - name: Lint (ESLint + Prettier) run: pnpm lint - name: Typecheck run: pnpm typecheck - name: Unit and integration tests run: pnpm test - name: Translation key parity (de/en) run: pnpm i18n:check # Job id/display name kept stable (branch-protection/status-check # matching uses the reported "CI / Auth e2e pack" context) even though # it now also runs the content pack (issue #32) against the same # already-built-and-seeded stack, instead of spinning up a second one. auth-e2e: name: Auth e2e pack runs-on: ubuntu-latest services: postgres: image: postgres:17.5-alpine env: POSTGRES_USER: e2e POSTGRES_PASSWORD: e2e POSTGRES_DB: e2e mailpit: image: axllent/mailpit:latest env: DATABASE_URL: postgresql://e2e:e2e@postgres:5432/e2e APP_BASE_URL: http://localhost:5173 SMTP_HOST: mailpit SMTP_PORT: '1025' steps: - name: Check out repository uses: actions/checkout@v4 - name: Set up pnpm uses: pnpm/action-setup@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build packages run: pnpm build - name: Apply migrations run: pnpm --filter @dorfteich/api exec prisma migrate deploy - name: Seed fixtures run: pnpm --filter @dorfteich/api db:seed - name: Start api, collab, and static web server run: | (cd apps/api && PORT=3001 node dist/main.js > /tmp/api.log 2>&1 &) (cd apps/collab && PORT=3002 node dist/index.js > /tmp/collab.log 2>&1 &) (PORT=5173 COLLAB_TARGET=http://127.0.0.1:3002 node scripts/e2e-static-server.mjs > /tmp/web.log 2>&1 &) for i in $(seq 1 30); do curl -sf http://localhost:3001/api/v1/readyz >/dev/null && break sleep 2 done for i in $(seq 1 30); do curl -sf http://localhost:3002/healthz >/dev/null && break sleep 2 done curl -sf http://localhost:5173/ >/dev/null - name: Install Playwright browser run: pnpm --filter @dorfteich/web exec playwright install --with-deps chromium - name: Run auth pack run: | E2E_BASE_URL=http://localhost:5173 E2E_MAILPIT_URL=http://mailpit:8025 \ pnpm --filter @dorfteich/web exec playwright test e2e/auth.spec.ts # auth.spec.ts's own logins (contextForUser per test) already spend # a good chunk of the login rate limit (10/min/IP, operations.md) — # reset it before content.spec.ts's five more, or its later tests # 429 (found by reproducing this job's failure locally, issue #32). - name: Reset login rate limit between e2e packs run: | echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \ pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL" - name: Run content pack run: | E2E_BASE_URL=http://localhost:5173 \ pnpm --filter @dorfteich/web exec playwright test e2e/content.spec.ts # The collab pack opens two browser contexts per test (more logins), # so reset the login rate limit before it as well (see note above). - name: Reset login rate limit before collab pack run: | echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \ pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL" - name: Run collab pack run: | E2E_BASE_URL=http://localhost:5173 \ pnpm --filter @dorfteich/web exec playwright test e2e/collab.spec.ts - name: Reset login rate limit before offline pack run: | echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \ pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL" - name: Run offline pack run: | E2E_BASE_URL=http://localhost:5173 \ pnpm --filter @dorfteich/web exec playwright test e2e/offline.spec.ts - name: Reset login rate limit before labels pack run: | echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \ pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL" - name: Run labels pack run: | E2E_BASE_URL=http://localhost:5173 \ pnpm --filter @dorfteich/web exec playwright test e2e/labels.spec.ts - name: Reset login rate limit before reorder pack run: | echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \ pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL" - name: Run reorder pack run: | E2E_BASE_URL=http://localhost:5173 \ pnpm --filter @dorfteich/web exec playwright test e2e/reorder.spec.ts - name: Reset login rate limit before wikilink pack run: | echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \ pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL" - name: Run wikilink pack run: | E2E_BASE_URL=http://localhost:5173 \ pnpm --filter @dorfteich/web exec playwright test e2e/wikilink.spec.ts - name: Reset login rate limit before backlinks pack run: | echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \ pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL" - name: Run backlinks pack run: | E2E_BASE_URL=http://localhost:5173 \ pnpm --filter @dorfteich/web exec playwright test e2e/backlinks.spec.ts - name: Dump server logs on failure if: failure() run: tail -50 /tmp/api.log /tmp/collab.log /tmp/web.log || true images: name: Build container images # PR-only: on main the CD workflow builds and pushes the same images — # building twice would waste the runner (ADR 0014: build once, promote). if: github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v4 # PRs prove the Dockerfiles still build; pushing happens in cd.yml. - name: Build web image run: docker build -f apps/web/Dockerfile --build-arg APP_VERSION=${{ github.sha }} -t dorfteich-web:ci . - name: Build api image run: docker build -f apps/api/Dockerfile --build-arg APP_VERSION=${{ github.sha }} -t dorfteich-api:ci . - name: Build collab image run: docker build -f apps/collab/Dockerfile --build-arg APP_VERSION=${{ github.sha }} -t dorfteich-collab:ci .