Skip to content

Commit

Permalink
Support Add/Remove Labels
Browse files Browse the repository at this point in the history
  • Loading branch information
edisonxiang committed Feb 22, 2019
1 parent a58596c commit ae8cbbb
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 42 deletions.
57 changes: 57 additions & 0 deletions handlers/assign/assign.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package assign

import (
"context"
"regexp"
"strings"

"github.com/golang/glog"
"github.com/google/go-github/github"
)

const (
Assign = "/assign"
Unassign = "/unassign"
)

// Handle event with assign
func Handle(client *github.Client, event github.IssueCommentEvent) error {
comment := *event.Comment.Body
//regular expression to Assign or unassign the Assignees
reg := regexp.MustCompile("(?mi)^/(un)?assign(( @?[-\\w]+?)*)\\s*$")

if reg.MatchString(comment) {
ctx := context.Background()
//split the assignees and operation to be performed.
substrings := strings.Split(comment, "@")
//list of assignees to be assigned for issues/PR
listOfAssignees := make([]string, 0)
//range over the substring to get the list of assignees
for i, assignees := range substrings {
if i == 0 {
//first index is the operation to be performed, rest will be the assignees
continue
}
listOfAssignees = append(listOfAssignees, assignees)
}
//operation is the assign or unassign check
operation := strings.Trim(substrings[0], " ")
if operation == Assign {
_, _, err := client.Issues.AddAssignees(ctx, *event.Repo.Owner.Login, *event.Repo.Name, *event.Issue.Number, listOfAssignees)
if err != nil {
glog.Fatalf("Unable to Add Assignees: %v err: %v", listOfAssignees, err)
return err
} else {
glog.Infof("Assignee added successfully: %v", listOfAssignees)
}
} else if operation == Unassign {
_, _, err := client.Issues.RemoveAssignees(ctx, *event.Repo.Owner.Login, *event.Repo.Name, *event.Issue.Number, listOfAssignees)
if err != nil {
glog.Fatalf("Cannot remove Assignees: %v err: %v", listOfAssignees, err)
return err
}
glog.Infof("Removed assignee: %v", listOfAssignees)
}
}
return nil
}
1 change: 0 additions & 1 deletion handlers/ci.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package handlers

import (

"github.com/golang/glog"
)

Expand Down
53 changes: 12 additions & 41 deletions handlers/issue.go
Original file line number Diff line number Diff line change
@@ -1,69 +1,40 @@
package handlers

import (
"context"
"encoding/json"
"regexp"
"strings"

"github.com/golang/glog"
"github.com/google/go-github/github"
)

const (
Assign = "/assign"
Unassign = "/unassign"
"github.com/Huawei-PaaS/ci-bot/handlers/assign"
"github.com/Huawei-PaaS/ci-bot/handlers/label"
)

type GithubIssue github.Issue

func (s *Server) handleIssueEvent(body []byte) {
glog.Info("Received an Issue Event")

}

//function to handle issue comments
func (s *Server) handleIssueCommentEvent(body []byte, client *github.Client) {
var commentEvent github.IssueCommentEvent

// Unmarshal
err := json.Unmarshal(body, &commentEvent)
if err != nil {
glog.Errorf("fail to unmarshal: %v", err)
}
ctx := context.Background()
comment := *commentEvent.Comment.Body
//split the assignees and operation to be performed.
substrings := strings.Split(comment, "@")
//regular expression to Assign or unassign the Assignees
reg := regexp.MustCompile("(?mi)^/(un)?assign(( @?[-\\w]+?)*)\\s*$")
matchAssignOrUnassign := reg.MatchString(comment)
//list of assignees to be assigned for issues/PR
listOfAssignees := make([]string, 0)
//range over the substring to get the list of assignees
for i, assignees := range substrings {
if i == 0 {
//first index is the operation to be performed, rest will be the assignees
continue
}
listOfAssignees = append(listOfAssignees, assignees)

// assign
err = assign.Handle(client, commentEvent)
if err != nil {
glog.Errorf("fail to handle: %v", err)
}
//operation is the assign or unassign check
operation := strings.Trim(substrings[0], " ")

if matchAssignOrUnassign == true {
if operation == Assign {
_, _, err := client.Issues.AddAssignees(ctx, *commentEvent.Repo.Owner.Login, *commentEvent.Repo.Name, *commentEvent.Issue.Number, listOfAssignees)
if err != nil {
glog.Fatalf("Unable to Add Assignees: %v err: %v", listOfAssignees, err)
} else {
glog.Infof("Assignee added successfully: %v", listOfAssignees)
}
} else if operation == Unassign {
_, _, err := client.Issues.RemoveAssignees(ctx, *commentEvent.Repo.Owner.Login, *commentEvent.Repo.Name, *commentEvent.Issue.Number, listOfAssignees)
if err != nil {
glog.Fatalf("Cannot remove Assignees: %v err: %v", listOfAssignees, err)
}
glog.Infof("Removed assignee: %v", listOfAssignees)
}
// label
err = label.Handle(client, commentEvent)
if err != nil {
glog.Errorf("fail to handle: %v", err)
}
}
216 changes: 216 additions & 0 deletions handlers/label/label.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package label

import (
"context"
"regexp"
"strings"

"github.com/golang/glog"
"github.com/google/go-github/github"
)

var (
// regular expression to add label
regAddLabel = regexp.MustCompile(`(?mi)^/(kind|priority)\s*(.*)$`)
// regular expression to remove label
regRemoveLabel = regexp.MustCompile(`(?mi)^/remove-(kind|priority)\s*(.*)$`)
)

// Handle event with label
func Handle(client *github.Client, event github.IssueCommentEvent) error {
// get basic params
comment := *event.Comment.Body
glog.Infof("receive event with label. comment: %s", comment)

// add labels
if regAddLabel.MatchString(comment) {
return add(client, event)
}
// remove labels
if regRemoveLabel.MatchString(comment) {
return remove(client, event)
}

return nil
}

// add labels
func add(client *github.Client, event github.IssueCommentEvent) error {
// get basic params
ctx := context.Background()
comment := *event.Comment.Body
owner := *event.Repo.Owner.Login
repo := *event.Repo.Name
number := *event.Issue.Number
glog.Infof("add label started. comment: %s owner: %s repo: %s number: %d", comment, owner, repo, number)

// map of add labels
mapOfAddLabels := getLabelsMap(comment)
glog.Infof("map of add labels: %v", mapOfAddLabels)

// list labels in current github repository
listofRepoLabels, _, err := client.Issues.ListLabels(ctx, owner, repo, nil)
if err != nil {
glog.Fatalf("unable to list repository labels. err: %v", err)
return err
}
glog.Infof("list of repository labels: %v", listofRepoLabels)

// list labels in current issue
listofIssueLabels, _, err := client.Issues.ListLabelsByIssue(ctx, owner, repo, number, nil)
if err != nil {
glog.Fatalf("unable to list issue labels. err: %v", err)
return err
}
glog.Infof("list of issue labels: %v", listofIssueLabels)

// list of add labels
listOfAddLabels := getListOfAddLabels(mapOfAddLabels, listofRepoLabels, listofIssueLabels)
glog.Infof("list of add labels: %v", listOfAddLabels)

// invoke github api to add labels
if len(listOfAddLabels) > 0 {
_, _, err := client.Issues.AddLabelsToIssue(ctx, owner, repo, number, listOfAddLabels)
if err != nil {
glog.Fatalf("unable to add labels: %v err: %v", listOfAddLabels, err)
return err
} else {
glog.Infof("add labels successfully: %v", listOfAddLabels)
}
} else {
glog.Infof("No label to add for this event")
}
return nil
}

// remove labels
func remove(client *github.Client, event github.IssueCommentEvent) error {
// get basic params
ctx := context.Background()
comment := *event.Comment.Body
owner := *event.Repo.Owner.Login
repo := *event.Repo.Name
number := *event.Issue.Number
glog.Infof("remove label started. comment: %s owner: %s repo: %s number: %d", comment, owner, repo, number)

// map of add labels
mapOfRemoveLabels := getLabelsMap(comment)
glog.Infof("map of remove labels: %v", mapOfRemoveLabels)

// list labels in current issue
listofIssueLabels, _, err := client.Issues.ListLabelsByIssue(ctx, owner, repo, number, nil)
if err != nil {
glog.Fatalf("unable to list issue labels. err: %v", err)
return err
}
glog.Infof("list of issue labels: %v", listofIssueLabels)

// list of remove labels
listOfRemoveLabels := getListOfRemoveLabels(mapOfRemoveLabels, listofIssueLabels)
glog.Infof("list of remove labels: %v", listOfRemoveLabels)

// invoke github api to remove labels
if len(listOfRemoveLabels) > 0 {
for _, l := range listOfRemoveLabels {
_, err := client.Issues.RemoveLabelForIssue(ctx, owner, repo, number, l)
if err != nil {
glog.Fatalf("unable to remove label: %v err: %v", l, err)
} else {
glog.Infof("remove label successfully: %v", l)
}
}
} else {
glog.Infof("No label to remove for this event")
}
return nil
}

// getListOfAddLabels return the exact list of add labels
func getListOfAddLabels(mapOfAddLabels map[string]string, listofRepoLabels []*github.Label, listofIssueLabels []*github.Label) []string {
// init
listOfAddLabels := make([]string, 0)
// range over the map to filter the list of labels
for l := range mapOfAddLabels {
// check if the label is existing in current github repository
existingInRepo := false
for _, repoLabel := range listofRepoLabels {
if l == *repoLabel.Name {
existingInRepo = true
break
}
}
// the label is not existing in current github repository so it can not add this label
if !existingInRepo {
glog.Infof("label %s is not existing in repository", l)
continue
}

// check if the label is existing in current issue
existingInIssue := false
for _, issueLabel := range listofIssueLabels {
if l == *issueLabel.Name {
existingInIssue = true
break
}
}
// the label is already existing in current issue so it is no need to add this label
if existingInIssue {
glog.Infof("label %s is already existing in current issue", l)
continue
}

// append
listOfAddLabels = append(listOfAddLabels, l)
}
return listOfAddLabels
}

// getListOfRemoveLabels return the exact list of remove labels
func getListOfRemoveLabels(mapOfRemoveLabels map[string]string, listofIssueLabels []*github.Label) []string {
// init
listOfRemoveLabels := make([]string, 0)
// range over the map to filter the list of labels
for l := range mapOfRemoveLabels {
// check if the label is existing in current issue
existingInIssue := false
for _, issueLabel := range listofIssueLabels {
if l == *issueLabel.Name {
existingInIssue = true
break
}
}
// the label is not existing in current issue so it is no need to remove this label
if !existingInIssue {
glog.Infof("label %s is not existing in current issue", l)
continue
}

// append
listOfRemoveLabels = append(listOfRemoveLabels, l)
}
return listOfRemoveLabels
}

// getLabelsMap for add or remove labels
func getLabelsMap(comment string) map[string]string {
// init labels map
mapOfLabels := map[string]string{}
// split with blank space
substrings := strings.Split(strings.TrimSpace(comment), " ")
// init label group
labelGroup := ""
// range over the substrings to get the map of labels
for i, l := range substrings {
if i == 0 {
// first index is the operation to be performed, rest will be the labels
// the label group. e.g kind, priority
labelGroup = strings.Replace(strings.Replace(l, "/", "", 1), "remove-", "", 1)
} else {
// the whole label = label group + / + label. e.g kind/feature
wholeLabel := labelGroup + "/" + l
// use map to avoid the reduplicate label
mapOfLabels[wholeLabel] = wholeLabel
}
}
return mapOfLabels
}

0 comments on commit ae8cbbb

Please sign in to comment.