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  }