Skip to content

Commit 928199e

Browse files
committed
feat: expose fields via yaml "Full" config
1 parent ef6c69b commit 928199e

File tree

7 files changed

+190
-4
lines changed

7 files changed

+190
-4
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ Usage:
1313
Flags:
1414
--config-path string A custom config path, relative to the repository root
1515
--data string A JSON string of the 'event' type (issue event or pull request event)
16+
--fields strings Fields to evaluate for labeling (title, body) (default [title,body])
1617
-h, --help help for labeler
1718
--id int The integer id of the issue or pull request
1819
-o, --owner string GitHub Owner/Org name [GITHUB_ACTOR]
1920
-r, --repo string GitHub Repo name [GITHUB_REPO]
2021
-t, --type string The target event type to label (issues or pull_request) [GITHUB_EVENT_NAME]
2122
-v, --version version for labeler
23+
2224
```
2325

2426
Example usage:
@@ -70,6 +72,8 @@ labels:
7072
- '\bquestion\b'
7173
```
7274
75+
Note that simple schema doesn't allow for some of the more advanced features of the full schema, such as excluding patterns or customizing comments for issues and pull requests. If you need those features, consider using the full schema.
76+
7377
### Full Schema
7478
7579
```yaml
@@ -81,6 +85,11 @@ enable:
8185
prs: true
8286
# comments object allows you to specify a different message for issues and prs
8387

88+
# (Optional): Determine which fields of the issue or pull request to evaluate.
89+
fields:
90+
- title
91+
- body
92+
8493
comments:
8594
issues: |
8695
Thanks for opening this issue!

labeler.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ func (l *Labeler) applyLabels(i githubEvent, existingLabels []*github.Label) int
205205
flags := l.fieldFlag.OrDefault()
206206
fields := make([]string, 0)
207207

208+
if overrideFields, ok := l.config.(*model.FullConfig); ok && len(overrideFields.Fields) > 0 {
209+
flags = ParseFieldFlags(overrideFields.Fields)
210+
}
211+
208212
if flags.Has(FieldTitle) {
209213
fields = append(fields, i.GetTitle())
210214
}

labeler_test.go

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,6 @@ func TestLabeler_Execute_success_issue(t *testing.T) {
275275
ctx := context.Background()
276276
mockClient := new(mockRichClient)
277277

278-
mockCfg := new(mockConfig)
279278
l := &Labeler{
280279
Owner: ptr("owner"),
281280
Repo: ptr("repo"),
@@ -296,14 +295,106 @@ labels:
296295
- '\bdupe\b'
297296
'question':
298297
- '\bquestion\b'
298+
`))), nil, nil)
299+
mockClient.On("GetIssue", mock.Anything, "owner", "repo", 1).Return(&github.Issue{Title: ptr("title"), Body: ptr("body")}, nil, nil)
300+
err := l.Execute()
301+
assert.NoError(t, err)
302+
303+
mockClient.AssertNumberOfCalls(t, "GetIssue", 1)
304+
mockClient.AssertExpectations(t)
305+
}
306+
307+
func TestLabeler_Execute_allows_config_override_fields_title(t *testing.T) {
308+
ctx := context.Background()
309+
mockClient := new(mockRichClient)
310+
311+
l := &Labeler{
312+
Owner: ptr("owner"),
313+
Repo: ptr("repo"),
314+
Event: ptr("issues"),
315+
ID: ptr(1),
316+
context: &ctx,
317+
client: mockClient,
318+
configPath: ".github/labeler.yml",
319+
fieldFlag: AllFieldFlags,
320+
}
321+
mockClient.On("DownloadContents", mock.Anything, "owner", "repo", ".github/labeler.yml", mock.Anything).
322+
Return(io.NopCloser(bytes.NewReader([]byte(
323+
`%YAML 1.1
324+
---
325+
enable:
326+
issues: true
327+
prs: false
328+
329+
fields:
330+
- title
331+
332+
labels:
333+
'bug':
334+
include:
335+
- '\btitle[s]?\b'
336+
exclude: []
337+
'help wanted':
338+
include:
339+
- '\bbody( me)?\b'
340+
`))), nil, nil)
341+
mockClient.On("GetIssue", mock.Anything, "owner", "repo", 1).Return(&github.Issue{Title: ptr("title"), Body: ptr("body")}, nil, nil)
342+
mockClient.On("AddLabelsToIssue", mock.Anything, "owner", "repo", 1, []string{"bug"}).Return([]*github.Label{{Name: ptr("bug")}}, nil, nil)
343+
err := l.Execute()
344+
assert.NoError(t, err)
345+
346+
mockClient.AssertNumberOfCalls(t, "GetIssue", 1)
347+
mockClient.AssertCalled(t, "AddLabelsToIssue", mock.Anything, "owner", "repo", 1, []string{"bug"})
348+
mockClient.AssertNumberOfCalls(t, "AddLabelsToIssue", 1)
349+
mockClient.AssertExpectations(t)
350+
}
351+
352+
func TestLabeler_Execute_allows_config_override_fields_body(t *testing.T) {
353+
ctx := context.Background()
354+
mockClient := new(mockRichClient)
355+
356+
mockCfg := new(mockConfig)
357+
l := &Labeler{
358+
Owner: ptr("owner"),
359+
Repo: ptr("repo"),
360+
Event: ptr("issues"),
361+
ID: ptr(1),
362+
context: &ctx,
363+
client: mockClient,
364+
configPath: ".github/labeler.yml",
365+
fieldFlag: AllFieldFlags,
366+
}
367+
mockClient.On("DownloadContents", mock.Anything, "owner", "repo", ".github/labeler.yml", mock.Anything).
368+
Return(io.NopCloser(bytes.NewReader([]byte(
369+
`%YAML 1.1
370+
---
371+
enable:
372+
issues: true
373+
prs: false
374+
375+
fields:
376+
- body
377+
378+
labels:
379+
'bug':
380+
include:
381+
- '\btitle[s]?\b'
382+
exclude: []
383+
'help wanted':
384+
include:
385+
- '\bbody\b'
386+
299387
`))), nil, nil)
300388
mockCfg.On("FromBytes", mock.Anything).Return(nil)
301-
mockCfg.On("LabelsFor", mock.Anything, mock.Anything).Return(map[string]model.Label{})
302-
mockClient.On("GetIssue", mock.Anything, "owner", "repo", 1).Return(&github.Issue{Title: ptr("t"), Body: ptr("b")}, nil, nil)
389+
mockCfg.On("LabelsFor", "body").Return(map[string]model.Label{})
390+
mockClient.On("GetIssue", mock.Anything, "owner", "repo", 1).Return(&github.Issue{Title: ptr("title"), Body: ptr("body")}, nil, nil)
391+
mockClient.On("AddLabelsToIssue", mock.Anything, "owner", "repo", 1, []string{"help wanted"}).Return([]*github.Label{{Name: ptr("help wanted")}}, nil, nil)
303392
err := l.Execute()
304393
assert.NoError(t, err)
305394

306395
mockClient.AssertNumberOfCalls(t, "GetIssue", 1)
396+
mockClient.AssertCalled(t, "AddLabelsToIssue", mock.Anything, "owner", "repo", 1, []string{"help wanted"})
397+
mockClient.AssertNumberOfCalls(t, "AddLabelsToIssue", 1)
307398
mockClient.AssertExpectations(t)
308399
}
309400

model/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@ type Config interface {
88
// LabelsFor allows config implementations to determine the labels to be applied to the input strings
99
LabelsFor(text ...string) map[string]Label
1010
}
11+
12+
type FieldOverrides interface {
13+
// IncludedFields returns the fields that are used for labeling, if not defined, it returns an empty slice
14+
IncludedFields() []string
15+
}

model/full_config.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type (
3333
Enable *Enable `yaml:"enable,omitempty"`
3434
Comments *Comments `yaml:"comments,omitempty"`
3535
Labels map[string]Label `yaml:"labels,flow"`
36+
Fields []string `yaml:"fields,omitempty,flow"`
3637
}
3738
)
3839

@@ -50,6 +51,18 @@ func (f *FullConfig) FromBytes(b []byte) error {
5051
return nil
5152
}
5253

54+
// IncludedFields returns the fields that are used for labeling, if not defined, it returns an empty slice
55+
func (f *FullConfig) IncludedFields() []string {
56+
fields := make([]string, 0)
57+
if f.Fields == nil || len(f.Fields) == 0 {
58+
return fields
59+
}
60+
for _, field := range f.Fields {
61+
fields = append(fields, strings.ToLower(field))
62+
}
63+
return fields
64+
}
65+
5366
// LabelsFor allows config implementations to determine the labels to be applied to the input strings
5467
func (f *FullConfig) LabelsFor(text ...string) map[string]Label {
5568
searchable := []byte(strings.Join(text, " "))

model/full_config_test.go

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ func TestFullConfig_FromBytes(t *testing.T) {
1414
Enable *Enable
1515
Comments *Comments
1616
Labels map[string]Label
17+
Fields []string
1718
}
1819
type args struct {
1920
b []byte
@@ -48,7 +49,36 @@ func TestFullConfig_FromBytes(t *testing.T) {
4849
}.Ptr(),
4950
},
5051
args{helperTestData(t, "full_config.yaml")},
51-
false},
52+
false,
53+
},
54+
55+
{"full config title only",
56+
fields{
57+
Labels: map[string]Label{
58+
"bug": {
59+
Include: []string{"\\bbug[s]?\\b"},
60+
Exclude: []string{},
61+
Branches: []string{"main", "develop"},
62+
},
63+
"enhancement": {
64+
Include: []string{"\\bfeat\\b"},
65+
Exclude: []string{},
66+
},
67+
"help wanted": {
68+
Include: []string{"\\bhelp( me)?\\b"},
69+
Exclude: []string{"\\b\\[test(ing)?\\]\\b"},
70+
},
71+
},
72+
Enable: Enable{Issues: &btrue, PullRequests: &bfalse}.Ptr(),
73+
Comments: Comments{
74+
Issues: p("👍 Thanks for this!"),
75+
PullRequests: p("I applied labels to your pull request.\n\nPlease review the labels.\n"),
76+
}.Ptr(),
77+
Fields: []string{"title"},
78+
},
79+
args{helperTestData(t, "full_config_title_only.yaml")},
80+
false,
81+
},
5282
{"full config labels only",
5383
fields{
5484
Labels: map[string]Label{
@@ -88,6 +118,7 @@ func TestFullConfig_FromBytes(t *testing.T) {
88118
assert.Equal(t, tt.fields.Enable, f.Enable)
89119
assert.Equal(t, tt.fields.Comments, f.Comments)
90120
assert.Equal(t, tt.fields.Labels, f.Labels)
121+
assert.Equal(t, tt.fields.Fields, f.Fields)
91122
}
92123
})
93124
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
%YAML 1.1
2+
---
3+
enable:
4+
issues: true
5+
prs: false
6+
7+
fields:
8+
- title
9+
10+
comments:
11+
issues: 👍 Thanks for this!
12+
prs: |
13+
I applied labels to your pull request.
14+
15+
Please review the labels.
16+
17+
labels:
18+
'bug':
19+
include:
20+
- '\bbug[s]?\b'
21+
exclude: []
22+
branches:
23+
- main
24+
- develop
25+
'help wanted':
26+
include:
27+
- '\bhelp( me)?\b'
28+
exclude:
29+
- '\b\[test(ing)?\]\b'
30+
'enhancement':
31+
include:
32+
- '\bfeat\b'
33+
exclude: []

0 commit comments

Comments
 (0)