Skip to content

Commit c5dadc2

Browse files
authored
Add 'changed-files-labels-limit' and 'max-files-changed' configs to allow capping number of labels added (#923)
* README.md: drop trailing whitespace * Add 'changed-files-labels-limit' config to allow capping number of labels added When a repository has many components, each with a changed-files label, a large refactor ends up with the labeler spamming the pull request with label changes. The end result is not very useful as it's not very readable, and due to how github automatically hides comments when label changes overflow the discussion tab, it means useful information is hidden and one has to manually click "Load more..." dozens of time every time the page is loaded. Add a changed-files-labels-limit top level config knob. If more than the configured limit of labels is set to be added, none are added. This only affects changed-files labels. * Add 'max-files-changed' config to allow capping number of files for labelling When a PR modifies a very large number of files (e.g., tree-wide refactors, automated code formatting), this new options allows skipping file-based labeling entirely when the number of files that are changed hits the configured limit. Fixes #486
1 parent e52e4fb commit c5dadc2

14 files changed

Lines changed: 1129 additions & 25 deletions

README.md

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ The match object allows control over the matching options. You can specify the l
3737

3838
The base match object is defined as:
3939
```yml
40-
- changed-files:
40+
- changed-files:
4141
- any-glob-to-any-file: ['list', 'of', 'globs']
4242
- any-glob-to-all-files: ['list', 'of', 'globs']
4343
- all-globs-to-any-file: ['list', 'of', 'globs']
@@ -132,7 +132,7 @@ Documentation:
132132
- changed-files:
133133
- any-glob-to-any-file: ['docs/*', 'guides/*']
134134
135-
# Add 'Documentation' label to any change to .md files within the entire repository
135+
# Add 'Documentation' label to any change to .md files within the entire repository
136136
Documentation:
137137
- changed-files:
138138
- any-glob-to-any-file: '**/*.md'
@@ -153,6 +153,96 @@ release:
153153
- base-branch: 'main'
154154
```
155155
156+
#### Configuration Options
157+
158+
The labeler configuration file (`.github/labeler.yml`) supports the following top-level options:
159+
160+
| Name | Description |
161+
|------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
162+
| `changed-files-labels-limit` | Maximum number of new labels to apply based on changed files (must be a non-negative integer). If exceeded, no changed-files labels are applied for that run. |
163+
| `max-files-changed` | Maximum number of total changed files (must be a non-negative integer). If exceeded, all file-based labeling is skipped. |
164+
165+
##### Limiting changed-files labels
166+
167+
When working with large PRs (e.g., tree-wide refactors) that touch many components, you may want to prevent the labeler from adding too many labels. Set `changed-files-labels-limit` in your `.github/labeler.yml` configuration file to limit the number of labels that can be applied based on changed files patterns.
168+
169+
**Important behaviors:**
170+
171+
- The limit counts only **new** labels that would be added by changed-files rules. Labels already present on the PR are not counted toward the limit.
172+
- If the number of new changed-files labels **exceeds** the limit, **all** new changed-files labels are skipped for that run.
173+
- If the number of new changed-files labels **equals** the limit, labels are still applied normally.
174+
- Labels based on branch conditions (`head-branch`, `base-branch`) are **not affected** by the limit.
175+
- **Any label definition that includes a `changed-files` rule is considered a changed-files label** and is subject to the limit, regardless of which condition caused the label to match. For example, a label with both `head-branch` and `changed-files` rules will be subject to the limit even if it matches via the branch rule.
176+
- If both `max-files-changed` and `changed-files-labels-limit` are configured at the same time, `max-files-changed` is evaluated first, and if it triggers, `changed-files-labels-limit` is not evaluated.
177+
178+
##### Example
179+
180+
```yml
181+
# .github/labeler.yml
182+
183+
# Limit changed-files based labels to 5
184+
changed-files-labels-limit: 5
185+
186+
# Label definitions - these are subject to the limit
187+
frontend:
188+
- changed-files:
189+
- any-glob-to-any-file: 'src/frontend/**'
190+
191+
backend:
192+
- changed-files:
193+
- any-glob-to-any-file: 'src/backend/**'
194+
195+
docs:
196+
- changed-files:
197+
- any-glob-to-any-file: 'docs/**'
198+
199+
# This label has both branch and changed-files rules.
200+
# It is still subject to the limit because it includes changed-files.
201+
mixed:
202+
- any:
203+
- head-branch: '^feature/'
204+
- changed-files:
205+
- any-glob-to-any-file: 'src/mixed/**'
206+
207+
# Branch-based labels are NOT affected by the limit
208+
feature:
209+
- head-branch: '^feature/'
210+
```
211+
212+
##### Skipping labeling for large PRs
213+
214+
When a PR modifies a very large number of files (e.g., tree-wide refactors, automated code formatting), you may want to skip file-based labeling entirely. Set `max-files-changed` in your `.github/labeler.yml` configuration file to skip all file-based labeling when the total number of changed files exceeds the threshold.
215+
216+
**Important behaviors:**
217+
218+
- If the total number of changed files **exceeds** the limit, all file-based labeling is skipped entirely.
219+
- If the total number of changed files **equals** the limit, labels are still applied normally.
220+
- Labels based **only** on branch conditions (`head-branch`, `base-branch`) are **not affected** by the limit.
221+
- **Any label definition that includes a `changed-files` rule is considered a file-based label** and will be skipped, regardless of which condition caused the label to match. For example, a label with both `head-branch` and `changed-files` rules will be skipped even if it would match via the branch rule.
222+
- Pre-existing labels on the PR are **preserved** — changed-files configs are not evaluated at all, so `sync-labels` will not remove them.
223+
224+
##### Example
225+
226+
```yml
227+
# .github/labeler.yml
228+
229+
# Skip file-based labeling if more than 100 files changed
230+
max-files-changed: 100
231+
232+
# These labels will be skipped if > 100 files changed
233+
frontend:
234+
- changed-files:
235+
- any-glob-to-any-file: 'src/frontend/**'
236+
237+
backend:
238+
- changed-files:
239+
- any-glob-to-any-file: 'src/backend/**'
240+
241+
# Branch-based labels are NOT affected
242+
release:
243+
- base-branch: 'main'
244+
```
245+
156246
### Create Workflow
157247

158248
Create a workflow (e.g. `.github/workflows/labeler.yml` see [Creating a Workflow file](https://docs.github.com/en/actions/writing-workflows/quickstart#creating-your-first-workflow)) to utilize the labeler action with content:
@@ -213,10 +303,10 @@ jobs:
213303
pull-requests: write
214304
runs-on: ubuntu-latest
215305
steps:
216-
306+
217307
# Label PRs 1, 2, and 3
218308
- uses: actions/labeler@v6
219-
with:
309+
with:
220310
pr-number: |
221311
1
222312
2
@@ -225,9 +315,9 @@ jobs:
225315

226316
**Note:** in normal usage the `pr-number` input is not required as the action will detect the PR number from the workflow context.
227317

228-
#### Outputs
318+
#### Outputs
229319

230-
Labeler provides the following outputs:
320+
Labeler provides the following outputs:
231321

232322
| Name | Description |
233323
|--------------|-----------------------------------------------------------|
@@ -249,13 +339,13 @@ jobs:
249339
steps:
250340
- id: label-the-PR
251341
uses: actions/labeler@v6
252-
342+
253343
- id: run-frontend-tests
254344
if: contains(steps.label-the-PR.outputs.all-labels, 'frontend')
255345
run: |
256346
echo "Running frontend tests..."
257347
# Put your commands for running frontend tests here
258-
348+
259349
- id: run-backend-tests
260350
if: contains(steps.label-the-PR.outputs.all-labels, 'backend')
261351
run: |
@@ -291,7 +381,7 @@ To ensure the action works correctly, include the following permissions in your
291381
issues: write
292382
```
293383

294-
### Manual Label Creation as an Alternative to Granting issues write Permission
384+
### Manual Label Creation as an Alternative to Granting issues write Permission
295385

296386
If you prefer not to grant the `issues: write` permission in your workflow, you can manually create all required labels in the repository before the action runs.
297387

__tests__/fixtures/limit_0.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Limit to 0 changed-files labels (none allowed)
2+
changed-files-labels-limit: 0
3+
4+
# Labels based on changed files
5+
component-a:
6+
- changed-files:
7+
- any-glob-to-any-file: ['components/a/**']
8+
9+
component-b:
10+
- changed-files:
11+
- any-glob-to-any-file: ['components/b/**']
12+
13+
# Labels based on branch patterns only
14+
test-branch:
15+
- head-branch: '^test/'
16+
17+
feature-branch:
18+
- head-branch: '/feature/'

__tests__/fixtures/limit_1.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Limit to 1 changed-files label
2+
changed-files-labels-limit: 1
3+
4+
# Labels based on changed files
5+
component-a:
6+
- changed-files:
7+
- any-glob-to-any-file: ['components/a/**']
8+
9+
component-b:
10+
- changed-files:
11+
- any-glob-to-any-file: ['components/b/**']
12+
13+
component-c:
14+
- changed-files:
15+
- any-glob-to-any-file: ['components/c/**']
16+
17+
component-d:
18+
- changed-files:
19+
- any-glob-to-any-file: ['components/d/**']
20+
21+
# Labels based on branch patterns only
22+
test-branch:
23+
- head-branch: '^test/'
24+
25+
feature-branch:
26+
- head-branch: '/feature/'

__tests__/fixtures/limit_2.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Limit to 2 changed-files labels
2+
changed-files-labels-limit: 2
3+
4+
# Labels based on changed files
5+
component-a:
6+
- changed-files:
7+
- any-glob-to-any-file: ['components/a/**']
8+
9+
component-b:
10+
- changed-files:
11+
- any-glob-to-any-file: ['components/b/**']
12+
13+
component-c:
14+
- changed-files:
15+
- any-glob-to-any-file: ['components/c/**']
16+
17+
component-d:
18+
- changed-files:
19+
- any-glob-to-any-file: ['components/d/**']
20+
21+
# Labels based on branch patterns only
22+
test-branch:
23+
- head-branch: '^test/'
24+
25+
feature-branch:
26+
- head-branch: '/feature/'

__tests__/fixtures/limit_3.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Limit to 3 changed-files labels
2+
changed-files-labels-limit: 3
3+
4+
# Labels based on changed files
5+
component-a:
6+
- changed-files:
7+
- any-glob-to-any-file: ['components/a/**']
8+
9+
component-b:
10+
- changed-files:
11+
- any-glob-to-any-file: ['components/b/**']
12+
13+
component-c:
14+
- changed-files:
15+
- any-glob-to-any-file: ['components/c/**']
16+
17+
component-d:
18+
- changed-files:
19+
- any-glob-to-any-file: ['components/d/**']
20+
21+
# Labels based on branch patterns only
22+
test-branch:
23+
- head-branch: '^test/'
24+
25+
feature-branch:
26+
- head-branch: '/feature/'

__tests__/fixtures/max_files_5.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Skip file-based labeling if more than 5 files changed
2+
max-files-changed: 5
3+
4+
# Labels based on changed files
5+
component-a:
6+
- changed-files:
7+
- any-glob-to-any-file: ['components/a/**']
8+
9+
component-b:
10+
- changed-files:
11+
- any-glob-to-any-file: ['components/b/**']
12+
13+
component-c:
14+
- changed-files:
15+
- any-glob-to-any-file: ['components/c/**']
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Skip file-based labeling if more than 3 files changed
2+
max-files-changed: 3
3+
4+
# Labels based on changed files
5+
component-a:
6+
- changed-files:
7+
- any-glob-to-any-file: ['components/a/**']
8+
9+
component-b:
10+
- changed-files:
11+
- any-glob-to-any-file: ['components/b/**']
12+
13+
# Branch-based label (should not be affected)
14+
test-branch:
15+
- head-branch: ['^test/']
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Labels based on changed files
2+
component-a:
3+
- changed-files:
4+
- any-glob-to-any-file: ['components/a/**']
5+
6+
component-b:
7+
- changed-files:
8+
- any-glob-to-any-file: ['components/b/**']
9+
10+
component-c:
11+
- changed-files:
12+
- any-glob-to-any-file: ['components/c/**']
13+
14+
component-d:
15+
- changed-files:
16+
- any-glob-to-any-file: ['components/d/**']
17+
18+
# Labels based on branch patterns only
19+
test-branch:
20+
- head-branch: '^test/'
21+
22+
feature-branch:
23+
- head-branch: '/feature/'

__tests__/fixtures/mixed_rules.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Test fixture for mixed rules behavior
2+
# A label with both branch and changed-files rules is considered a "changed-files label"
3+
# and is subject to the limit, even if it matches via the branch rule
4+
changed-files-labels-limit: 0
5+
6+
# This label has both branch and changed-files rules
7+
# It should be subject to the limit even if matched via branch
8+
mixed-label:
9+
- any:
10+
- head-branch: '^test/'
11+
- changed-files:
12+
- any-glob-to-any-file: ['components/a/**']
13+
14+
# Pure branch-based label - not subject to limit
15+
pure-branch-label:
16+
- head-branch: '^test/'

0 commit comments

Comments
 (0)