github.com/abayer/test-infra@v0.0.5/prow/plugins/yuks/yuks.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 yuks
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  	"net/http"
    24  	"regexp"
    25  
    26  	"github.com/sirupsen/logrus"
    27  
    28  	"k8s.io/test-infra/prow/github"
    29  	"k8s.io/test-infra/prow/pluginhelp"
    30  	"k8s.io/test-infra/prow/plugins"
    31  )
    32  
    33  var (
    34  	match  = regexp.MustCompile(`(?mi)^/joke\s*$`)
    35  	simple = regexp.MustCompile(`^[\w?'!., ]+$`)
    36  )
    37  
    38  const (
    39  	// Previously: https://tambal.azurewebsites.net/joke/random
    40  	jokeURL    = realJoke("https://icanhazdadjoke.com")
    41  	pluginName = "yuks"
    42  )
    43  
    44  func init() {
    45  	plugins.RegisterGenericCommentHandler(pluginName, handleGenericComment, helpProvider)
    46  }
    47  
    48  func helpProvider(config *plugins.Configuration, enabledRepos []string) (*pluginhelp.PluginHelp, error) {
    49  	// The Config field is omitted because this plugin is not configurable.
    50  	pluginHelp := &pluginhelp.PluginHelp{
    51  		Description: "The yuks plugin comments with jokes in response to the `/joke` command.",
    52  	}
    53  	pluginHelp.AddCommand(pluginhelp.Command{
    54  		Usage:       "/joke",
    55  		Description: "Tells a joke.",
    56  		Featured:    false,
    57  		WhoCanUse:   "Anyone can use the `/joke` command.",
    58  		Examples:    []string{"/joke"},
    59  	})
    60  	return pluginHelp, nil
    61  }
    62  
    63  type githubClient interface {
    64  	CreateComment(owner, repo string, number int, comment string) error
    65  }
    66  
    67  type joker interface {
    68  	readJoke() (string, error)
    69  }
    70  
    71  type realJoke string
    72  
    73  var client = http.Client{}
    74  
    75  type jokeResult struct {
    76  	Joke string `json:"joke"`
    77  }
    78  
    79  func (url realJoke) readJoke() (string, error) {
    80  	req, err := http.NewRequest("GET", string(url), nil)
    81  	if err != nil {
    82  		return "", fmt.Errorf("could not create request %s: %v", url, err)
    83  	}
    84  	req.Header.Add("Accept", "application/json")
    85  	resp, err := client.Do(req)
    86  	if err != nil {
    87  		return "", fmt.Errorf("could not read joke from %s: %v", url, err)
    88  	}
    89  	defer resp.Body.Close()
    90  	var a jokeResult
    91  	if err = json.NewDecoder(resp.Body).Decode(&a); err != nil {
    92  		return "", err
    93  	}
    94  	if a.Joke == "" {
    95  		return "", fmt.Errorf("result from %s did not contain a joke", url)
    96  	}
    97  	return a.Joke, nil
    98  }
    99  
   100  func handleGenericComment(pc plugins.PluginClient, e github.GenericCommentEvent) error {
   101  	return handle(pc.GitHubClient, pc.Logger, &e, jokeURL)
   102  }
   103  
   104  func handle(gc githubClient, log *logrus.Entry, e *github.GenericCommentEvent, j joker) error {
   105  	// Only consider new comments.
   106  	if e.Action != github.GenericCommentActionCreated {
   107  		return nil
   108  	}
   109  	// Make sure they are requesting a joke
   110  	if !match.MatchString(e.Body) {
   111  		return nil
   112  	}
   113  
   114  	org := e.Repo.Owner.Login
   115  	repo := e.Repo.Name
   116  	number := e.Number
   117  
   118  	for i := 0; i < 10; i++ {
   119  		resp, err := j.readJoke()
   120  		if err != nil {
   121  			return err
   122  		}
   123  		if simple.MatchString(resp) {
   124  			log.Infof("Commenting with \"%s\".", resp)
   125  			return gc.CreateComment(org, repo, number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, resp))
   126  		}
   127  
   128  		log.Errorf("joke contains invalid characters: %v", resp)
   129  	}
   130  
   131  	return errors.New("all 10 jokes contain invalid character... such an unlucky day")
   132  }