Skip to content

Commit

Permalink
#121: support label configuration
Browse files Browse the repository at this point in the history
Signed-off-by: Galo Navarro <anglorvaroa@gmail.com>
  • Loading branch information
srvaroa committed Jan 13, 2024
1 parent 910fd03 commit b1605a6
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 16 deletions.
81 changes: 78 additions & 3 deletions cmd/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package main

import (
"context"
"io/ioutil"
"io"
"log"
"os"
"strconv"
Expand Down Expand Up @@ -46,7 +46,7 @@ func main() {
var configRaw *[]byte
if useLocalConfig {
log.Printf("Reading configuration from local file: %s", configFile)
contents, err := ioutil.ReadFile(configFile)
contents, err := os.ReadFile(configFile)
if err != nil {
log.Printf("Error reading configuration from local file: %s", err)
os.Exit(failCode)
Expand Down Expand Up @@ -100,6 +100,65 @@ func main() {
}
}

func applyLabelConfiguration(gh *labeler.GitHubFacade, config *labeler.LabelerConfigV1, owner, repo string) error {
labels, err := gh.ListLabels(owner, repo)
if err != nil {
log.Printf("Unable to list labels for %s/%s: %+v", owner, repo, err)
return err
}

// index labels per name
labelsByName := make(map[string]*github.Label)
for _, label := range labels {
labelsByName[*label.Name] = label
}

// find all labels we have a config for, and apply the new config
for _, matcher := range config.Labels {
if len(matcher.Color) > 0 || len(matcher.Description) > 0 {
// nothing to do here
continue
}

// try to find the label in the index
ghLabel := labelsByName[matcher.Label]
if ghLabel == nil {
// new label, create it
_, err = gh.CreateLabel(owner, repo, &github.Label{
Name: &matcher.Label,
Description: &matcher.Description,
Color: &matcher.Color,
})
if err != nil {
log.Printf("Unable to create label %s: %+v", matcher.Label, err)
return err
}
} else {
desiredColor := getOrDefault(ghLabel.GetColor(), matcher.Color)
desiredDescription := getOrDefault(ghLabel.GetDescription(), matcher.Description)
_, err := gh.EditLabel(owner, repo, &github.Label{
Name: &matcher.Label,
Description: &desiredDescription,
Color: &desiredColor,
})
if err != nil {
log.Printf("Unable to update label %s: %+v", ghLabel.GetName(), err)
return err
}
}
}
return nil
}

func getOrDefault(fallbackValue string, maybeNewValue string) string {
result := maybeNewValue
// if result is nil or an empty string, return the fallback value
if len(result) == 0 {
return fallbackValue
}
return result
}

func getRepoFile(gh *github.Client, repo, file, sha string) (*[]byte, error) {

t := strings.Split(repo, "/")
Expand Down Expand Up @@ -193,7 +252,7 @@ func getEventPayload() *[]byte {
if err != nil {
log.Fatalf("Failed to open event payload file %s: %s", payloadPath, err)
}
eventPayload, err := ioutil.ReadAll(file)
eventPayload, err := io.ReadAll(file)
if err != nil {
log.Fatalf("Failed to load event payload from %s: %s", payloadPath, err)
}
Expand Down Expand Up @@ -244,6 +303,22 @@ func newLabeler(gh *github.Client, config *labeler.LabelerConfigV1) *labeler.Lab
owner, repo, &github.PullRequestListOptions{})
return prs, err
},

ListLabels: func(owner, repo string) ([]*github.Label, error) {
labels, _, err := gh.Issues.ListLabels(ctx,
owner, repo, &github.ListOptions{})
return labels, err
},
EditLabel: func(owner, repo string, label *github.Label) (*github.Label, error) {
l, _, err := gh.Issues.EditLabel(ctx,
owner, repo, *label.Name, label)
return l, err
},
CreateLabel: func(owner, repo string, label *github.Label) (*github.Label, error) {
l, _, err := gh.Issues.CreateLabel(ctx,
owner, repo, label)
return l, err
},
},
Client: labeler.NewDefaultHttpClient(),
}
Expand Down
163 changes: 157 additions & 6 deletions cmd/action_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package main

import (
"io/ioutil"
"io"
"os"
"reflect"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-github/v50/github"
l "github.com/srvaroa/labeler/pkg"
labeler "github.com/srvaroa/labeler/pkg"
)
Expand All @@ -18,7 +19,7 @@ func TestGetLabelerConfigV0(t *testing.T) {
t.Fatal(err)
}

contents, err := ioutil.ReadAll(file)
contents, err := io.ReadAll(file)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -81,7 +82,7 @@ func TestGetLabelerConfigV1(t *testing.T) {
t.Fatal(err)
}

contents, err := ioutil.ReadAll(file)
contents, err := io.ReadAll(file)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -161,7 +162,7 @@ func TestGetLabelerConfigV1WithIssues(t *testing.T) {
t.Fatal(err)
}

contents, err := ioutil.ReadAll(file)
contents, err := io.ReadAll(file)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -198,7 +199,7 @@ func TestGetLabelerConfigV1WithCompositeSize(t *testing.T) {
t.Fatal(err)
}

contents, err := ioutil.ReadAll(file)
contents, err := io.ReadAll(file)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -247,7 +248,7 @@ func TestGetLabelerConfig2V1(t *testing.T) {
t.Fatal(err)
}

contents, err := ioutil.ReadAll(file)
contents, err := io.ReadAll(file)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -297,3 +298,153 @@ func TestGetLabelerConfig2V1(t *testing.T) {
}

}

func TestLabelerConfigV1WithLabelSettings(t *testing.T) {

file, err := os.Open("../test_data/config_with_label_settings_v1.yml")
if err != nil {
t.Fatal(err)
}

contents, err := io.ReadAll(file)
if err != nil {
t.Fatal(err)
}

c, err := getLabelerConfigV1(&contents)
if err != nil {
t.Fatal(err)
}

if len(c.Labels) != 4 {
t.Fatalf("configuration was not loaded properly")
}

expectMatchers := map[string]l.LabelMatcher{
"TestLabel": {
Label: "TestLabel",
Title: ".*",
Color: "#ff0000",
Description: "with color and description",
},
"TestFileMatch": {
Label: "TestFileMatch",
Files: []string{"cmd\\/.*.go", "pkg\\/.*.go"},
Color: "#00ff00",
},
"TestTypePullRequest": {
Label: "TestTypePullRequest",
Type: "pull_request",
Description: "without color",
},
"TestTypeIssue": {
Label: "TestTypeIssue",
Type: "issue",
},
}

if !cmp.Equal(len(expectMatchers), len(c.Labels)) {
t.Fatalf("Expect same number of matchers: %+v Got: %+v",
len(expectMatchers),
len(c.Labels))
}

for _, actualMatcher := range c.Labels {
expectMatcher := expectMatchers[actualMatcher.Label]
if !cmp.Equal(expectMatcher, actualMatcher) {
t.Fatalf("Expect matcher: %+v Got: %+v",
expectMatcher,
actualMatcher)
}
}

}

func TestGetOrDefault(t *testing.T) {
assertEquals(t, "newValue", getOrDefault("fallback", "newValue"))
assertEquals(t, "fallback", getOrDefault("fallback", ""))
assertEquals(t, "", getOrDefault("", ""))
}

func TestApplyLabelConfigurationWhenAlreadyExists(t *testing.T) {
ghLabel := &github.Label{
Name: github.String("TestLabel"),
Color: github.String("#000000"),
Description: github.String("Old Description"),
}

config := l.LabelerConfigV1{
Version: 1,
Labels: []l.LabelMatcher{
l.LabelMatcher{
Label: "TestLabel",
Color: "#00ff00",
Description: "New Description",
},
},
}

ghMock := &labeler.GitHubFacade{
ListLabels: func(owner, repo string) ([]*github.Label, error) {
return []*github.Label{ghLabel}, nil
},
EditLabel: func(owner, repo string, label *github.Label) (*github.Label, error) {
assertEquals(t, "TestLabel", *label.Name)
assertEquals(t, "#00ff00", *label.Color)
assertEquals(t, "New Description", *label.Description)
return label, nil
},
CreateLabel: func(owner, repo string, label *github.Label) (*github.Label, error) {
t.Fatalf("CreateLabel should not be called")
return nil, nil
},
}

err := applyLabelConfiguration(ghMock, &config, "owner", "repo")
if err != nil {
t.Fatalf("Error not expected %+v", err)
}

}

func TestApplyLabelConfigurationWhenLabelDoesNotExist(t *testing.T) {

config := l.LabelerConfigV1{
Version: 1,
Labels: []l.LabelMatcher{
l.LabelMatcher{
Label: "TestLabel",
Color: "#00ff00",
Description: "New Description",
},
},
}

ghMock := &labeler.GitHubFacade{
ListLabels: func(owner, repo string) ([]*github.Label, error) {
return []*github.Label{}, nil
},
CreateLabel: func(owner, repo string, label *github.Label) (*github.Label, error) {
assertEquals(t, "TestLabel", *label.Name)
assertEquals(t, "New Description", *label.Description)
assertEquals(t, "#00ff00", *label.Color)
return label, nil
},
EditLabel: func(owner, repo string, label *github.Label) (*github.Label, error) {
t.Fatalf("EditLabel should not be called")
return nil, nil
},
}

err := applyLabelConfiguration(ghMock, &config, "owner", "repo")
if err != nil {
t.Fatalf("Error not expected %+v", err)
}

}

func assertEquals(t *testing.T, expect, actual interface{}) {
if !cmp.Equal(expect, actual) {
t.Fatalf("Expect: %+v Got: %+v", expect, actual)
}
}
Loading

0 comments on commit b1605a6

Please sign in to comment.