github.com/abayer/test-infra@v0.0.5/prow/plugins/heart/heart.go (about)

     1  /*
     2  Copyright 2017 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 heart
    18  
    19  import (
    20  	"fmt"
    21  	"math/rand"
    22  	"path/filepath"
    23  	"regexp"
    24  	"strings"
    25  
    26  	"github.com/sirupsen/logrus"
    27  
    28  	"k8s.io/test-infra/prow/github"
    29  	"k8s.io/test-infra/prow/pluginhelp"
    30  	"k8s.io/test-infra/prow/plugins"
    31  )
    32  
    33  const (
    34  	pluginName     = "heart"
    35  	ownersFilename = "OWNERS"
    36  )
    37  
    38  var mergeRe = regexp.MustCompile(`Automatic merge from submit-queue`)
    39  
    40  var reactions = []string{
    41  	github.ReactionThumbsUp,
    42  	github.ReactionLaugh,
    43  	github.ReactionHeart,
    44  	github.ReactionHooray,
    45  }
    46  
    47  func init() {
    48  	plugins.RegisterIssueCommentHandler(pluginName, handleIssueComment, helpProvider)
    49  	plugins.RegisterPullRequestHandler(pluginName, handlePullRequest, helpProvider)
    50  }
    51  
    52  func helpProvider(config *plugins.Configuration, enabledRepos []string) (*pluginhelp.PluginHelp, error) {
    53  	// The {WhoCanUse, Usage, Examples} fields are omitted because this plugin is not triggered with commands.
    54  	return &pluginhelp.PluginHelp{
    55  			Description: "The heart plugin celebrates certain Github actions with the reaction emojis. Emojis are added to merge notifications left by mungegithub's submit-queue and to pull requests that make additions to OWNERS files.",
    56  			Config: map[string]string{
    57  				"": fmt.Sprintf(
    58  					"The heart plugin is configured to react to merge notifications left by the following Github users: %s.",
    59  					strings.Join(config.Heart.Adorees, ", "),
    60  				),
    61  			},
    62  		},
    63  		nil
    64  }
    65  
    66  type githubClient interface {
    67  	CreateCommentReaction(org, repo string, ID int, reaction string) error
    68  	CreateIssueReaction(org, repo string, ID int, reaction string) error
    69  	GetPullRequestChanges(org, repo string, number int) ([]github.PullRequestChange, error)
    70  }
    71  
    72  type client struct {
    73  	GitHubClient githubClient
    74  	Logger       *logrus.Entry
    75  }
    76  
    77  func getClient(pc plugins.PluginClient) client {
    78  	return client{
    79  		GitHubClient: pc.GitHubClient,
    80  		Logger:       pc.Logger,
    81  	}
    82  }
    83  
    84  func handleIssueComment(pc plugins.PluginClient, ic github.IssueCommentEvent) error {
    85  	return handleIC(getClient(pc), pc.PluginConfig.Heart.Adorees, ic)
    86  }
    87  
    88  func handlePullRequest(pc plugins.PluginClient, pre github.PullRequestEvent) error {
    89  	return handlePR(getClient(pc), pre)
    90  }
    91  
    92  func handleIC(c client, adorees []string, ic github.IssueCommentEvent) error {
    93  	// Only consider new comments on PRs.
    94  	if !ic.Issue.IsPullRequest() || ic.Action != github.IssueCommentActionCreated {
    95  		return nil
    96  	}
    97  	adoredLogin := false
    98  	for _, login := range adorees {
    99  		if ic.Comment.User.Login == login {
   100  			adoredLogin = true
   101  			break
   102  		}
   103  	}
   104  	if !adoredLogin {
   105  		return nil
   106  	}
   107  
   108  	if !mergeRe.MatchString(ic.Comment.Body) {
   109  		return nil
   110  	}
   111  
   112  	c.Logger.Info("This is a wonderful thing!")
   113  	return c.GitHubClient.CreateCommentReaction(
   114  		ic.Repo.Owner.Login,
   115  		ic.Repo.Name,
   116  		ic.Comment.ID,
   117  		reactions[rand.Intn(len(reactions))])
   118  }
   119  
   120  func handlePR(c client, pre github.PullRequestEvent) error {
   121  	// Only consider newly opened PRs
   122  	if pre.Action != github.PullRequestActionOpened {
   123  		return nil
   124  	}
   125  
   126  	org := pre.PullRequest.Base.Repo.Owner.Login
   127  	repo := pre.PullRequest.Base.Repo.Name
   128  
   129  	changes, err := c.GitHubClient.GetPullRequestChanges(org, repo, pre.PullRequest.Number)
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	// Smile at any change that adds to OWNERS files
   135  	for _, change := range changes {
   136  		_, filename := filepath.Split(change.Filename)
   137  		if filename == ownersFilename && change.Additions > 0 {
   138  			c.Logger.Info("Adding new OWNERS makes me happy!")
   139  			return c.GitHubClient.CreateIssueReaction(
   140  				pre.PullRequest.Base.Repo.Owner.Login,
   141  				pre.PullRequest.Base.Repo.Name,
   142  				pre.Number,
   143  				reactions[rand.Intn(len(reactions))])
   144  		}
   145  	}
   146  
   147  	return nil
   148  }