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