Skip to content

Commit f9deb01

Browse files
committed
chore: add support for ignoring PRs by labels
Add `does_not_have_labels` parameter (list of strings) which will make PR ignore PRs with those labels.
1 parent 00157ef commit f9deb01

5 files changed

Lines changed: 74 additions & 1 deletion

File tree

fixtures/config.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,17 @@ github_pr_notifications:
2121

2222
- gh_owner: my-org
2323
gh_repo: my-repo-1
24+
# PR must have ALL labels in this list to match
2425
gh_pr_labels:
2526
- enhancement
2627
gh_pr_include_drafts: true
2728
gh_pr_ignore_approved: true
2829
gh_pr_ignore_changes_requested: true
2930
gh_pr_conditions:
3031
older_than_seconds: 3600
32+
does_not_have_labels:
33+
- "WIP"
34+
- "do not merge"
3135
# Mon-Fri every 2 hours during business hours
3236
schedule: "CRON_TZ=Europe/Berlin 00 10-18/2 * * 1-5"
3337
notify:

internal/cfg/cfg.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ type Notification struct {
7979

8080
// PrConditions struct describes additional conditions for PRs
8181
type PrConditions struct {
82-
OlderThanSeconds int `yaml:"older_than_seconds"`
82+
OlderThanSeconds int `yaml:"older_than_seconds"`
83+
DoesNotHaveLabels []string `yaml:"does_not_have_labels"`
8384
}
8485

8586
// PrNotification is a struct for a single GH repo PRs notifications

internal/cfg/cfg_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,31 @@ func TestGetSlackUID(t *testing.T) {
8585
t.Errorf("Did not expect to find Slack user ID for GitHub login 'nonexistent-gh-user', but found one")
8686
}
8787
}
88+
89+
func TestPrConditions(t *testing.T) {
90+
config := AppConfig{}
91+
err := config.LoadConfig("../../fixtures/config.yaml")
92+
if err != nil {
93+
t.Errorf("Failed to load ./fixtures/config.yaml: %s", err.Error())
94+
}
95+
96+
if len(config.PrNotifications) < 1 {
97+
t.Errorf("Length of github_pr_notifications is %d, but it should be not empty", len(config.PrNotifications))
98+
}
99+
100+
conditions := config.PrNotifications[0].Conditions
101+
if conditions.OlderThanSeconds != 3600 {
102+
t.Errorf("Expected gh_pr_conditions.older_than_seconds=3600, but got %d", conditions.OlderThanSeconds)
103+
}
104+
105+
expectedLabels := []string{"WIP", "do not merge"}
106+
if len(conditions.DoesNotHaveLabels) != len(expectedLabels) {
107+
t.Errorf("Expected gh_pr_conditions.does_not_have_labels length=%d, but got %d", len(expectedLabels), len(conditions.DoesNotHaveLabels))
108+
} else {
109+
for i, label := range expectedLabels {
110+
if conditions.DoesNotHaveLabels[i] != label {
111+
t.Errorf("Expected gh_pr_conditions.does_not_have_labels[%d]=%q, but got %q", i, label, conditions.DoesNotHaveLabels[i])
112+
}
113+
}
114+
}
115+
}

internal/gh/gh.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type Github struct {
1717
Client *github.Client
1818
}
1919

20+
// labelsMatched checks if all labels in filterLabels are present in PR labels
2021
func labelsMatched(prLabels []*github.Label, filterLabels []string) bool {
2122
matched := 0
2223

@@ -80,6 +81,7 @@ func (g *Github) GetPullRequests(prn cfg.PrNotification) ([]*github.PullRequest,
8081
}
8182
glog.V(8).Infof("Checking PR-%d %q: %s", *pr.Number, *pr.Title, *pr.State)
8283

84+
// If ALL labels in prn.Labels are present on the PR, include it
8385
if labelsMatched(pr.Labels, prn.Labels) {
8486
addPR := true
8587

@@ -121,6 +123,13 @@ func (g *Github) MatchesConditions(pr *github.PullRequest, prn cfg.PrNotificatio
121123
prOlderThan := createdAt.Add(time.Duration(prn.Conditions.OlderThanSeconds) * time.Second)
122124
isAfter := time.Now().After(prOlderThan)
123125
if !isAfter {
126+
// PR is not older than the specified time
127+
return false
128+
}
129+
}
130+
if len(prn.Conditions.DoesNotHaveLabels) > 0 {
131+
if labelsMatched(pr.Labels, prn.Conditions.DoesNotHaveLabels) {
132+
// If the PR has any of the labels in DoesNotHaveLabels, it doesn't match the conditions
124133
return false
125134
}
126135
}

internal/gh/gh_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func TestMatchesConditions_OlderThanSeconds(t *testing.T) {
2626
if !g.MatchesConditions(pr, prn) {
2727
t.Error("Expected MatchesConditions to return true for PR older than OlderThanSeconds")
2828
}
29+
2930
}
3031

3132
func TestMatchesConditions_NotOlderThanSeconds(t *testing.T) {
@@ -66,3 +67,33 @@ func TestMatchesConditions_ZeroOlderThanSeconds(t *testing.T) {
6667
t.Error("Expected MatchesConditions to return true when OlderThanSeconds is zero")
6768
}
6869
}
70+
71+
func TestMatchesConditions_DoesNotHaveLabels(t *testing.T) {
72+
g := &Github{}
73+
74+
label := "WIP"
75+
pr := &github.PullRequest{
76+
CreatedAt: &github.Timestamp{Time: time.Now().Add(-2 * time.Hour)},
77+
Labels: []*github.Label{
78+
{Name: &label},
79+
},
80+
}
81+
82+
prNoLabels := &github.PullRequest{
83+
CreatedAt: &github.Timestamp{Time: time.Now().Add(-2 * time.Hour)},
84+
}
85+
86+
prn := cfg.PrNotification{
87+
Conditions: cfg.PrConditions{
88+
DoesNotHaveLabels: []string{"WIP"},
89+
},
90+
}
91+
92+
if g.MatchesConditions(pr, prn) {
93+
t.Error("Expected MatchesConditions to return false for PR with labels in DoesNotHaveLabels")
94+
}
95+
96+
if !g.MatchesConditions(prNoLabels, prn) {
97+
t.Error("Expected MatchesConditions to return true for PR without labels")
98+
}
99+
}

0 commit comments

Comments
 (0)