name: CI on: push: branches: [main, develop] pull_request: branches: [main, develop] concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: check-changes: name: Check for app changes runs-on: ubuntu-latest outputs: should_test: ${{ steps.filter.outputs.should_test }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Check changed files id: filter run: | if [ "${{ github.event_name }}" = "push" ]; then echo "should_test=true" >> "$GITHUB_OUTPUT" exit 0 fi CHANGED=$(git diff --name-only origin/main...HEAD || true) if echo "$CHANGED" | grep -qE '^(src/|frontend/|tests/|package\.json|package-lock\.json|tsconfig\.json|vite\.config|vitest\.config|playwright\.config)'; then echo "should_test=true" >> "$GITHUB_OUTPUT" else echo "No application code changed, skipping tests" echo "should_test=false" >> "$GITHUB_OUTPUT" fi setup: name: Install & Build needs: check-changes if: needs.check-changes.outputs.should_test == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup Node.js uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20.x' - name: Cache node_modules id: cache-nm uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: node_modules key: node-modules-${{ runner.os }}-node20-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-nm.outputs.cache-hit != 'true' run: npm ci - name: Build run: npm run build - name: Upload build output uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v4.6.2 with: name: dist path: dist/ retention-days: 1 test: name: Unit & Integration Tests needs: setup runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup Node.js uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20.x' - name: Restore node_modules from cache uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: node_modules key: node-modules-${{ runner.os }}-node20-${{ hashFiles('package-lock.json') }} - name: Run tests run: npm test lint: name: Lint & Type Check needs: setup runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup Node.js uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20.x' - name: Restore node_modules from cache uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: node_modules key: node-modules-${{ runner.os }}-node20-${{ hashFiles('package-lock.json') }} - name: Type check run: npm run type-check e2e: name: E2E Tests needs: setup runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup Node.js uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20.x' - name: Restore node_modules from cache uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: node_modules key: node-modules-${{ runner.os }}-node20-${{ hashFiles('package-lock.json') }} - name: Download build output uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: dist path: dist/ - name: Check build artifacts run: | test -f dist/index.js test -f dist/server.js test -d dist/frontend - name: Get Playwright version id: pw-version run: echo "version=$(node -e "console.log(require('./node_modules/@playwright/test/package.json').version)")" >> "$GITHUB_OUTPUT" - name: Cache Playwright browsers id: cache-pw uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ steps.pw-version.outputs.version }} - name: Install Playwright browsers if: steps.cache-pw.outputs.cache-hit != 'true' run: ./node_modules/.bin/playwright install --with-deps chromium - name: Install Playwright system deps if: steps.cache-pw.outputs.cache-hit == 'true' run: ./node_modules/.bin/playwright install-deps chromium - name: Run E2E tests run: npm run test:e2e env: EXCALIDRAW_DB_PATH: /tmp/excalidraw-e2e-ci.db - name: Upload Playwright report if: failure() uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v4.6.2 with: name: playwright-report path: playwright-report/ retention-days: 7 ci-status: runs-on: ubuntu-latest continue-on-error: false name: CI Status Check needs: [check-changes, setup, test, lint, e2e] if: always() permissions: statuses: write steps: - name: Failed id: failed if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') run: | curl -X POST -H "Content-Type: application/json" -H "Authorization: token ${{ github.token }}" \ -d '{ "state" : "failure" , "context" : "github/ci-status-check" , "description" : "CI checks failed", "target_url" : "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" }' \ https://api.github.com/repos/${{ github.repository }}/statuses/${{ github.sha }} exit 1 - name: Success if: steps.failed.conclusion == 'skipped' run: | curl -X POST -H "Content-Type: application/json" -H "Authorization: token ${{ github.token }}" \ -d '{ "state" : "success" , "context" : "github/ci-status-check" , "description" : "CI checks passed", "target_url" : "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" }' \ https://api.github.com/repos/${{ github.repository }}/statuses/${{ github.sha }}