github.com/abayer/test-infra@v0.0.5/prow/plugins/dog/dog.go (about) 1 /* 2 Copyright 2018 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 dog adds dog images to issues in response to a /woof comment 18 package dog 19 20 import ( 21 "encoding/json" 22 "errors" 23 "fmt" 24 "net/http" 25 "net/url" 26 "regexp" 27 28 "github.com/sirupsen/logrus" 29 30 "k8s.io/test-infra/prow/github" 31 "k8s.io/test-infra/prow/pluginhelp" 32 "k8s.io/test-infra/prow/plugins" 33 ) 34 35 var ( 36 match = regexp.MustCompile(`(?mi)^/(woof|bark)\s*$`) 37 filetypes = regexp.MustCompile(`(?i)\.(jpg|gif|png)$`) 38 ) 39 40 const ( 41 dogURL = realPack("https://random.dog/woof.json") 42 pluginName = "dog" 43 ) 44 45 func init() { 46 plugins.RegisterGenericCommentHandler(pluginName, handleGenericComment, helpProvider) 47 } 48 49 func helpProvider(config *plugins.Configuration, enabledRepos []string) (*pluginhelp.PluginHelp, error) { 50 // The Config field is omitted because this plugin is not configurable. 51 pluginHelp := &pluginhelp.PluginHelp{ 52 Description: "The dog plugin adds a dog image to an issue in response to the `/woof` command.", 53 } 54 pluginHelp.AddCommand(pluginhelp.Command{ 55 Usage: "/(woof|bark)", 56 Description: "Add a dog image to the issue", 57 Featured: false, 58 WhoCanUse: "Anyone", 59 Examples: []string{"/woof", "/bark"}, 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 pack interface { 69 readDog() (string, error) 70 } 71 72 type realPack string 73 74 var client = http.Client{} 75 76 type dogResult struct { 77 URL string `json:"url"` 78 } 79 80 func (dr dogResult) Format() (string, error) { 81 if dr.URL == "" { 82 return "", errors.New("empty url") 83 } 84 src, err := url.ParseRequestURI(dr.URL) 85 if err != nil { 86 return "", fmt.Errorf("invalid url %s: %v", dr.URL, err) 87 } 88 return fmt.Sprintf("[![dog image](%s)](%s)", src, src), nil 89 } 90 91 func (u realPack) readDog() (string, error) { 92 uri := string(u) 93 req, err := http.NewRequest("GET", uri, nil) 94 if err != nil { 95 return "", fmt.Errorf("could not create request %s: %v", uri, err) 96 } 97 req.Header.Add("Accept", "application/json") 98 resp, err := client.Do(req) 99 if err != nil { 100 return "", fmt.Errorf("could not read dog from %s: %v", uri, err) 101 } 102 defer resp.Body.Close() 103 var a dogResult 104 if err = json.NewDecoder(resp.Body).Decode(&a); err != nil { 105 return "", err 106 } 107 // GitHub doesn't support videos :( 108 if !filetypes.MatchString(a.URL) { 109 return "", errors.New("unsupported doggo :( unknown filetype: " + a.URL) 110 } 111 // checking size, GitHub doesn't support big images 112 toobig, err := github.ImageTooBig(a.URL) 113 if err != nil { 114 return "", err 115 } else if toobig { 116 return "", errors.New("unsupported doggo :( size too big: " + a.URL) 117 } 118 return a.Format() 119 } 120 121 func handleGenericComment(pc plugins.PluginClient, e github.GenericCommentEvent) error { 122 return handle(pc.GitHubClient, pc.Logger, &e, dogURL) 123 } 124 125 func handle(gc githubClient, log *logrus.Entry, e *github.GenericCommentEvent, p pack) error { 126 // Only consider new comments. 127 if e.Action != github.GenericCommentActionCreated { 128 return nil 129 } 130 // Make sure they are requesting a dog 131 mat := match.FindStringSubmatch(e.Body) 132 if mat == nil { 133 return nil 134 } 135 136 org := e.Repo.Owner.Login 137 repo := e.Repo.Name 138 number := e.Number 139 140 for i := 0; i < 5; i++ { 141 resp, err := p.readDog() 142 if err != nil { 143 log.WithError(err).Println("Failed to get dog img") 144 continue 145 } 146 return gc.CreateComment(org, repo, number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, resp)) 147 } 148 149 return errors.New("could not find a valid dog image") 150 }