feat(api): add wake-triggered feed auto-refresh #27
Workflow file for this run
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: pr-quality | |
| on: | |
| pull_request: | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| concurrency: | |
| group: pr-quality-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| CI: true | |
| # prisma generate (via prelint/pretypecheck/prebuild) requires DATABASE_URL | |
| # to be set, even though the static/format/scope jobs never connect to a | |
| # database. Jobs that need a real connection override this at the job level. | |
| DATABASE_URL: postgresql://placeholder:placeholder@127.0.0.1:5432/placeholder | |
| jobs: | |
| scope: | |
| name: pr-quality / scope | |
| runs-on: ubuntu-latest | |
| outputs: | |
| docs_only: ${{ steps.scope.outputs.docs_only }} | |
| code_change: ${{ steps.scope.outputs.code_change }} | |
| run_mode: ${{ steps.scope.outputs.run_mode }} | |
| can_use_remote_cache: ${{ steps.scope.outputs.can_use_remote_cache }} | |
| reason: ${{ steps.scope.outputs.reason }} | |
| steps: | |
| - name: Check out trusted base for scope evaluation | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.event.pull_request.base.sha }} | |
| fetch-depth: 1 | |
| path: .trusted-base | |
| persist-credentials: false | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 24.14.1 | |
| - name: Collect changed files from the pull request | |
| id: files | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const files = await github.paginate(github.rest.pulls.listFiles, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.payload.pull_request.number, | |
| per_page: 100, | |
| }); | |
| core.setOutput( | |
| 'changed_files_json', | |
| JSON.stringify(files.map((file) => file.filename)), | |
| ); | |
| - name: Classify PR scope from trusted base logic | |
| id: scope | |
| env: | |
| CHANGED_FILES_JSON: ${{ steps.files.outputs.changed_files_json }} | |
| PR_HEAD_REPO_FULL_NAME: ${{ github.event.pull_request.head.repo.full_name }} | |
| HAS_TURBO_TOKEN: ${{ secrets.TURBO_TOKEN != '' }} | |
| HAS_TURBO_TEAM: ${{ secrets.TURBO_TEAM != '' }} | |
| run: | | |
| node .trusted-base/.github/scripts/pr-quality-scope.mjs \ | |
| --changed-files-json "$CHANGED_FILES_JSON" \ | |
| --github-output "$GITHUB_OUTPUT" | |
| format: | |
| name: pr-quality / format | |
| needs: scope | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Fail when scope classification did not complete | |
| if: ${{ needs.scope.result != 'success' }} | |
| run: | | |
| echo "Scope classification failed; refusing to report a false-success quality result." | |
| exit 1 | |
| - name: Check out trusted base for planning | |
| if: ${{ needs.scope.result == 'success' }} | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.event.pull_request.base.sha }} | |
| fetch-depth: 1 | |
| path: .trusted-base | |
| persist-credentials: false | |
| - name: Set up Node.js | |
| if: ${{ needs.scope.result == 'success' }} | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 24.14.1 | |
| - name: Plan format command | |
| if: ${{ needs.scope.result == 'success' }} | |
| id: plan | |
| run: | | |
| node .trusted-base/.github/scripts/pr-quality-command-plan.mjs \ | |
| --job format \ | |
| --docs-only "${{ needs.scope.outputs.docs_only }}" \ | |
| --run-mode "${{ needs.scope.outputs.run_mode }}" \ | |
| --can-use-remote-cache "${{ needs.scope.outputs.can_use_remote_cache }}" \ | |
| --github-output "$GITHUB_OUTPUT" | |
| - name: Check out repository | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up pnpm | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: pnpm/action-setup@v5 | |
| with: | |
| version: 10.33.0 | |
| - name: Set up cached Node.js | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 24.14.1 | |
| cache: pnpm | |
| - name: Install dependencies | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| run: pnpm install --frozen-lockfile | |
| - name: Docs-only no-op | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run != 'true' }} | |
| run: | | |
| echo "Docs-only PR: format gate intentionally no-op." | |
| - name: Run format gate | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| run: ${{ steps.plan.outputs.command }} | |
| static: | |
| name: pr-quality / static | |
| needs: scope | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Fail when scope classification did not complete | |
| if: ${{ needs.scope.result != 'success' }} | |
| run: | | |
| echo "Scope classification failed; refusing to report a false-success quality result." | |
| exit 1 | |
| - name: Check out trusted base for planning | |
| if: ${{ needs.scope.result == 'success' }} | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.event.pull_request.base.sha }} | |
| fetch-depth: 1 | |
| path: .trusted-base | |
| persist-credentials: false | |
| - name: Set up Node.js | |
| if: ${{ needs.scope.result == 'success' }} | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 24.14.1 | |
| - name: Plan static commands | |
| if: ${{ needs.scope.result == 'success' }} | |
| id: plan | |
| run: | | |
| node .trusted-base/.github/scripts/pr-quality-command-plan.mjs \ | |
| --job static \ | |
| --docs-only "${{ needs.scope.outputs.docs_only }}" \ | |
| --run-mode "${{ needs.scope.outputs.run_mode }}" \ | |
| --can-use-remote-cache "${{ needs.scope.outputs.can_use_remote_cache }}" \ | |
| --github-output "$GITHUB_OUTPUT" | |
| - name: Check out repository | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up pnpm | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: pnpm/action-setup@v5 | |
| with: | |
| version: 10.33.0 | |
| - name: Set up cached Node.js | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 24.14.1 | |
| cache: pnpm | |
| - name: Install dependencies | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| run: pnpm install --frozen-lockfile | |
| - name: Docs-only no-op | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run != 'true' }} | |
| run: | | |
| echo "Docs-only PR: static gate intentionally no-op." | |
| - name: Run static gate | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| env: | |
| TURBO_TOKEN: ${{ steps.plan.outputs.uses_remote_cache == 'true' && secrets.TURBO_TOKEN || '' }} | |
| TURBO_TEAM: ${{ steps.plan.outputs.uses_remote_cache == 'true' && secrets.TURBO_TEAM || '' }} | |
| run: ${{ steps.plan.outputs.command }} | |
| test: | |
| name: pr-quality / test | |
| needs: scope | |
| if: always() | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:18 | |
| env: | |
| POSTGRES_DB: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_USER: postgres | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U postgres -d postgres" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| env: | |
| DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/rssift_ci | |
| TEST_DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/rssift_test_ci | |
| INGEST_ON_BOOT: false | |
| steps: | |
| - name: Fail when scope classification did not complete | |
| if: ${{ needs.scope.result != 'success' }} | |
| run: | | |
| echo "Scope classification failed; refusing to report a false-success quality result." | |
| exit 1 | |
| - name: Check out trusted base for planning | |
| if: ${{ needs.scope.result == 'success' }} | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.event.pull_request.base.sha }} | |
| fetch-depth: 1 | |
| path: .trusted-base | |
| persist-credentials: false | |
| - name: Set up Node.js | |
| if: ${{ needs.scope.result == 'success' }} | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 24.14.1 | |
| - name: Plan test commands | |
| if: ${{ needs.scope.result == 'success' }} | |
| id: plan | |
| run: | | |
| node .trusted-base/.github/scripts/pr-quality-command-plan.mjs \ | |
| --job test \ | |
| --docs-only "${{ needs.scope.outputs.docs_only }}" \ | |
| --run-mode "${{ needs.scope.outputs.run_mode }}" \ | |
| --can-use-remote-cache "${{ needs.scope.outputs.can_use_remote_cache }}" \ | |
| --github-output "$GITHUB_OUTPUT" | |
| - name: Check out repository | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up pnpm | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: pnpm/action-setup@v5 | |
| with: | |
| version: 10.33.0 | |
| - name: Set up cached Node.js | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 24.14.1 | |
| cache: pnpm | |
| - name: Install dependencies | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| run: pnpm install --frozen-lockfile | |
| - name: Provision PostgreSQL 18 test databases | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| run: pnpm --filter api exec node scripts/provision-ci-dbs.mjs | |
| - name: Docs-only no-op | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run != 'true' }} | |
| run: | | |
| echo "Docs-only PR: test gate intentionally no-op." | |
| - name: Run test gate | |
| if: ${{ needs.scope.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| env: | |
| TURBO_TOKEN: ${{ steps.plan.outputs.uses_remote_cache == 'true' && secrets.TURBO_TOKEN || '' }} | |
| TURBO_TEAM: ${{ steps.plan.outputs.uses_remote_cache == 'true' && secrets.TURBO_TEAM || '' }} | |
| run: ${{ steps.plan.outputs.command }} | |
| e2e: | |
| name: pr-quality / e2e | |
| needs: | |
| - scope | |
| - format | |
| - static | |
| - test | |
| if: always() | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:18 | |
| env: | |
| POSTGRES_DB: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_USER: postgres | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U postgres -d postgres" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| env: | |
| DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/rssift_ci | |
| TEST_DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/rssift_test_ci | |
| INGEST_ON_BOOT: false | |
| steps: | |
| - name: Fail when upstream quality gates did not complete successfully | |
| if: ${{ needs.scope.result != 'success' || needs.format.result != 'success' || needs.static.result != 'success' || needs.test.result != 'success' }} | |
| run: | | |
| echo "Earlier quality gates failed or did not complete successfully; refusing to report a false-success e2e result." | |
| exit 1 | |
| - name: Check out trusted base for planning | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' }} | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.event.pull_request.base.sha }} | |
| fetch-depth: 1 | |
| path: .trusted-base | |
| persist-credentials: false | |
| - name: Set up Node.js | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' }} | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 24.14.1 | |
| - name: Plan e2e command | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' }} | |
| id: plan | |
| run: | | |
| node .trusted-base/.github/scripts/pr-quality-command-plan.mjs \ | |
| --job e2e \ | |
| --docs-only "${{ needs.scope.outputs.docs_only }}" \ | |
| --run-mode "${{ needs.scope.outputs.run_mode }}" \ | |
| --can-use-remote-cache "${{ needs.scope.outputs.can_use_remote_cache }}" \ | |
| --github-output "$GITHUB_OUTPUT" | |
| - name: Check out repository | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up pnpm | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: pnpm/action-setup@v5 | |
| with: | |
| version: 10.33.0 | |
| - name: Set up cached Node.js | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 24.14.1 | |
| cache: pnpm | |
| - name: Install dependencies | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| run: pnpm install --frozen-lockfile | |
| - name: Provision PostgreSQL 18 e2e databases | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| run: pnpm --filter api exec node scripts/provision-ci-dbs.mjs | |
| - name: Install Playwright browsers | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| run: pnpm --filter web exec playwright install --with-deps chromium | |
| - name: Docs-only no-op | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' && steps.plan.outputs.should_run != 'true' }} | |
| run: | | |
| echo "Docs-only PR: e2e gate intentionally no-op." | |
| - name: Run e2e gate | |
| if: ${{ needs.scope.result == 'success' && needs.format.result == 'success' && needs.static.result == 'success' && needs.test.result == 'success' && steps.plan.outputs.should_run == 'true' }} | |
| env: | |
| TURBO_TOKEN: ${{ steps.plan.outputs.uses_remote_cache == 'true' && secrets.TURBO_TOKEN || '' }} | |
| TURBO_TEAM: ${{ steps.plan.outputs.uses_remote_cache == 'true' && secrets.TURBO_TEAM || '' }} | |
| run: ${{ steps.plan.outputs.command }} |