# Continuous integration on GitHub Actions (GitHub is the only home). # Post-merge gate on `main` — the FULL safety net, always: the promote PR # already passed ci-pr (possibly with affected-test selection), so this run # re-verifies everything against the minimal synthetic database, including # build and full e2e. # PRs run in ci-pr.yml; merges to `stage` run in ci-stage.yml (stage Neon # snapshot smoke — never a build there). name: CI on: push: branches: [main] concurrency: group: ci-${{ github.ref }} cancel-in-progress: true env: # Tests load .env.test themselves (database teqo_test on localhost:5432). # These are only for the migrate/seed/build steps, which read the process env. DATABASE_URL: postgresql://teqo:teqo@localhost:5432/teqo_test PAYLOAD_SECRET: test-only-secret-not-used-in-production NEXT_PUBLIC_SITE_URL: http://localhost:3000 jobs: static: runs-on: ubuntu-latest timeout-minutes: 20 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 24 cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm lint - run: pnpm format:check - run: pnpm typecheck - run: pnpm exec knip - run: pnpm check:cycles - run: pnpm test:unit int: runs-on: ubuntu-latest timeout-minutes: 25 services: postgres: # Matches production Neon major (17) and docker-compose.yml. image: postgres:17-alpine env: POSTGRES_USER: teqo POSTGRES_PASSWORD: teqo POSTGRES_DB: teqo_test ports: - 5432:5432 options: >- --health-cmd "pg_isready -U teqo" --health-interval 5s --health-timeout 5s --health-retries 12 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 24 cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm migrate - run: pnpm db:seed:minimal - run: pnpm test:int build: runs-on: ubuntu-latest timeout-minutes: 25 services: postgres: image: postgres:17-alpine env: POSTGRES_USER: teqo POSTGRES_PASSWORD: teqo POSTGRES_DB: teqo_test ports: - 5432:5432 options: >- --health-cmd "pg_isready -U teqo" --health-interval 5s --health-timeout 5s --health-retries 12 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 24 cache: pnpm - run: pnpm install --frozen-lockfile - name: Build (against the local service database) run: pnpm build e2e: runs-on: ubuntu-latest timeout-minutes: 40 services: postgres: image: postgres:17-alpine env: POSTGRES_USER: teqo POSTGRES_PASSWORD: teqo POSTGRES_DB: teqo_test ports: - 5432:5432 options: >- --health-cmd "pg_isready -U teqo" --health-interval 5s --health-timeout 5s --health-retries 12 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 24 cache: pnpm - run: pnpm install --frozen-lockfile - name: Install Playwright chromium run: pnpm exec playwright install --with-deps chromium - run: pnpm migrate - run: pnpm db:seed:minimal - name: Build for e2e run: pnpm build env: NEXT_DIST_DIR: .next/e2e - name: E2E tests (full suite) run: pnpm test:e2e # Same legacy branch-protection context as ci-pr.yml (see comment there). checks: name: checks runs-on: ubuntu-latest needs: [static, int, build, e2e] if: always() steps: - name: All parallel checks green env: NEEDS: ${{ toJSON(needs) }} run: | set -euo pipefail echo "$NEEDS" | jq -e ' to_entries | all(.value.result == "success" or .value.result == "skipped") '