Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions fixtures/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ github_pr_notifications:

- gh_owner: my-org
gh_repo: my-repo-1
# PR must have ALL labels in this list to match
gh_pr_labels:
- enhancement
gh_pr_include_drafts: true
gh_pr_ignore_approved: true
gh_pr_ignore_changes_requested: true
gh_pr_conditions:
older_than_seconds: 3600
does_not_have_labels:
- "WIP"
- "do not merge"
# Mon-Fri every 2 hours during business hours
schedule: "CRON_TZ=Europe/Berlin 00 10-18/2 * * 1-5"
notify:
Expand Down
3 changes: 2 additions & 1 deletion internal/cfg/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ type Notification struct {

// PrConditions struct describes additional conditions for PRs
type PrConditions struct {
OlderThanSeconds int `yaml:"older_than_seconds"`
OlderThanSeconds int `yaml:"older_than_seconds"`
DoesNotHaveLabels []string `yaml:"does_not_have_labels"`
}

// PrNotification is a struct for a single GH repo PRs notifications
Expand Down
28 changes: 28 additions & 0 deletions internal/cfg/cfg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,31 @@ func TestGetSlackUID(t *testing.T) {
t.Errorf("Did not expect to find Slack user ID for GitHub login 'nonexistent-gh-user', but found one")
}
}

func TestPrConditions(t *testing.T) {
config := AppConfig{}
err := config.LoadConfig("../../fixtures/config.yaml")
if err != nil {
t.Errorf("Failed to load ./fixtures/config.yaml: %s", err.Error())
}

if len(config.PrNotifications) < 1 {
t.Errorf("Length of github_pr_notifications is %d, but it should be not empty", len(config.PrNotifications))
}

conditions := config.PrNotifications[0].Conditions
if conditions.OlderThanSeconds != 3600 {
t.Errorf("Expected gh_pr_conditions.older_than_seconds=3600, but got %d", conditions.OlderThanSeconds)
}

expectedLabels := []string{"WIP", "do not merge"}
if len(conditions.DoesNotHaveLabels) != len(expectedLabels) {
t.Errorf("Expected gh_pr_conditions.does_not_have_labels length=%d, but got %d", len(expectedLabels), len(conditions.DoesNotHaveLabels))
} else {
for i, label := range expectedLabels {
if conditions.DoesNotHaveLabels[i] != label {
t.Errorf("Expected gh_pr_conditions.does_not_have_labels[%d]=%q, but got %q", i, label, conditions.DoesNotHaveLabels[i])
}
}
}
}
9 changes: 9 additions & 0 deletions internal/gh/gh.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Github struct {
Client *github.Client
}

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

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

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

Expand Down Expand Up @@ -121,6 +123,13 @@ func (g *Github) MatchesConditions(pr *github.PullRequest, prn cfg.PrNotificatio
prOlderThan := createdAt.Add(time.Duration(prn.Conditions.OlderThanSeconds) * time.Second)
isAfter := time.Now().After(prOlderThan)
if !isAfter {
// PR is not older than the specified time
return false
}
}
if len(prn.Conditions.DoesNotHaveLabels) > 0 {
if labelsMatched(pr.Labels, prn.Conditions.DoesNotHaveLabels) {
// If the PR has any of the labels in DoesNotHaveLabels, it doesn't match the conditions
return false
}
}
Expand Down
30 changes: 30 additions & 0 deletions internal/gh/gh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,33 @@ func TestMatchesConditions_ZeroOlderThanSeconds(t *testing.T) {
t.Error("Expected MatchesConditions to return true when OlderThanSeconds is zero")
}
}

func TestMatchesConditions_DoesNotHaveLabels(t *testing.T) {
g := &Github{}

label := "WIP"
pr := &github.PullRequest{
CreatedAt: &github.Timestamp{Time: time.Now().Add(-2 * time.Hour)},
Labels: []*github.Label{
{Name: &label},
},
}

prNoLabels := &github.PullRequest{
CreatedAt: &github.Timestamp{Time: time.Now().Add(-2 * time.Hour)},
}

prn := cfg.PrNotification{
Conditions: cfg.PrConditions{
DoesNotHaveLabels: []string{"WIP"},
},
}

if g.MatchesConditions(pr, prn) {
t.Error("Expected MatchesConditions to return false for PR with labels in DoesNotHaveLabels")
}

if !g.MatchesConditions(prNoLabels, prn) {
t.Error("Expected MatchesConditions to return true for PR without labels")
}
}
Loading