CI #925
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
| name: CI | |
| on: | |
| push: | |
| branches: [master] | |
| pull_request: | |
| branches: [master] | |
| schedule: | |
| # Run daily at 2 AM UTC to refresh data | |
| - cron: '0 2 * * *' | |
| workflow_dispatch: | |
| # Allow manual triggering | |
| permissions: | |
| contents: read | |
| # Cancel in-progress runs for the same ref on PR and push events. | |
| # Schedule and workflow_dispatch runs each get a unique group via run_id | |
| # so they are never cancelled mid-flight (data-refresh is long-running). | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }}-${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.run_id || 'default' }} | |
| cancel-in-progress: ${{ github.event_name != 'schedule' && github.event_name != 'workflow_dispatch' }} | |
| jobs: | |
| detect-change-scope: | |
| name: Detect non-runtime-only changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| lightweight_only: ${{ steps.changed-files.outputs.lightweight_only }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Detect non-runtime-only changes | |
| id: changed-files | |
| shell: bash | |
| run: | | |
| if [[ "${{ github.event_name }}" == "schedule" || "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| echo "lightweight_only=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if [[ "${{ github.event_name }}" == "pull_request" ]]; then | |
| base_sha="${{ github.event.pull_request.base.sha }}" | |
| head_sha="${{ github.event.pull_request.head.sha }}" | |
| else | |
| base_sha="${{ github.event.before }}" | |
| head_sha="${{ github.sha }}" | |
| fi | |
| if [[ -z "$base_sha" || "$base_sha" =~ ^0+$ ]]; then | |
| echo "lightweight_only=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| changed_files="$(git diff --name-only "$base_sha" "$head_sha")" | |
| if [[ -z "$changed_files" ]]; then | |
| echo "lightweight_only=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # Safe-to-skip patterns for heavyweight CI jobs. | |
| # Keep this list narrow and repo-specific. Any path not matched here | |
| # will run full CI gates. | |
| lightweight_patterns='(^docs/|\.md$|^LICENSE$|^\.github/|^\.vscode/|^\.editorconfig$|^\.gitignore$|^\.prettier.*$|^biome\.jsonc$)' | |
| non_runtime_count="$(printf '%s\n' "$changed_files" | grep -Evc "$lightweight_patterns" || true)" | |
| if [[ "$non_runtime_count" == "0" ]]; then | |
| echo "lightweight_only=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "lightweight_only=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| test: | |
| name: Test Suite | |
| runs-on: ubuntu-latest | |
| needs: detect-change-scope | |
| if: needs.detect-change-scope.outputs.lightweight_only != 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js and pnpm | |
| uses: ./.github/actions/setup-node-pnpm | |
| - name: Run non-browser tests with coverage for PR/push | |
| if: github.event_name == 'pull_request' || github.event_name == 'push' | |
| run: pnpm run test:coverage | |
| - name: Run non-browser tests for schedule/manual runs | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| run: pnpm run test:run | |
| - name: Upload coverage artifacts | |
| if: github.event_name == 'pull_request' || github.event_name == 'push' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-${{ github.sha }} | |
| path: coverage/ | |
| retention-days: 7 | |
| browser-test: | |
| name: Browser Test Suite | |
| runs-on: ubuntu-latest | |
| needs: [detect-change-scope, test] | |
| if: needs.detect-change-scope.outputs.lightweight_only != 'true' && (github.event_name == 'pull_request' || github.event_name == 'push') | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js and pnpm | |
| uses: ./.github/actions/setup-node-pnpm | |
| - name: Get Playwright version | |
| id: playwright-version | |
| shell: bash | |
| run: echo "version=$(pnpm exec playwright --version | awk '{print $2}')" >> "$GITHUB_OUTPUT" | |
| - name: Cache Playwright browsers | |
| id: playwright-cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }} | |
| - name: Install Playwright browsers | |
| if: steps.playwright-cache.outputs.cache-hit != 'true' | |
| run: pnpm exec playwright install --with-deps chromium | |
| - name: Install Playwright system dependencies | |
| if: steps.playwright-cache.outputs.cache-hit == 'true' | |
| run: pnpm exec playwright install-deps chromium | |
| - name: Run browser-only test suite | |
| run: pnpm run test:run:browser | |
| type-check: | |
| name: Type Check | |
| runs-on: ubuntu-latest | |
| needs: detect-change-scope | |
| if: needs.detect-change-scope.outputs.lightweight_only != 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js and pnpm | |
| uses: ./.github/actions/setup-node-pnpm | |
| - name: Run type-check | |
| run: pnpm run type-check | |
| code-quality: | |
| name: Code Quality | |
| runs-on: ubuntu-latest | |
| needs: detect-change-scope | |
| if: needs.detect-change-scope.outputs.lightweight_only != 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js and pnpm | |
| uses: ./.github/actions/setup-node-pnpm | |
| - name: Run full validation | |
| run: pnpm run validate | |
| release-gate: | |
| name: Release Gate | |
| runs-on: ubuntu-latest | |
| needs: [detect-change-scope, test, browser-test, type-check, code-quality] | |
| if: always() | |
| steps: | |
| - name: Enforce required checks | |
| run: | | |
| if [[ "${{ needs.detect-change-scope.outputs.lightweight_only }}" == "true" ]]; then | |
| echo "Non-runtime-only change detected; skipping heavy CI gates" | |
| exit 0 | |
| fi | |
| if [[ "${{ needs.test.result }}" != "success" ]]; then | |
| echo "Test Suite must pass before release gating" | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.browser-test.result }}" != "success" && "${{ needs.browser-test.result }}" != "skipped" ]]; then | |
| echo "Browser Test Suite must pass before release gating" | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.code-quality.result }}" != "success" ]]; then | |
| echo "Code Quality must pass before release gating" | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.type-check.result }}" != "success" ]]; then | |
| echo "Type Check must pass before release gating" | |
| exit 1 | |
| fi | |
| echo "Required release checks passed" | |
| data-refresh: | |
| name: Data Download & Validation | |
| runs-on: ubuntu-latest | |
| needs: [detect-change-scope, test, type-check, code-quality] | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js and pnpm | |
| uses: ./.github/actions/setup-node-pnpm | |
| - name: Download fresh Pokemon data | |
| run: | | |
| pnpm run scrape | |
| - name: Run data integrity tests on fresh data | |
| run: | | |
| echo "🧪 Validating data integrity..." | |
| pnpm vitest run tests/data-integrity.test.ts | |
| - name: Display data summary | |
| run: | | |
| echo "📊 Data Summary:" | |
| echo "Pokemon data files:" | |
| find data -name "*.json" -type f | sort | |
| echo "" | |
| echo "File sizes:" | |
| find data -name "*.json" -type f -exec du -h {} \; | |
| - name: Upload data artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: pokemon-data | |
| path: | | |
| data/**/*.json | |
| retention-days: 30 | |
| - name: Check for data changes | |
| id: data-changes | |
| run: | | |
| if [[ -n $(git status --porcelain data/) ]]; then | |
| echo "changes=true" >> $GITHUB_OUTPUT | |
| echo "Data files have been updated" | |
| else | |
| echo "changes=false" >> $GITHUB_OUTPUT | |
| echo "No changes to data files" | |
| fi | |
| - name: Generate data update PR body | |
| if: steps.data-changes.outputs.changes == 'true' && github.event_name == 'schedule' | |
| run: pnpm run data:pr-body -- "$RUNNER_TEMP/data-refresh-pr-body.md" | |
| - name: Create Pull Request with updated data | |
| if: steps.data-changes.outputs.changes == 'true' && github.event_name == 'schedule' | |
| uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| commit-message: 'chore: update Pokemon data files' | |
| title: '🤖 Auto-update Pokemon data' | |
| body-path: ${{ runner.temp }}/data-refresh-pr-body.md | |
| branch: auto-update-data | |
| delete-branch: true |