github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/pkg/plugins/trick-or-treat/trick-or-treat.go (about) 1 /* 2 Copyright 2020 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 trickortreat adds halloween images to an issue or PR in response to a /trick-or-treat comment 18 package trickortreat 19 20 import ( 21 "errors" 22 "fmt" 23 "math/rand" 24 "regexp" 25 "time" 26 27 "github.com/sirupsen/logrus" 28 29 "sigs.k8s.io/prow/pkg/config" 30 "sigs.k8s.io/prow/pkg/github" 31 "sigs.k8s.io/prow/pkg/pluginhelp" 32 "sigs.k8s.io/prow/pkg/plugins" 33 ) 34 35 var ( 36 match = regexp.MustCompile(`(?mi)^/trick(\-)?or(\-)?treat(?: (.+))?\s*$`) 37 trickOrTreat realSnicker 38 ) 39 40 const ( 41 pluginName = "trick-or-treat" 42 ) 43 44 func init() { 45 plugins.RegisterGenericCommentHandler(pluginName, handleGenericComment, helpProvider) 46 } 47 48 func helpProvider(config *plugins.Configuration, _ []config.OrgRepo) (*pluginhelp.PluginHelp, error) { 49 pluginHelp := &pluginhelp.PluginHelp{ 50 Description: "The trick-or-treat plugin adds a candy image to an issue or PR in response to the `/trick-or-treat` command.", 51 Config: map[string]string{}, 52 Snippet: "", 53 } 54 pluginHelp.AddCommand(pluginhelp.Command{ 55 Usage: "/trick(-)or(-)treat", 56 Description: "Add a candy image to the issue or PR", 57 Featured: false, 58 WhoCanUse: "Anyone", 59 Examples: []string{"/trick-or-treat", "/trickortreat"}, 60 }) 61 return pluginHelp, nil 62 } 63 64 type githubClient interface { 65 CreateComment(owner, repo string, number int, comment string) error 66 } 67 68 type snicker interface { 69 readImage(*logrus.Entry) (string, error) 70 } 71 72 type realSnicker struct { 73 } 74 75 func (c *realSnicker) readImage(log *logrus.Entry) (string, error) { 76 var imgURL string 77 var err error 78 var tooBig bool 79 for i := 0; i < 3; i++ { 80 imgIndex := rand.Intn(len(candiesImgs)) 81 imgURL = candiesImgs[imgIndex] 82 // checking size, GitHub doesn't support big images 83 tooBig, err = github.ImageTooBig(imgURL) 84 if err != nil { // Retry another image 85 continue 86 } 87 if tooBig { // Retry another image 88 err = errors.New("image too big") 89 continue 90 } 91 return fmt.Sprintf("", imgURL), nil 92 } 93 94 log.WithError(err).WithField("img-url", imgURL).Debug("Failed to read image.") 95 return "", err 96 } 97 98 func handleGenericComment(pc plugins.Agent, e github.GenericCommentEvent) error { 99 return handle( 100 pc.GitHubClient, 101 pc.Logger, 102 &e, 103 &trickOrTreat, 104 ) 105 } 106 107 func handle(gc githubClient, log *logrus.Entry, e *github.GenericCommentEvent, c snicker) error { 108 // Only consider new comments. 109 if e.Action != github.GenericCommentActionCreated { 110 return nil 111 } 112 // Make sure they are requesting a cat 113 if mat := match.FindStringSubmatch(e.Body); mat == nil { 114 return nil 115 } 116 117 org := e.Repo.Owner.Login 118 repo := e.Repo.Name 119 number := e.Number 120 interval := 200 * time.Microsecond 121 for i := 0; i < 3; i++ { 122 imgURL, err := c.readImage(log) 123 if err != nil { 124 log.WithError(err).Error("Failed to get img") 125 time.Sleep(interval) 126 continue 127 } 128 return gc.CreateComment(org, repo, number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, imgURL)) 129 } 130 131 return errors.New("could not find a valid candy image") 132 }