| ... | ... | @@ -24,32 +24,32 @@ jobs: |
| 24 | 24 | { |
| 25 | 25 | name: "size:XS", |
| 26 | 26 | color: "0e8a16", |
| 27 | | description: "0-9 changed lines (additions + deletions).", |
| 27 | description: "0-9 effective changed lines (test files excluded in mixed PRs).", |
| 28 | 28 | }, |
| 29 | 29 | { |
| 30 | 30 | name: "size:S", |
| 31 | 31 | color: "5ebd3e", |
| 32 | | description: "10-29 changed lines (additions + deletions).", |
| 32 | description: "10-29 effective changed lines (test files excluded in mixed PRs).", |
| 33 | 33 | }, |
| 34 | 34 | { |
| 35 | 35 | name: "size:M", |
| 36 | 36 | color: "fbca04", |
| 37 | | description: "30-99 changed lines (additions + deletions).", |
| 37 | description: "30-99 effective changed lines (test files excluded in mixed PRs).", |
| 38 | 38 | }, |
| 39 | 39 | { |
| 40 | 40 | name: "size:L", |
| 41 | 41 | color: "fe7d37", |
| 42 | | description: "100-499 changed lines (additions + deletions).", |
| 42 | description: "100-499 effective changed lines (test files excluded in mixed PRs).", |
| 43 | 43 | }, |
| 44 | 44 | { |
| 45 | 45 | name: "size:XL", |
| 46 | 46 | color: "d93f0b", |
| 47 | | description: "500-999 changed lines (additions + deletions).", |
| 47 | description: "500-999 effective changed lines (test files excluded in mixed PRs).", |
| 48 | 48 | }, |
| 49 | 49 | { |
| 50 | 50 | name: "size:XXL", |
| 51 | 51 | color: "b60205", |
| 52 | | description: "1,000+ changed lines (additions + deletions).", |
| 52 | description: "1,000+ effective changed lines (test files excluded in mixed PRs).", |
| 53 | 53 | }, |
| 54 | 54 | ]; |
| 55 | 55 | |
| ... | ... | @@ -131,12 +131,18 @@ jobs: |
| 131 | 131 | with: |
| 132 | 132 | script: | |
| 133 | 133 | 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; |
| 137 | 134 | const managedLabels = JSON.parse(process.env.PR_SIZE_LABELS_JSON ?? "[]"); |
| 138 | | |
| 139 | 135 | 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)); |
| 140 | 146 | |
| 141 | 147 | const resolveSizeLabel = (totalChangedLines) => { |
| 142 | 148 | if (totalChangedLines < 10) { |
| ... | ... | @@ -162,6 +168,42 @@ jobs: |
| 162 | 168 | return "size:XXL"; |
| 163 | 169 | }; |
| 164 | 170 | |
| 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; |
| 165 | 207 | const nextLabelName = resolveSizeLabel(changedLines); |
| 166 | 208 | |
| 167 | 209 | const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({ |
| ... | ... | @@ -199,4 +241,15 @@ jobs: |
| 199 | 241 | }); |
| 200 | 242 | } |
| 201 | 243 | |
| 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 | ); |