github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/prow/plugins/lgtm/lgtm.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package lgtm 18 19 import ( 20 "fmt" 21 "regexp" 22 23 "github.com/sirupsen/logrus" 24 25 "k8s.io/test-infra/prow/github" 26 "k8s.io/test-infra/prow/plugins" 27 ) 28 29 const pluginName = "lgtm" 30 31 var ( 32 lgtmLabel = "lgtm" 33 lgtmRe = regexp.MustCompile(`(?mi)^/lgtm(?: no-issue)?\s*$`) 34 lgtmCancelRe = regexp.MustCompile(`(?mi)^/lgtm cancel\s*$`) 35 ) 36 37 func init() { 38 plugins.RegisterGenericCommentHandler(pluginName, handleGenericComment) 39 } 40 41 type githubClient interface { 42 IsMember(owner, login string) (bool, error) 43 AddLabel(owner, repo string, number int, label string) error 44 AssignIssue(owner, repo string, number int, assignees []string) error 45 CreateComment(owner, repo string, number int, comment string) error 46 RemoveLabel(owner, repo string, number int, label string) error 47 GetIssueLabels(org, repo string, number int) ([]github.Label, error) 48 } 49 50 func handleGenericComment(pc plugins.PluginClient, e github.GenericCommentEvent) error { 51 return handle(pc.GitHubClient, pc.Logger, &e) 52 } 53 54 func handle(gc githubClient, log *logrus.Entry, e *github.GenericCommentEvent) error { 55 // Only consider open PRs and new comments. 56 if !e.IsPR || e.IssueState != "open" || e.Action != github.GenericCommentActionCreated { 57 return nil 58 } 59 60 // If we create an "/lgtm" comment, add lgtm if necessary. 61 // If we create a "/lgtm cancel" comment, remove lgtm if necessary. 62 wantLGTM := false 63 if lgtmRe.MatchString(e.Body) { 64 wantLGTM = true 65 } else if lgtmCancelRe.MatchString(e.Body) { 66 wantLGTM = false 67 } else { 68 return nil 69 } 70 71 org := e.Repo.Owner.Login 72 repo := e.Repo.Name 73 commentAuthor := e.User.Login 74 75 // Allow authors to cancel LGTM. Do not allow authors to LGTM, and do not 76 // accept commands from any other user. 77 isAssignee := false 78 for _, assignee := range e.Assignees { 79 if assignee.Login == e.User.Login { 80 isAssignee = true 81 break 82 } 83 } 84 isAuthor := e.User.Login == e.IssueAuthor.Login 85 if isAuthor && wantLGTM { 86 resp := "you cannot LGTM your own PR." 87 log.Infof("Commenting with \"%s\".", resp) 88 return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, commentAuthor, resp)) 89 } else if !isAuthor && !isAssignee { 90 log.Infof("Assigning %s/%s#%d to %s", org, repo, e.Number, commentAuthor) 91 if err := gc.AssignIssue(org, repo, e.Number, []string{commentAuthor}); err != nil { 92 msg := "assigning you to the PR failed" 93 if ok, merr := gc.IsMember(org, commentAuthor); merr == nil && !ok { 94 msg = fmt.Sprintf("only %s org members may be assigned issues", org) 95 } else if merr != nil { 96 log.WithError(merr).Errorf("Failed IsMember(%s, %s)", org, commentAuthor) 97 } else { 98 log.WithError(err).Errorf("Failed AssignIssue(%s, %s, %d, %s)", org, repo, e.Number, commentAuthor) 99 } 100 resp := "changing LGTM is restricted to assignees, and " + msg + "." 101 log.Infof("Reply to assign via /lgtm request with comment: \"%s\"", resp) 102 return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, commentAuthor, resp)) 103 } 104 } 105 106 // Only add the label if it doesn't have it, and vice versa. 107 hasLGTM := false 108 labels, err := gc.GetIssueLabels(org, repo, e.Number) 109 if err != nil { 110 log.WithError(err).Errorf("Failed to get the labels on %s/%s#%d.", org, repo, e.Number) 111 } 112 for _, candidate := range labels { 113 if candidate.Name == lgtmLabel { 114 hasLGTM = true 115 break 116 } 117 } 118 if hasLGTM && !wantLGTM { 119 log.Info("Removing LGTM label.") 120 return gc.RemoveLabel(org, repo, e.Number, lgtmLabel) 121 } else if !hasLGTM && wantLGTM { 122 log.Info("Adding LGTM label.") 123 return gc.AddLabel(org, repo, e.Number, lgtmLabel) 124 } 125 return nil 126 }