Skip to content

Commit 3867270

Browse files
authored
Reduce unnecessary CI runtime (vercel#2151)
* Reduce unnecessary CI runtime * Fix shared E2E artifact extraction path * Stabilize getWorkflowPort timeout test on Windows * Preserve UI unit coverage on CI fast path
1 parent 7994629 commit 3867270

5 files changed

Lines changed: 243 additions & 31 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
---
3+
4+
Reduce CI runtime by opting community benchmarks in explicitly, fast-pathing
5+
docs and UI pull requests, and sharing E2E package build artifacts.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: 'Detect CI Scope'
2+
description: 'Classify pull request changes for runtime and validation CI fast paths.'
3+
4+
inputs:
5+
github-token:
6+
description: 'Token used to list changed pull request files.'
7+
required: true
8+
9+
outputs:
10+
runtime-fast-path:
11+
description: 'Whether expensive runtime E2E and benchmark lanes may be skipped.'
12+
value: ${{ steps.scope.outputs.runtime-fast-path }}
13+
validation-fast-path:
14+
description: 'Whether all package validation lanes may be skipped.'
15+
value: ${{ steps.scope.outputs.validation-fast-path }}
16+
17+
runs:
18+
using: 'composite'
19+
steps:
20+
- name: Classify changed files
21+
id: scope
22+
uses: actions/github-script@v7
23+
with:
24+
github-token: ${{ inputs.github-token }}
25+
script: |
26+
if (context.eventName !== 'pull_request') {
27+
core.setOutput('runtime-fast-path', 'false');
28+
core.setOutput('validation-fast-path', 'false');
29+
return;
30+
}
31+
32+
const files = await github.paginate(github.rest.pulls.listFiles, {
33+
owner: context.repo.owner,
34+
repo: context.repo.repo,
35+
pull_number: context.issue.number,
36+
per_page: 100,
37+
});
38+
const validationFastPathPatterns = [
39+
/^\.changeset\/[^/]+\.md$/,
40+
/^docs\//,
41+
/^(AGENTS|CONTRIBUTING|LICENSE|README)\.md$/,
42+
/^packages\/[^/]+\/README\.md$/,
43+
];
44+
const runtimeFastPathPatterns = [
45+
...validationFastPathPatterns,
46+
/^packages\/web\//,
47+
/^packages\/web-shared\//,
48+
];
49+
const changedFiles = files.map((file) => file.filename);
50+
const runtimeFiles = changedFiles.filter(
51+
(filename) =>
52+
!runtimeFastPathPatterns.some((pattern) => pattern.test(filename))
53+
);
54+
const validationFiles = changedFiles.filter(
55+
(filename) =>
56+
!validationFastPathPatterns.some((pattern) => pattern.test(filename))
57+
);
58+
const runtimeFastPath = runtimeFiles.length === 0;
59+
const validationFastPath = validationFiles.length === 0;
60+
61+
core.setOutput('runtime-fast-path', runtimeFastPath ? 'true' : 'false');
62+
core.setOutput('validation-fast-path', validationFastPath ? 'true' : 'false');
63+
core.info(
64+
runtimeFastPath
65+
? 'Only docs or UI files changed; runtime E2E and benchmarks may be skipped.'
66+
: `Runtime CI required by: ${runtimeFiles.join(', ')}`
67+
);
68+
core.info(
69+
validationFastPath
70+
? 'Only inert documentation files changed; package validation may be skipped.'
71+
: `Package validation required by: ${validationFiles.join(', ')}`
72+
);

.github/workflows/benchmarks.yml

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,31 @@ concurrency:
1919
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
2020

2121
jobs:
22+
ci-scope:
23+
name: Detect CI Scope
24+
runs-on: ubuntu-latest
25+
outputs:
26+
fast-path: ${{ steps.scope.outputs.runtime-fast-path }}
27+
steps:
28+
- name: Checkout Repo
29+
uses: actions/checkout@v4
30+
31+
- name: Classify changed files
32+
id: scope
33+
uses: ./.github/actions/detect-ci-scope
34+
with:
35+
github-token: ${{ secrets.GITHUB_TOKEN }}
36+
2237
# Phase 0: Update PR comment to show benchmarks are running
2338
pr-comment-start:
2439
name: Create PR Comment
2540
runs-on: ubuntu-latest
26-
if: github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test')
41+
needs: ci-scope
42+
if: >-
43+
github.event_name == 'pull_request' &&
44+
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
45+
(needs.ci-scope.outputs.fast-path != 'true' ||
46+
contains(github.event.pull_request.labels.*.name, 'community-benchmarks'))
2747
timeout-minutes: 2
2848

2949
steps:
@@ -127,7 +147,12 @@ jobs:
127147
build:
128148
name: Build Packages
129149
runs-on: ubuntu-latest
130-
if: ${{ !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
150+
needs: ci-scope
151+
if: >-
152+
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
153+
(needs.ci-scope.outputs.fast-path != 'true' ||
154+
github.event_name == 'workflow_dispatch' ||
155+
contains(github.event.pull_request.labels.*.name, 'community-benchmarks'))
131156
timeout-minutes: 30
132157
env:
133158
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
@@ -156,8 +181,8 @@ jobs:
156181
benchmark-local:
157182
name: Benchmark Local (${{ matrix.app }})
158183
runs-on: ubuntu-latest
159-
needs: build
160-
if: ${{ !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
184+
needs: [ci-scope, build]
185+
if: ${{ needs.ci-scope.outputs.fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
161186
timeout-minutes: 60
162187
strategy:
163188
fail-fast: false
@@ -239,8 +264,8 @@ jobs:
239264
benchmark-postgres:
240265
name: Benchmark Postgres (${{ matrix.app }})
241266
runs-on: ubuntu-latest
242-
needs: build
243-
if: ${{ !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
267+
needs: [ci-scope, build]
268+
if: ${{ needs.ci-scope.outputs.fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
244269
timeout-minutes: 60
245270
strategy:
246271
fail-fast: false
@@ -343,8 +368,8 @@ jobs:
343368
benchmark-vercel:
344369
name: Benchmark Vercel (${{ matrix.app.name }})
345370
runs-on: ubuntu-latest
346-
needs: build
347-
if: ${{ !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
371+
needs: [ci-scope, build]
372+
if: ${{ needs.ci-scope.outputs.fast-path != 'true' && !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
348373
timeout-minutes: 90
349374
permissions:
350375
id-token: write
@@ -446,7 +471,11 @@ jobs:
446471
getCommunityWorldsMatrix:
447472
name: Get Community Worlds Matrix
448473
runs-on: ubuntu-latest
449-
if: ${{ !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
474+
needs: ci-scope
475+
if: >-
476+
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
477+
(github.event_name == 'workflow_dispatch' ||
478+
contains(github.event.pull_request.labels.*.name, 'community-benchmarks'))
450479
outputs:
451480
matrix: ${{ steps.set-matrix.outputs.matrix }}
452481
steps:
@@ -471,7 +500,10 @@ jobs:
471500
472501
benchmark-community:
473502
name: Benchmark Community World (${{ matrix.world.name }})
474-
if: ${{ !contains(github.event.pull_request.labels.*.name, 'workflow-server-test') }}
503+
if: >-
504+
!contains(github.event.pull_request.labels.*.name, 'workflow-server-test') &&
505+
(github.event_name == 'workflow_dispatch' ||
506+
contains(github.event.pull_request.labels.*.name, 'community-benchmarks'))
475507
needs: [build, getCommunityWorldsMatrix]
476508
strategy:
477509
fail-fast: false
@@ -491,8 +523,12 @@ jobs:
491523
summary:
492524
name: Benchmark Summary
493525
runs-on: ubuntu-latest
494-
needs: [benchmark-local, benchmark-postgres, benchmark-vercel, benchmark-community]
495-
if: always() && !cancelled()
526+
needs: [ci-scope, benchmark-local, benchmark-postgres, benchmark-vercel, benchmark-community]
527+
if: >-
528+
always() && !cancelled() &&
529+
(needs.ci-scope.outputs.fast-path != 'true' ||
530+
github.event_name == 'workflow_dispatch' ||
531+
contains(github.event.pull_request.labels.*.name, 'community-benchmarks'))
496532
timeout-minutes: 10
497533

498534
steps:

0 commit comments

Comments
 (0)