github.com/abayer/test-infra@v0.0.5/prow/plugins/wip/wip-label.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 wip will label a PR a work-in-progress if the author provides 18 // a prefix to their pull request title to the same effect. The submit- 19 // queue will not merge pull requests with the work-in-progress label. 20 // The label will be removed when the title changes to no longer begin 21 // with the prefix. 22 package wip 23 24 import ( 25 "fmt" 26 "regexp" 27 28 "github.com/sirupsen/logrus" 29 30 "k8s.io/test-infra/prow/github" 31 "k8s.io/test-infra/prow/pluginhelp" 32 "k8s.io/test-infra/prow/plugins" 33 ) 34 35 const ( 36 label = "do-not-merge/work-in-progress" 37 pluginName = "wip" 38 ) 39 40 var ( 41 titleRegex = regexp.MustCompile(`(?i)^\W?WIP\W`) 42 ) 43 44 type event struct { 45 org string 46 repo string 47 number int 48 hasLabel bool 49 needsLabel bool 50 } 51 52 func init() { 53 plugins.RegisterPullRequestHandler(pluginName, handlePullRequest, helpProvider) 54 } 55 56 func helpProvider(config *plugins.Configuration, enabledRepos []string) (*pluginhelp.PluginHelp, error) { 57 // Only the Description field is specified because this plugin is not triggered with commands and is not configurable. 58 return &pluginhelp.PluginHelp{ 59 Description: "The wip (Work In Progress) plugin applies the '" + label + "' label to pull requests whose title starts with 'WIP' and removes it from pull requests when they remove the title prefix. The '" + label + "' label is typically used to block a pull request from merging while it is still in progress.", 60 }, 61 nil 62 } 63 64 // Strict subset of *github.Client methods. 65 type githubClient interface { 66 GetIssueLabels(org, repo string, number int) ([]github.Label, error) 67 AddLabel(owner, repo string, number int, label string) error 68 RemoveLabel(owner, repo string, number int, label string) error 69 } 70 71 func handlePullRequest(pc plugins.PluginClient, pe github.PullRequestEvent) error { 72 // These are the only actions indicating the PR title may have changed. 73 if pe.Action != github.PullRequestActionOpened && 74 pe.Action != github.PullRequestActionReopened && 75 pe.Action != github.PullRequestActionEdited { 76 return nil 77 } 78 79 var ( 80 org = pe.PullRequest.Base.Repo.Owner.Login 81 repo = pe.PullRequest.Base.Repo.Name 82 number = pe.PullRequest.Number 83 title = pe.PullRequest.Title 84 ) 85 86 currentLabels, err := pc.GitHubClient.GetIssueLabels(org, repo, number) 87 if err != nil { 88 return fmt.Errorf("could not get labels for PR %s/%s:%d in WIP plugin: %v", org, repo, number, err) 89 } 90 hasLabel := false 91 for _, l := range currentLabels { 92 if l.Name == label { 93 hasLabel = true 94 } 95 } 96 97 needsLabel := titleRegex.MatchString(title) 98 99 e := &event{ 100 org: org, 101 repo: repo, 102 number: number, 103 hasLabel: hasLabel, 104 needsLabel: needsLabel, 105 } 106 return handle(pc.GitHubClient, pc.Logger, e) 107 } 108 109 // handle interacts with GitHub to drive the pull request to the 110 // proper state by adding and removing comments and labels. If a 111 // PR has a WIP prefix, it needs an explanatory comment and label. 112 // Otherwise, neither should be present. 113 func handle(gc githubClient, le *logrus.Entry, e *event) error { 114 if e.needsLabel && !e.hasLabel { 115 if err := gc.AddLabel(e.org, e.repo, e.number, label); err != nil { 116 le.Warnf("error while adding label %q: %v", label, err) 117 return err 118 } 119 } else if !e.needsLabel && e.hasLabel { 120 if err := gc.RemoveLabel(e.org, e.repo, e.number, label); err != nil { 121 le.Warnf("error while removing label %q: %v", label, err) 122 return err 123 } 124 } 125 return nil 126 }