mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
perf(ci): skip unit coverage on PRs that cannot reach it and persist the Jest cache (#1711)
Pull requests whose changes cannot reach any Tier A test (allowlist checked against declared Tier A inputs and an AST scan of cross-project reads) skip the unit coverage suite; master pushes always run it. Jest's transform cache is persisted with actions/cache: PRs restore only, master pushes start empty and save. Paired CI runs: Tier A 9m04s cold -> 6m09s warm. Nx Cloud is intentionally not used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
34d393adc8
commit
e8902f472a
9 files changed
+648
-3
No files matched your search
@@ -209,6 +209,10 @@ jobs:
|
||||
name: Unit Tests and Typechecks
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
contents: read
|
||||
# The scope step lists the PR's changed files through the API.
|
||||
pull-requests: read
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -247,11 +251,75 @@ jobs:
|
||||
- name: Check i18n drift
|
||||
run: pnpm run i18n:check
|
||||
|
||||
# A pull request whose changes cannot reach any Tier A test (docs,
|
||||
# notes, other workflows, website, E2E and mock-server apps, release
|
||||
# and packaging tooling, a scripts-only package.json edit) skips the
|
||||
# suite. The allowlist lives in a unit-tested script; anything it
|
||||
# does not know runs everything, and master always runs everything.
|
||||
- name: Decide unit coverage scope
|
||||
id: scope
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
CHANGED_FILES: ${{ github.event.pull_request.changed_files }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ "$EVENT_NAME" != "pull_request" ]; then
|
||||
echo "Not a pull request; running the full suite."
|
||||
echo "run=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
# The list-files endpoint stops at 3,000 files; a truncated
|
||||
# list could hide a file that needs the suite.
|
||||
if [ "${CHANGED_FILES:-0}" -ge 3000 ]; then
|
||||
echo "PR changes ${CHANGED_FILES} files, beyond the API listing limit; running the full suite."
|
||||
echo "run=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
git fetch --no-tags --depth=1 origin "$BASE_SHA"
|
||||
gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/files?per_page=100" \
|
||||
--paginate --jq '.[] | .filename, (.previous_filename // empty)' |
|
||||
node tools/coverage/unit-coverage-scope.mjs --base FETCH_HEAD --github-output
|
||||
|
||||
# Jest's transform cache (TypeScript/Angular transpilation plus
|
||||
# coverage instrumentation, keyed by file content) is persisted
|
||||
# between runs. Only master pushes and maintainer dispatches save
|
||||
# it; pull requests restore it and never write, so a PR cannot plant
|
||||
# an entry that a later master run would read.
|
||||
- name: Restore Jest transform cache
|
||||
if: steps.scope.outputs.run == 'true' && github.event_name != 'push'
|
||||
uses: actions/cache/restore@v6
|
||||
with:
|
||||
path: ${{ runner.temp }}/jest-cache
|
||||
key: jest-transform-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'tsconfig.base.json', 'jest.preset.js', 'jest.web-esm.workspace.ts', 'apps/web/jest.config.ts') }}-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
jest-transform-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'tsconfig.base.json', 'jest.preset.js', 'jest.web-esm.workspace.ts', 'apps/web/jest.config.ts') }}-
|
||||
|
||||
- name: Run Tier A unit coverage suite
|
||||
if: steps.scope.outputs.run == 'true'
|
||||
run: pnpm run coverage:ci
|
||||
env:
|
||||
CI: true
|
||||
NX_TASKS_RUNNER_DYNAMIC_OUTPUT: false
|
||||
JEST_CACHE_DIRECTORY: ${{ runner.temp }}/jest-cache
|
||||
|
||||
- name: Validate coverage tooling (suite skipped)
|
||||
if: steps.scope.outputs.run != 'true'
|
||||
run: pnpm run coverage:tools:test && pnpm run coverage:policy:check
|
||||
|
||||
# Master pushes start from an empty cache, so the saved cache holds
|
||||
# exactly the current tree and does not grow run over run.
|
||||
- name: Save Jest transform cache
|
||||
if: >-
|
||||
steps.scope.outputs.run == 'true' &&
|
||||
(github.event_name == 'workflow_dispatch' ||
|
||||
(github.event_name == 'push' && github.ref == 'refs/heads/master'))
|
||||
uses: actions/cache/save@v6
|
||||
with:
|
||||
path: ${{ runner.temp }}/jest-cache
|
||||
key: jest-transform-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'tsconfig.base.json', 'jest.preset.js', 'jest.web-esm.workspace.ts', 'apps/web/jest.config.ts') }}-${{ github.run_id }}
|
||||
|
||||
- name: Run Tier B/C validation commands
|
||||
run: node tools/coverage/check-coverage-policy.mjs --run-non-tier-a
|
||||
@@ -260,7 +328,7 @@ jobs:
|
||||
NX_TASKS_RUNNER_DYNAMIC_OUTPUT: false
|
||||
|
||||
- name: Upload unit coverage artifact
|
||||
if: always()
|
||||
if: always() && steps.scope.outputs.run == 'true'
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: unit-coverage
|
||||
@@ -269,7 +337,7 @@ jobs:
|
||||
retention-days: 14
|
||||
|
||||
- name: Upload unit coverage to Codecov
|
||||
if: always()
|
||||
if: always() && steps.scope.outputs.run == 'true'
|
||||
uses: codecov/codecov-action@v7
|
||||
with:
|
||||
files: ./coverage/merged/lcov.info,./coverage/merged/cobertura-coverage.xml
|
||||
|
||||
Reference in new issue
Block a user