name: CI on: push: branches: [master] pull_request: branches: [master] jobs: backend: name: Backend tests runs-on: ubuntu-latest defaults: run: working-directory: backend steps: - uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v4 with: version: latest - name: Set up Python run: uv python install 3.13 - name: Sync dependencies run: uv sync - name: Run pytest run: uv run pytest -v frontend-lint: name: Frontend lint runs-on: ubuntu-latest defaults: run: working-directory: frontend steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22' cache: npm cache-dependency-path: frontend/package-lock.json - name: Install dependencies run: npm ci - name: Run ESLint run: npm run lint frontend-test: name: Frontend unit tests runs-on: ubuntu-latest defaults: run: working-directory: frontend steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22' cache: npm cache-dependency-path: frontend/package-lock.json - name: Install dependencies run: npm ci - name: Run Vitest run: npm test frontend-build: name: Frontend build runs-on: ubuntu-latest defaults: run: working-directory: frontend steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22' cache: npm cache-dependency-path: frontend/package-lock.json - name: Install dependencies run: npm ci - name: Build production bundle run: npm run build e2e: name: Playwright e2e runs-on: ubuntu-latest needs: [backend, frontend-build] steps: - uses: actions/checkout@v4 - name: Start stack run: docker compose -p life-towers -f docker-compose.dev.yml up --build -d - name: Wait for /api/v1/health run: | set -e cid=$(docker compose -p life-towers -f docker-compose.dev.yml ps -q life-towers) for i in $(seq 1 60); do status=$(docker inspect -f '{{.State.Health.Status}}' "$cid" 2>/dev/null || echo starting) if [ "$status" = healthy ]; then echo "stack healthy after ${i} attempts" exit 0 fi sleep 2 done echo "stack failed to become healthy" >&2 docker compose -p life-towers -f docker-compose.dev.yml logs >&2 exit 1 - name: Run Playwright run: | docker run --rm \ --network life-towers_default \ -v "$(pwd)/frontend:/work" \ -w /work \ -e PLAYWRIGHT_BASE_URL=http://life-towers:8000 \ -e CI=true \ mcr.microsoft.com/playwright:v1.60.0-noble \ sh -c 'npm ci && npx playwright test' - name: Upload Playwright report if: always() uses: actions/upload-artifact@v4 with: name: playwright-report path: frontend/playwright-report if-no-files-found: ignore retention-days: 14 - name: Upload visual screenshots if: always() uses: actions/upload-artifact@v4 with: name: playwright-visuals path: frontend/visuals if-no-files-found: ignore retention-days: 14 - name: Dump container logs on failure if: failure() run: docker compose -p life-towers -f docker-compose.dev.yml logs - name: Tear down stack if: always() run: docker compose -p life-towers -f docker-compose.dev.yml down -v