name: ci-cd on: push: branches: - main pull_request: workflow_dispatch: jobs: quality: runs-on: projecte-runner timeout-minutes: 30 steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 1 # Self-hosted Gitea runners may not be able to resolve actions from # github.com. If the checkout action above failed (e.g. it could not be # fetched), fall back to a manual shallow clone from the Gitea server. - name: Fallback checkout (manual clone) if: failure() shell: bash run: | set -euo pipefail SERVER_URL="${{ github.server_url }}" REPO="${{ github.repository }}" TOKEN="${{ github.token }}" HOST="${SERVER_URL#https://}" HOST="${HOST#http://}" rm -rf ./* ./.git 2>/dev/null || true echo "Manual shallow clone from ${HOST}/${REPO}" git clone --depth 1 "https://oauth2:${TOKEN}@${HOST}/${REPO}.git" . - name: Ensure bun shell: bash run: command -v bun || npm i -g bun@1.3.14 - name: Install dependencies shell: bash run: bun install --frozen-lockfile || bun install - name: Typecheck shell: bash run: bun run typecheck - name: Build web shell: bash run: cd apps/web && bun run build - name: Docker compose build shell: bash env: POSTGRES_PASSWORD: ci-placeholder AUTH_SECRET: ci-placeholder run: docker compose build e2e: runs-on: projecte-runner needs: quality timeout-minutes: 25 steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 1 # Self-hosted Gitea runners may not be able to resolve actions from # github.com. If the checkout action above failed (e.g. it could not be # fetched), fall back to a manual shallow clone from the Gitea server. - name: Fallback checkout (manual clone) if: failure() shell: bash run: | set -euo pipefail SERVER_URL="${{ github.server_url }}" REPO="${{ github.repository }}" TOKEN="${{ github.token }}" HOST="${SERVER_URL#https://}" HOST="${HOST#http://}" rm -rf ./* ./.git 2>/dev/null || true echo "Manual shallow clone from ${HOST}/${REPO}" git clone --depth 1 "https://oauth2:${TOKEN}@${HOST}/${REPO}.git" . - name: Ensure bun shell: bash run: command -v bun || npm i -g bun@1.3.14 - name: Install dependencies shell: bash run: bun install --frozen-lockfile || bun install - name: Start ephemeral Postgres shell: bash run: | set -euo pipefail docker rm -f projecte-e2e-db >/dev/null 2>&1 || true docker run -d --name projecte-e2e-db \ -e POSTGRES_PASSWORD=test \ -e POSTGRES_DB=project_e \ -e POSTGRES_USER=project_e \ -p 5433:5432 \ postgres:16-alpine echo "Waiting for Postgres to accept connections..." for i in $(seq 1 30); do if docker exec projecte-e2e-db pg_isready -U project_e -d project_e >/dev/null 2>&1; then echo "Postgres ready" exit 0 fi sleep 1 done echo "ERROR: Postgres did not become ready in time" exit 1 - name: Sync database schema shell: bash env: DATABASE_URL: postgresql://project_e:test@localhost:5433/project_e run: bun run db:migrate - name: Install Playwright chromium shell: bash run: npx playwright install --with-deps chromium # The Playwright webServer boots the API + Vite dev server itself via # `bun run dev`. The API needs the ephemeral DB connection, and the admin # auto-creation on first login depends on INITIAL_ADMIN_* — the same # values the e2e fixtures fall back to. - name: Run E2E tests (chromium) shell: bash env: DATABASE_URL: postgresql://project_e:test@localhost:5433/project_e INITIAL_ADMIN_EMAIL: admin@example.com INITIAL_ADMIN_PASSWORD: testpassword123 CI: "1" # The host runs the production stack on :3000/:3001; shift the e2e # dev servers to :3100/:3101 so Playwright doesn't collide with prod. VITE_PORT: "3100" PORT: "3101" API_PROXY_TARGET: http://localhost:3101 E2E_BASE_URL: http://localhost:3100 E2E_WEB_SERVER_CMD: bun run dev E2E_WEB_SERVER_URL: http://localhost:3100/api/health run: bunx playwright test - name: Stop ephemeral Postgres if: always() shell: bash run: docker rm -f projecte-e2e-db >/dev/null 2>&1 || true