github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/plugins/trigger/generic-comment.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/labels" 25 "k8s.io/test-infra/prow/plugins" 26 ) 27 28 var okToTestRe = regexp.MustCompile(`(?m)^/ok-to-test\s*$`) 29 var testAllRe = regexp.MustCompile(`(?m)^/test all,?($|\s.*)`) 30 var retestRe = regexp.MustCompile(`(?m)^/retest\s*$`) 31 32 func handleGenericComment(c Client, trigger *plugins.Trigger, gc github.GenericCommentEvent) error { 33 org := gc.Repo.Owner.Login 34 repo := gc.Repo.Name 35 number := gc.Number 36 commentAuthor := gc.User.Login 37 // Only take action when a comment is first created, 38 // when it belongs to a PR, 39 // and the PR is open. 40 if gc.Action != github.GenericCommentActionCreated || !gc.IsPR || gc.IssueState != "open" { 41 return nil 42 } 43 // Skip bot comments. 44 botName, err := c.GitHubClient.BotName() 45 if err != nil { 46 return err 47 } 48 if commentAuthor == botName { 49 return nil 50 } 51 52 // Which jobs does the comment want us to run? 53 allowOkToTest := trigger == nil || !trigger.IgnoreOkToTest 54 isOkToTest := okToTestRe.MatchString(gc.Body) && allowOkToTest 55 testAll := isOkToTest || testAllRe.MatchString(gc.Body) 56 shouldRetestFailed := retestRe.MatchString(gc.Body) 57 requestedJobs := c.Config.MatchingPresubmits(gc.Repo.FullName, gc.Body, testAll) 58 if !shouldRetestFailed && len(requestedJobs) == 0 { 59 // If a trusted member has commented "/ok-to-test", 60 // eventually add ok-to-test and remove needs-ok-to-test. 61 l, err := c.GitHubClient.GetIssueLabels(org, repo, number) 62 if err != nil { 63 return err 64 } 65 if isOkToTest && !github.HasLabel(labels.OkToTest, l) { 66 trusted, err := TrustedUser(c.GitHubClient, trigger, commentAuthor, org, repo) 67 if err != nil { 68 return err 69 } 70 if trusted { 71 if err := c.GitHubClient.AddLabel(org, repo, number, labels.OkToTest); err != nil { 72 return err 73 } 74 if github.HasLabel(labels.NeedsOkToTest, l) { 75 if err := c.GitHubClient.RemoveLabel(org, repo, number, labels.NeedsOkToTest); err != nil { 76 return err 77 } 78 } 79 } 80 } 81 return nil 82 } 83 84 pr, err := c.GitHubClient.GetPullRequest(org, repo, number) 85 if err != nil { 86 return err 87 } 88 89 // Skip untrusted users comments. 90 trusted, err := TrustedUser(c.GitHubClient, trigger, commentAuthor, org, repo) 91 if err != nil { 92 return fmt.Errorf("error checking trust of %s: %v", commentAuthor, err) 93 } 94 var l []github.Label 95 if !trusted { 96 // Skip untrusted PRs. 97 l, trusted, err = TrustedPullRequest(c.GitHubClient, trigger, gc.IssueAuthor.Login, org, repo, number, nil) 98 if err != nil { 99 return err 100 } 101 if !trusted { 102 resp := fmt.Sprintf("Cannot trigger testing until a trusted user reviews the PR and leaves an `/ok-to-test` message.") 103 c.Logger.Infof("Commenting \"%s\".", resp) 104 return c.GitHubClient.CreateComment(org, repo, number, plugins.FormatResponseRaw(gc.Body, gc.HTMLURL, gc.User.Login, resp)) 105 } 106 } 107 108 // At this point we can trust the PR, so we eventually update labels. 109 // Ensure we have labels before test, because TrustedPullRequest() won't be called 110 // when commentAuthor is trusted. 111 if l == nil { 112 l, err = c.GitHubClient.GetIssueLabels(org, repo, number) 113 if err != nil { 114 return err 115 } 116 } 117 if isOkToTest && !github.HasLabel(labels.OkToTest, l) { 118 if err := c.GitHubClient.AddLabel(org, repo, number, labels.OkToTest); err != nil { 119 return err 120 } 121 } 122 if (isOkToTest || github.HasLabel(labels.OkToTest, l)) && github.HasLabel(labels.NeedsOkToTest, l) { 123 if err := c.GitHubClient.RemoveLabel(org, repo, number, labels.NeedsOkToTest); err != nil { 124 return err 125 } 126 } 127 128 // Do we have to run some tests? 129 var forceRunContexts map[string]bool 130 if shouldRetestFailed { 131 combinedStatus, err := c.GitHubClient.GetCombinedStatus(org, repo, pr.Head.SHA) 132 if err != nil { 133 return err 134 } 135 skipContexts := make(map[string]bool) // these succeeded or are running 136 forceRunContexts = make(map[string]bool) // these failed and should be re-run 137 for _, status := range combinedStatus.Statuses { 138 state := status.State 139 if state == github.StatusSuccess || state == github.StatusPending { 140 skipContexts[status.Context] = true 141 } else if state == github.StatusError || state == github.StatusFailure { 142 forceRunContexts[status.Context] = true 143 } 144 } 145 retests := c.Config.RetestPresubmits(gc.Repo.FullName, skipContexts, forceRunContexts) 146 requestedJobs = append(requestedJobs, retests...) 147 } 148 149 return RunOrSkipRequested(c, pr, requestedJobs, forceRunContexts, gc.Body, gc.GUID) 150 }