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("![candy image](%s)", 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  }