authorgravatar for crazywolf132@gmail.com0x1f99d <crazywolf132@gmail.com> 2026-03-24 14:16:13+11:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-03-23 20:16:13-07:00
loge823f8f14ecb99c92345dbd72ba82b836858ba09
treecb4a51b4e7f1afa64773b461aca4369f761ad701
parent2b08d8669646109ffa101b1b767f4c1922d2e072
signature Signed by PGP key B5690EEEBB952194

ci(github): exclude test files from mixed PR size calculation (#1105)


1 files changed, 64 insertions(+), 11 deletions(-)

.github/workflows/pr-size.yml+64-11
......@@ -24,32 +24,32 @@ jobs:
2424 {
2525 name: "size:XS",
2626 color: "0e8a16",
27 description: "0-9 changed lines (additions + deletions).",
27 description: "0-9 effective changed lines (test files excluded in mixed PRs).",
2828 },
2929 {
3030 name: "size:S",
3131 color: "5ebd3e",
32 description: "10-29 changed lines (additions + deletions).",
32 description: "10-29 effective changed lines (test files excluded in mixed PRs).",
3333 },
3434 {
3535 name: "size:M",
3636 color: "fbca04",
37 description: "30-99 changed lines (additions + deletions).",
37 description: "30-99 effective changed lines (test files excluded in mixed PRs).",
3838 },
3939 {
4040 name: "size:L",
4141 color: "fe7d37",
42 description: "100-499 changed lines (additions + deletions).",
42 description: "100-499 effective changed lines (test files excluded in mixed PRs).",
4343 },
4444 {
4545 name: "size:XL",
4646 color: "d93f0b",
47 description: "500-999 changed lines (additions + deletions).",
47 description: "500-999 effective changed lines (test files excluded in mixed PRs).",
4848 },
4949 {
5050 name: "size:XXL",
5151 color: "b60205",
52 description: "1,000+ changed lines (additions + deletions).",
52 description: "1,000+ effective changed lines (test files excluded in mixed PRs).",
5353 },
5454 ];
5555
......@@ -131,12 +131,18 @@ jobs:
131131 with:
132132 script: |
133133 const issueNumber = context.payload.pull_request.number;
134 const additions = context.payload.pull_request.additions ?? 0;
135 const deletions = context.payload.pull_request.deletions ?? 0;
136 const changedLines = additions + deletions;
137134 const managedLabels = JSON.parse(process.env.PR_SIZE_LABELS_JSON ?? "[]");
138
139135 const managedLabelNames = new Set(managedLabels.map((label) => label.name));
136 // Keep this aligned with the repo's test entrypoints and test-only support files.
137 const testFilePatterns = [
138 /(^|\/)__tests__(\/|$)/,
139 /(^|\/)tests?(\/|$)/,
140 /^apps\/server\/integration\//,
141 /\.(test|spec|browser|integration)\.[^.\/]+$/,
142 ];
143
144 const isTestFile = (filename) =>
145 testFilePatterns.some((pattern) => pattern.test(filename));
140146
141147 const resolveSizeLabel = (totalChangedLines) => {
142148 if (totalChangedLines < 10) {
......@@ -162,6 +168,42 @@ jobs:
162168 return "size:XXL";
163169 };
164170
171 const files = await github.paginate(
172 github.rest.pulls.listFiles,
173 {
174 owner: context.repo.owner,
175 repo: context.repo.repo,
176 pull_number: issueNumber,
177 per_page: 100,
178 },
179 (response) => response.data,
180 );
181
182 if (files.length >= 3000) {
183 core.warning(
184 "The GitHub pull request files API may truncate results at 3,000 files; PR size may be undercounted.",
185 );
186 }
187
188 let testChangedLines = 0;
189 let nonTestChangedLines = 0;
190
191 for (const file of files) {
192 const changedLinesForFile = (file.additions ?? 0) + (file.deletions ?? 0);
193
194 if (changedLinesForFile === 0) {
195 continue;
196 }
197
198 if (isTestFile(file.filename)) {
199 testChangedLines += changedLinesForFile;
200 continue;
201 }
202
203 nonTestChangedLines += changedLinesForFile;
204 }
205
206 const changedLines = nonTestChangedLines === 0 ? testChangedLines : nonTestChangedLines;
165207 const nextLabelName = resolveSizeLabel(changedLines);
166208
167209 const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
......@@ -199,4 +241,15 @@ jobs:
199241 });
200242 }
201243
202 core.info(`PR #${issueNumber}: ${changedLines} changed lines -> ${nextLabelName}`);
244 const classification =
245 nonTestChangedLines === 0
246 ? testChangedLines > 0
247 ? "test-only PR"
248 : "no line changes"
249 : testChangedLines > 0
250 ? "test lines excluded"
251 : "all non-test changes";
252
253 core.info(
254 `PR #${issueNumber}: ${nonTestChangedLines} non-test lines, ${testChangedLines} test lines, ${changedLines} effective lines -> ${nextLabelName} (${classification})`,
255 );