perf(ci): cache test results for unchanged app source

Add check-app-changes job (runs parallel with gate-2-start after Gate 1)
that git-diffs the push range to detect whether test-relevant paths changed:

  e2e_changed:  frontends/ + e2e/ + packages/ + components/
  unit_changed: frontends/nextjs/src/

test-unit and test-e2e both gain a cache-restore step:
  - Finds the last successful run on the same branch via gh CLI
  - Downloads coverage-report / playwright-report artifact from that run
  - Sets hit=true if download succeeded
  - All heavy steps (npm install, build, browsers, test run) are gated on
    hit != 'true', so the job completes in seconds on cache hit

Fallback: if no prior successful run exists (hit=false), tests run
normally. New branches and manual dispatches always run (no before SHA).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 22:42:36 +00:00
parent 57be5dbc42
commit 2021e568f1

View File

@@ -661,6 +661,43 @@ jobs:
# GATE 2: Testing Gates (runs after container images are published to GHCR)
# ============================================================================
# Detect which test suites need to run based on changed paths
check-app-changes:
name: "Check: App source changes"
runs-on: ubuntu-latest
needs: gate-1-complete
if: github.event_name != 'issues' && github.event_name != 'issue_comment'
outputs:
e2e_changed: ${{ steps.diff.outputs.e2e_changed }}
unit_changed: ${{ steps.diff.outputs.unit_changed }}
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Detect changed paths
id: diff
shell: bash
run: |
BEFORE="${{ github.event.before }}"
if [ -z "$BEFORE" ] || [ "$BEFORE" = "0000000000000000000000000000000000000000" ]; then
echo "e2e_changed=true" >> "$GITHUB_OUTPUT"
echo "unit_changed=true" >> "$GITHUB_OUTPUT"
echo "No before SHA — marking all changed"
exit 0
fi
git fetch --depth=1 origin "$BEFORE" 2>/dev/null || true
E2E=$(git diff --name-only "$BEFORE" "${{ github.sha }}" -- \
frontends e2e packages components 2>/dev/null || echo "")
UNIT=$(git diff --name-only "$BEFORE" "${{ github.sha }}" -- \
frontends/nextjs/src 2>/dev/null || echo "")
[ -n "$E2E" ] && echo "e2e_changed=true" >> "$GITHUB_OUTPUT" || echo "e2e_changed=false" >> "$GITHUB_OUTPUT"
[ -n "$UNIT" ] && echo "unit_changed=true" >> "$GITHUB_OUTPUT" || echo "unit_changed=false" >> "$GITHUB_OUTPUT"
echo "E2E paths changed: ${E2E:-none}"
echo "Unit paths changed: ${UNIT:-none}"
gate-2-start:
name: "Gate 2: Testing - Starting"
runs-on: ubuntu-latest
@@ -688,18 +725,46 @@ jobs:
test-unit:
name: "Gate 2.1: Unit Tests"
runs-on: ubuntu-latest
needs: gate-2-start
needs: [gate-2-start, check-app-changes]
if: ${{ !inputs.skip_tests }}
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Restore cached coverage report
id: cache-restore
if: needs.check-app-changes.outputs.unit_changed == 'false'
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
LAST_RUN=$(gh run list \
--repo "${{ github.repository }}" \
--workflow gated-pipeline.yml \
--branch "${{ github.ref_name }}" \
--status success \
--limit 1 \
--json databaseId \
--jq '.[0].databaseId' 2>/dev/null || echo "")
if [ -n "$LAST_RUN" ] && [ "$LAST_RUN" != "null" ]; then
gh run download "$LAST_RUN" \
--repo "${{ github.repository }}" \
--name coverage-report \
--dir frontends/nextjs/coverage/ 2>/dev/null \
&& echo "hit=true" >> "$GITHUB_OUTPUT" \
|| echo "hit=false" >> "$GITHUB_OUTPUT"
else
echo "hit=false" >> "$GITHUB_OUTPUT"
fi
- name: Setup npm with Nexus
if: steps.cache-restore.outputs.hit != 'true'
uses: ./.github/actions/setup-npm
with:
node-version: '20'
- name: Run unit tests with coverage
if: steps.cache-restore.outputs.hit != 'true'
run: |
set -o pipefail
cd frontends/nextjs
@@ -760,13 +825,41 @@ jobs:
test-e2e:
name: "Gate 2.2: E2E Tests"
runs-on: ubuntu-latest
needs: gate-2-start
needs: [gate-2-start, check-app-changes]
if: ${{ !inputs.skip_tests }}
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Restore cached test results
id: cache-restore
if: needs.check-app-changes.outputs.e2e_changed == 'false'
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
LAST_RUN=$(gh run list \
--repo "${{ github.repository }}" \
--workflow gated-pipeline.yml \
--branch "${{ github.ref_name }}" \
--status success \
--limit 1 \
--json databaseId \
--jq '.[0].databaseId' 2>/dev/null || echo "")
if [ -n "$LAST_RUN" ] && [ "$LAST_RUN" != "null" ]; then
gh run download "$LAST_RUN" \
--repo "${{ github.repository }}" \
--name playwright-report \
--dir playwright-report/ 2>/dev/null \
&& echo "hit=true" >> "$GITHUB_OUTPUT" \
|| echo "hit=false" >> "$GITHUB_OUTPUT"
echo "Using cached results from run $LAST_RUN"
else
echo "hit=false" >> "$GITHUB_OUTPUT"
fi
- name: Log in to GitHub Container Registry
if: steps.cache-restore.outputs.hit != 'true'
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
@@ -774,17 +867,21 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Setup npm with Nexus
if: steps.cache-restore.outputs.hit != 'true'
uses: ./.github/actions/setup-npm
with:
node-version: '20'
- name: Build workspace packages
if: steps.cache-restore.outputs.hit != 'true'
run: npm run build --workspaces --if-present 2>&1
- name: Install Playwright Browsers
if: steps.cache-restore.outputs.hit != 'true'
run: npx playwright install --with-deps chromium
- name: Run Playwright tests
if: steps.cache-restore.outputs.hit != 'true'
run: |
if [ -f e2e/playwright.config.ts ]; then
npx playwright test --config=e2e/playwright.config.ts 2>&1