github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/prow/plugins/trigger/ic.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 trigger
    18  
    19  import (
    20  	"fmt"
    21  	"regexp"
    22  
    23  	"k8s.io/test-infra/prow/github"
    24  	"k8s.io/test-infra/prow/kube"
    25  	"k8s.io/test-infra/prow/pjutil"
    26  	"k8s.io/test-infra/prow/plugins"
    27  )
    28  
    29  var okToTest = regexp.MustCompile(`(?m)^/ok-to-test\s*$`)
    30  var retest = regexp.MustCompile(`(?m)^/retest\s*$`)
    31  
    32  func handleIC(c client, trustedOrg string, ic github.IssueCommentEvent) error {
    33  	org := ic.Repo.Owner.Login
    34  	repo := ic.Repo.Name
    35  	number := ic.Issue.Number
    36  	commentAuthor := ic.Comment.User.Login
    37  	// Only take action when a comment is first created.
    38  	if ic.Action != github.IssueCommentActionCreated {
    39  		return nil
    40  	}
    41  	// If it's not an open PR, skip it.
    42  	if !ic.Issue.IsPullRequest() {
    43  		return nil
    44  	}
    45  	if ic.Issue.State != "open" {
    46  		return nil
    47  	}
    48  	// Skip bot comments.
    49  	botName, err := c.GitHubClient.BotName()
    50  	if err != nil {
    51  		return err
    52  	}
    53  	if commentAuthor == botName {
    54  		return nil
    55  	}
    56  
    57  	// Which jobs does the comment want us to run?
    58  	shouldRetestFailed := retest.MatchString(ic.Comment.Body)
    59  	requestedJobs := c.Config.MatchingPresubmits(ic.Repo.FullName, ic.Comment.Body, okToTest)
    60  	if !shouldRetestFailed && len(requestedJobs) == 0 {
    61  		// Check for the presence of the needs-ok-to-test label and remove it
    62  		// if a trusted member has commented "/ok-to-test".
    63  		if okToTest.MatchString(ic.Comment.Body) && ic.Issue.HasLabel(needsOkToTest) {
    64  			orgMember, err := c.GitHubClient.IsMember(trustedOrg, commentAuthor)
    65  			if err != nil {
    66  				return err
    67  			}
    68  			if orgMember {
    69  				return c.GitHubClient.RemoveLabel(ic.Repo.Owner.Login, ic.Repo.Name, ic.Issue.Number, needsOkToTest)
    70  			}
    71  		}
    72  		return nil
    73  	}
    74  
    75  	pr, err := c.GitHubClient.GetPullRequest(org, repo, number)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	if shouldRetestFailed {
    81  		combinedStatus, err := c.GitHubClient.GetCombinedStatus(org, repo, pr.Head.SHA)
    82  		if err != nil {
    83  			return err
    84  		}
    85  		skipContexts := make(map[string]bool) // these succeeded or are running
    86  		runContexts := make(map[string]bool)  // these failed and should be re-run
    87  		for _, status := range combinedStatus.Statuses {
    88  			state := status.State
    89  			if state == github.StatusSuccess || state == github.StatusPending {
    90  				skipContexts[status.Context] = true
    91  			} else if state == github.StatusError || state == github.StatusFailure {
    92  				runContexts[status.Context] = true
    93  			}
    94  		}
    95  		requestedJobs = append(requestedJobs, c.Config.RetestPresubmits(ic.Repo.FullName, skipContexts, runContexts)...)
    96  	}
    97  
    98  	// Skip untrusted users.
    99  	orgMember, err := c.GitHubClient.IsMember(trustedOrg, commentAuthor)
   100  	if err != nil {
   101  		return err
   102  	} else if !orgMember {
   103  		trusted, err := trustedPullRequest(c.GitHubClient, *pr, trustedOrg)
   104  		if err != nil {
   105  			return err
   106  		}
   107  		if !trusted {
   108  			resp := fmt.Sprintf("you can't request testing unless you are a [%s](https://github.com/orgs/%s/people) member.", trustedOrg, trustedOrg)
   109  			c.Logger.Infof("Commenting \"%s\".", resp)
   110  			return c.GitHubClient.CreateComment(org, repo, number, plugins.FormatICResponse(ic.Comment, resp))
   111  		}
   112  	}
   113  
   114  	if okToTest.MatchString(ic.Comment.Body) && ic.Issue.HasLabel(needsOkToTest) {
   115  		if err := c.GitHubClient.RemoveLabel(ic.Repo.Owner.Login, ic.Repo.Name, ic.Issue.Number, needsOkToTest); err != nil {
   116  			c.Logger.WithError(err).Errorf("Failed at removing %s label", needsOkToTest)
   117  		}
   118  	}
   119  
   120  	ref, err := c.GitHubClient.GetRef(org, repo, "heads/"+pr.Base.Ref)
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	var errors []error
   126  	for _, job := range requestedJobs {
   127  		if !job.RunsAgainstBranch(pr.Base.Ref) {
   128  			if err := c.GitHubClient.CreateStatus(org, repo, pr.Head.SHA, github.Status{
   129  				State:       github.StatusSuccess,
   130  				Context:     job.Context,
   131  				Description: "Skipped",
   132  			}); err != nil {
   133  				return err
   134  			}
   135  			continue
   136  		}
   137  		c.Logger.Infof("Starting %s build.", job.Name)
   138  		kr := kube.Refs{
   139  			Org:     org,
   140  			Repo:    repo,
   141  			BaseRef: pr.Base.Ref,
   142  			BaseSHA: ref,
   143  			Pulls: []kube.Pull{
   144  				{
   145  					Number: number,
   146  					Author: pr.User.Login,
   147  					SHA:    pr.Head.SHA,
   148  				},
   149  			},
   150  		}
   151  		if _, err := c.KubeClient.CreateProwJob(pjutil.NewProwJob(pjutil.PresubmitSpec(job, kr))); err != nil {
   152  			errors = append(errors, err)
   153  		}
   154  	}
   155  	if len(errors) > 0 {
   156  		return fmt.Errorf("errors starting jobs: %v", errors)
   157  	}
   158  	return nil
   159  }