Skip to content

Commit

Permalink
Add pr file matchers (#9)
Browse files Browse the repository at this point in the history
* Add pr file matchers

* Quick refactors per PR comments

* Refactor getting of pr file names

* Removed unused param

* Only fetch PR files names once
  • Loading branch information
Stoom authored Jun 26, 2020
1 parent 3958b41 commit 052ceac
Show file tree
Hide file tree
Showing 7 changed files with 623 additions and 3 deletions.
9 changes: 7 additions & 2 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
TestLabel:
title: ".*"
TestLabel:
title: ".*"
TestFileMatch:
files:
- "cmd/.*.go"
- "pkg/.*.go"

15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,21 @@ This condition is satisfied when the PR title matches on the given regex.
WIP:
title: "^WIP:.*"

### Regex on branch

This condition is satisfied when the PR branch matches on the given regex.

Feature:
branch: "^feature/.*"

### Regex on PR files

This condition is satisfied when any of the PR files matches on the given regexs.

Tests:
files:
- "cmd/.*_tests.go"

### Mergeable status

This condition is satisfied when the PR is in a [mergeable state](https://developer.github.com/v3/pulls/#response-1).
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ require (
github.com/kr/pretty v0.1.0 // indirect
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
github.com/waigani/diffparser v0.0.0-20190828052634-7391f219313d
)
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
Expand All @@ -13,6 +15,11 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/waigani/diffparser v0.0.0-20190828052634-7391f219313d h1:xQcF7b7cZLWZG/+7A4G7un1qmEDYHIvId9qxRS1mZMs=
github.com/waigani/diffparser v0.0.0-20190828052634-7391f219313d/go.mod h1:BzSc3WEF8R+lCaP5iGFRxd5kIXy4JKOZAwNe1w0cdc0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
Expand Down
85 changes: 85 additions & 0 deletions pkg/labeler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@ package labeler

import (
"fmt"
"io/ioutil"
"log"
"math"
"net/http"
"os"
"regexp"
"strconv"
"strings"

gh "github.com/google/go-github/v27/github"
"github.com/waigani/diffparser"
)

type LabelerConfig map[string]LabelMatcher
type LabelMatcher struct {
Title string
Branch string
Files []string
Mergeable string
SizeBelow string `yaml:"size-below"`
SizeAbove string `yaml:"size-above"`
Expand Down Expand Up @@ -68,6 +74,41 @@ func NewBranchCondition() Condition {
}
}

func NewFilesCondition() Condition {
prFiles := []string{}

return Condition{
GetName: func() string {
return "File matches regex"
},
Evaluate: func(pr *gh.PullRequest, matcher LabelMatcher) (bool, error) {
if len(matcher.Files) <= 0 {
return false, fmt.Errorf("Files are not set in config")
}

if len(prFiles) == 0 {
var err error
prFiles, err = getPrFileNames(pr)
if err != nil {
return false, err
}
}

log.Printf("Matching `%s` against: %s", strings.Join(matcher.Files, ", "), strings.Join(prFiles, ", "))
for _, fileMatcher := range matcher.Files {
for _, prFile := range prFiles {
isMatched, _ := regexp.Match(fileMatcher, []byte(prFile))
if isMatched {
log.Printf("Matched `%s` against: `%s`", prFile, fileMatcher)
return isMatched, nil
}
}
}
return false, nil
},
}
}

func NewIsMergeableCondition() Condition {
return Condition{
GetName: func() string {
Expand Down Expand Up @@ -184,6 +225,7 @@ func (l *Labeler) findMatches(pr *gh.PullRequest, config *LabelerConfig) (LabelU
NewBranchCondition(),
NewIsMergeableCondition(),
NewSizeCondition(),
NewFilesCondition(),
}

for label, matcher := range *config {
Expand All @@ -204,3 +246,46 @@ func (l *Labeler) findMatches(pr *gh.PullRequest, config *LabelerConfig) (LabelU

return labelUpdates, nil
}

// getPrFileNames returns all of the file names (old and new) of files changed in the given PR
func getPrFileNames(pr *gh.PullRequest) ([]string, error) {
ghToken := os.Getenv("GITHUB_TOKEN")
diffReq, err := http.NewRequest("GET", pr.GetDiffURL(), nil)

if err != nil {
return nil, err
}

diffReq.Header.Add("Authorization", "Bearer "+ghToken)
diffRes, err := http.DefaultClient.Do(diffReq)

if err != nil {
return nil, err
}

defer diffRes.Body.Close()

var diffRaw []byte
prFiles := make([]string, 0)
if diffRes.StatusCode == http.StatusOK {
diffRaw, err = ioutil.ReadAll(diffRes.Body)

if err != nil {
return nil, err
}

diff, _ := diffparser.Parse(string(diffRaw))
prFilesSet := map[string]struct{}{}
// Place in a set to remove duplicates
for _, file := range diff.Files {
prFilesSet[file.OrigName] = struct{}{}
prFilesSet[file.NewName] = struct{}{}
}
// Convert to list to make it easier to consume
for k := range prFilesSet {
prFiles = append(prFiles, k)
}
}

return prFiles, nil
}
13 changes: 13 additions & 0 deletions pkg/labeler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,19 @@ func TestHandleEvent(t *testing.T) {
initialLabels: []string{},
expectedLabels: []string{},
},
TestCase{
payloads: []string{"diff_pr"},
name: "Test the branch rule",
config: LabelerConfig{
"Files": LabelMatcher{
Files: []string{
"^pkg/.*_test.go",
},
},
},
initialLabels: []string{},
expectedLabels: []string{"Files"},
},
}

for _, tc := range testCases {
Expand Down
Loading

0 comments on commit 052ceac

Please sign in to comment.