CICD - Unit | Integration | E2E #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ============================================================================= | |
| # CI/CD Pipeline | |
| # ============================================================================= | |
| # | |
| # Two-stage pipeline that gates merges to main: | |
| # Stage 1 (test): Unit + integration tests on GH Actions runner | |
| # [TODO] Stage 2 (e2e): Playwright E2E against a real staging deployment | |
| # | |
| # Both stages must pass before a PR can be merged to main. | |
| # Merging to main triggers production deploy via Coolify (existing setup). | |
| # | |
| # REQUIRED BRANCH PROTECTION RULES ON main: | |
| # - Require status checks for unit-integration and e2e | |
| # - Require branches to be up to date before merging | |
| # ============================================================================= | |
| name: CI Pipeline | |
| on: | |
| pull_request: | |
| branches: [main] | |
| # ============================================================================= | |
| # WHY NO WORKFLOW-LEVEL CONCURRENCY: | |
| # | |
| # We need different concurrency strategies per job: | |
| # - unit-integration: cancel-in-progress per PR (fast feedback on new pushes) | |
| # - e2e: queue globally (staging is a shared single resource) | |
| # | |
| # Workflow-level concurrency would force one strategy for both. | |
| # ============================================================================= | |
| jobs: | |
| # =========================================================================== | |
| # STAGE 1: Unit & Integration Tests | |
| # =========================================================================== | |
| # | |
| # Runs Vitest against a local Supabase subset. | |
| # | |
| # Concurrency: cancel-in-progress PER PR. If you push again to the same PR | |
| # while tests are running, the old run is killed immediately. No point | |
| # finishing tests on stale code. | |
| # =========================================================================== | |
| unit-integration: | |
| name: Unit & Integration Tests | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| concurrency: | |
| group: test-pr-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| # ------------------------------------------------------------------------- | |
| # maximum amount of time a job or step can run before GitHub automatically cancels it | |
| # ------------------------------------------------------------------------- | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| # use Node version enforced for the project | |
| # see https://github.com/actions/setup-node | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| # load the env variables for the sveltekit app | |
| # (slightly) different from .env.ci | |
| - name: Load app env | |
| run: cat cicd/.env.app.ci >> "$GITHUB_ENV" | |
| # ----------------------------------------------------------------------- | |
| - name: Run Unit Tests | |
| run: npm run test:unit | |
| - name: Run Integration Tests | |
| if: always() | |
| run: npm run test:integration | |
| - name: Upload unit coverage | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-unit | |
| path: reports/coverage/unit | |
| retention-days: 7 | |
| - name: Upload integration coverage | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-integration | |
| path: reports/coverage/integration | |
| retention-days: 7 | |
| # https://github.com/davelosert/vitest-coverage-report-action | |
| - name: Report Unit Coverage | |
| # Set if: always() to also generate the report if tests are failing | |
| # Only works if you set `reportOnFailure: true` in your vite config as specified above | |
| if: always() | |
| uses: davelosert/vitest-coverage-report-action@v2 | |
| with: | |
| name: Unit | |
| json-summary-path: reports/coverage/unit/coverage-summary.json | |
| json-final-path: reports/coverage/unit/coverage-final.json | |
| vite-config-path: vitest.config.unit.ts | |
| - name: Report Integration Coverage | |
| if: always() | |
| uses: davelosert/vitest-coverage-report-action@v2 | |
| with: | |
| name: Integration | |
| json-summary-path: reports/coverage/integration/coverage-summary.json | |
| json-final-path: reports/coverage/integration/coverage-final.json | |
| vite-config-path: vitest.config.integration.ts |