k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/robots/pr-creator/updater/updater.go (about) 1 /* 2 Copyright 2019 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 updater 18 19 import ( 20 "fmt" 21 22 "github.com/sirupsen/logrus" 23 24 "sigs.k8s.io/prow/pkg/github" 25 ) 26 27 // Indicates whether maintainers can modify a pull request in fork. 28 const ( 29 AllowMods = true 30 PreventMods = false 31 ) 32 33 type updateClient interface { 34 UpdatePullRequest(org, repo string, number int, title, body *string, open *bool, branch *string, canModify *bool) error 35 BotUser() (*github.UserData, error) 36 FindIssues(query, sort string, asc bool) ([]github.Issue, error) 37 } 38 39 type ensureClient interface { 40 updateClient 41 AddLabel(org, repo string, number int, label string) error 42 CreatePullRequest(org, repo, title, body, head, base string, canModify bool) (int, error) 43 GetIssue(org, repo string, number int) (*github.Issue, error) 44 } 45 46 func UpdatePR(org, repo, title, body, headBranch string, gc updateClient) (*int, error) { 47 return updatePRWithQueryTokens(org, repo, title, body, "head:"+headBranch, gc) 48 } 49 50 func EnsurePR(org, repo, title, body, source, branch, headBranch string, allowMods bool, gc ensureClient) (*int, error) { 51 return EnsurePRWithLabels(org, repo, title, body, source, branch, headBranch, allowMods, gc, nil) 52 } 53 54 func EnsurePRWithQueryTokens(org, repo, title, body, source, baseBranch, queryTokensString string, allowMods bool, gc ensureClient) (*int, error) { 55 n, err := updatePRWithQueryTokens(org, repo, title, body, queryTokensString, gc) 56 if err != nil { 57 return nil, fmt.Errorf("update error: %w", err) 58 } 59 if n == nil { 60 pr, err := gc.CreatePullRequest(org, repo, title, body, source, baseBranch, allowMods) 61 if err != nil { 62 return nil, fmt.Errorf("create error: %w", err) 63 } 64 n = &pr 65 } 66 67 return n, nil 68 } 69 70 func updatePRWithQueryTokens(org, repo, title, body, queryTokensString string, gc updateClient) (*int, error) { 71 logrus.Info("Looking for a PR to reuse...") 72 me, err := gc.BotUser() 73 if err != nil { 74 return nil, fmt.Errorf("bot name: %w", err) 75 } 76 77 issues, err := gc.FindIssues(fmt.Sprintf("is:open is:pr archived:false repo:%s/%s author:%s %s", org, repo, me.Login, queryTokensString), "updated", false) 78 if err != nil { 79 return nil, fmt.Errorf("find issues: %w", err) 80 } else if len(issues) == 0 { 81 logrus.Info("No reusable issues found") 82 return nil, nil 83 } 84 n := issues[0].Number 85 logrus.Infof("Found %d", n) 86 var ignoreOpen *bool 87 var ignoreBranch *string 88 var ignoreModify *bool 89 if err := gc.UpdatePullRequest(org, repo, n, &title, &body, ignoreOpen, ignoreBranch, ignoreModify); err != nil { 90 return nil, fmt.Errorf("update %d: %w", n, err) 91 } 92 93 return &n, nil 94 } 95 96 func EnsurePRWithLabels(org, repo, title, body, source, baseBranch, headBranch string, allowMods bool, gc ensureClient, labels []string) (*int, error) { 97 return EnsurePRWithQueryTokensAndLabels(org, repo, title, body, source, baseBranch, "head:"+headBranch, allowMods, labels, gc) 98 } 99 100 func EnsurePRWithQueryTokensAndLabels(org, repo, title, body, source, baseBranch, queryTokensString string, allowMods bool, labels []string, gc ensureClient) (*int, error) { 101 n, err := EnsurePRWithQueryTokens(org, repo, title, body, source, baseBranch, queryTokensString, allowMods, gc) 102 if err != nil { 103 return n, err 104 } 105 106 if len(labels) == 0 { 107 return n, nil 108 } 109 110 issue, err := gc.GetIssue(org, repo, *n) 111 if err != nil { 112 return n, fmt.Errorf("failed to get PR: %w", err) 113 } 114 115 for _, label := range labels { 116 if issue.HasLabel(label) { 117 continue 118 } 119 120 if err := gc.AddLabel(org, repo, *n, label); err != nil { 121 return n, fmt.Errorf("failed to add label %q: %w", label, err) 122 } 123 logrus.WithField("label", label).Info("Added label") 124 } 125 return n, nil 126 }