github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/pkg/hook/events.go (about) 1 /* 2 Copyright 2016 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 hook 18 19 import ( 20 "fmt" 21 "runtime/debug" 22 "strconv" 23 "time" 24 25 "github.com/prometheus/client_golang/prometheus" 26 "github.com/sirupsen/logrus" 27 28 "sigs.k8s.io/prow/pkg/github" 29 "sigs.k8s.io/prow/pkg/plugins" 30 ) 31 32 const FailedCommentCoerceFmt = "Could not coerce %s event to a GenericCommentEvent. Unknown 'action': %q." 33 34 const eventTypeField = "event-type" 35 36 var ( 37 nonCommentIssueActions = map[github.IssueEventAction]bool{ 38 github.IssueActionAssigned: true, 39 github.IssueActionUnassigned: true, 40 github.IssueActionLabeled: true, 41 github.IssueActionUnlabeled: true, 42 github.IssueActionMilestoned: true, 43 github.IssueActionDemilestoned: true, 44 github.IssueActionClosed: true, 45 github.IssueActionReopened: true, 46 github.IssueActionPinned: true, 47 github.IssueActionUnpinned: true, 48 github.IssueActionTransferred: true, 49 github.IssueActionDeleted: true, 50 github.IssueActionLocked: true, 51 github.IssueActionUnlocked: true, 52 } 53 nonCommentPullRequestActions = map[github.PullRequestEventAction]bool{ 54 github.PullRequestActionAssigned: true, 55 github.PullRequestActionUnassigned: true, 56 github.PullRequestActionReviewRequested: true, 57 github.PullRequestActionReviewRequestRemoved: true, 58 github.PullRequestActionLabeled: true, 59 github.PullRequestActionUnlabeled: true, 60 github.PullRequestActionClosed: true, 61 github.PullRequestActionReopened: true, 62 github.PullRequestActionSynchronize: true, 63 github.PullRequestActionReadyForReview: true, 64 github.PullRequestActionConvertedToDraft: true, 65 github.PullRequestActionLocked: true, 66 github.PullRequestActionUnlocked: true, 67 github.PullRequestActionAutoMergeEnabled: true, 68 github.PullRequestActionAutoMergeDisabled: true, 69 } 70 ) 71 72 func (s *Server) handleReviewEvent(l *logrus.Entry, re github.ReviewEvent) { 73 defer s.wg.Done() 74 l = l.WithFields(logrus.Fields{ 75 github.OrgLogField: re.Repo.Owner.Login, 76 github.RepoLogField: re.Repo.Name, 77 github.PrLogField: re.PullRequest.Number, 78 "review": re.Review.ID, 79 "reviewer": re.Review.User.Login, 80 "url": re.Review.HTMLURL, 81 }) 82 l.Infof("Review %s.", re.Action) 83 for p, h := range s.Plugins.ReviewEventHandlers(re.PullRequest.Base.Repo.Owner.Login, re.PullRequest.Base.Repo.Name) { 84 s.wg.Add(1) 85 go func(p string, h plugins.ReviewEventHandler) { 86 defer s.wg.Done() 87 agent := plugins.NewAgent(s.ConfigAgent, s.Plugins, s.ClientAgent, re.Repo.Owner.Login, s.Metrics.Metrics, l, p) 88 agent.InitializeCommentPruner( 89 re.Repo.Owner.Login, 90 re.Repo.Name, 91 re.PullRequest.Number, 92 ) 93 start := time.Now() 94 err := errorOnPanic(func() error { return h(agent, re) }) 95 labels := prometheus.Labels{"event_type": l.Data[eventTypeField].(string), "action": string(re.Action), "plugin": p, "took_action": strconv.FormatBool(agent.TookAction())} 96 if err != nil { 97 agent.Logger.WithError(err).Error("Error handling ReviewEvent.") 98 s.Metrics.PluginHandleErrors.With(labels).Inc() 99 } 100 s.Metrics.PluginHandleDuration.With(labels).Observe(time.Since(start).Seconds()) 101 }(p, h) 102 } 103 action := github.GeneralizeCommentAction(string(re.Action)) 104 if action == "" { 105 l.Errorf(FailedCommentCoerceFmt, "pull_request_review", string(re.Action)) 106 return 107 } 108 109 gce, err := github.GeneralizeComment(re) 110 if err != nil { 111 l.Errorln(err) 112 return 113 } 114 115 s.handleGenericComment(l, gce) 116 } 117 118 func (s *Server) handleReviewCommentEvent(l *logrus.Entry, rce github.ReviewCommentEvent) { 119 defer s.wg.Done() 120 l = l.WithFields(logrus.Fields{ 121 github.OrgLogField: rce.Repo.Owner.Login, 122 github.RepoLogField: rce.Repo.Name, 123 github.PrLogField: rce.PullRequest.Number, 124 "review": rce.Comment.ReviewID, 125 "commenter": rce.Comment.User.Login, 126 "url": rce.Comment.HTMLURL, 127 }) 128 l.Infof("Review comment %s.", rce.Action) 129 for p, h := range s.Plugins.ReviewCommentEventHandlers(rce.PullRequest.Base.Repo.Owner.Login, rce.PullRequest.Base.Repo.Name) { 130 s.wg.Add(1) 131 go func(p string, h plugins.ReviewCommentEventHandler) { 132 defer s.wg.Done() 133 agent := plugins.NewAgent(s.ConfigAgent, s.Plugins, s.ClientAgent, rce.Repo.Owner.Login, s.Metrics.Metrics, l, p) 134 agent.InitializeCommentPruner( 135 rce.Repo.Owner.Login, 136 rce.Repo.Name, 137 rce.PullRequest.Number, 138 ) 139 start := time.Now() 140 err := errorOnPanic(func() error { return h(agent, rce) }) 141 labels := prometheus.Labels{"event_type": l.Data[eventTypeField].(string), "action": string(rce.Action), "plugin": p, "took_action": strconv.FormatBool(agent.TookAction())} 142 if err != nil { 143 agent.Logger.WithError(err).Error("Error handling ReviewCommentEvent.") 144 s.Metrics.PluginHandleErrors.With(labels).Inc() 145 } 146 s.Metrics.PluginHandleDuration.With(labels).Observe(time.Since(start).Seconds()) 147 }(p, h) 148 } 149 action := github.GeneralizeCommentAction(string(rce.Action)) 150 if action == "" { 151 l.Errorf(FailedCommentCoerceFmt, "pull_request_review_comment", string(rce.Action)) 152 return 153 } 154 155 gce, err := github.GeneralizeComment(rce) 156 if err != nil { 157 l.Errorln(err) 158 return 159 } 160 161 s.handleGenericComment(l, gce) 162 } 163 164 func (s *Server) handlePullRequestEvent(l *logrus.Entry, pr github.PullRequestEvent) { 165 defer s.wg.Done() 166 l = l.WithFields(logrus.Fields{ 167 github.OrgLogField: pr.Repo.Owner.Login, 168 github.RepoLogField: pr.Repo.Name, 169 github.PrLogField: pr.Number, 170 "author": pr.PullRequest.User.Login, 171 "url": pr.PullRequest.HTMLURL, 172 }) 173 l.Infof("Pull request %s.", pr.Action) 174 for p, h := range s.Plugins.PullRequestHandlers(pr.PullRequest.Base.Repo.Owner.Login, pr.PullRequest.Base.Repo.Name) { 175 s.wg.Add(1) 176 go func(p string, h plugins.PullRequestHandler) { 177 defer s.wg.Done() 178 agent := plugins.NewAgent(s.ConfigAgent, s.Plugins, s.ClientAgent, pr.Repo.Owner.Login, s.Metrics.Metrics, l, p) 179 agent.InitializeCommentPruner( 180 pr.Repo.Owner.Login, 181 pr.Repo.Name, 182 pr.PullRequest.Number, 183 ) 184 start := time.Now() 185 err := errorOnPanic(func() error { return h(agent, pr) }) 186 labels := prometheus.Labels{"event_type": l.Data[eventTypeField].(string), "action": string(pr.Action), "plugin": p, "took_action": strconv.FormatBool(agent.TookAction())} 187 if err != nil { 188 agent.Logger.WithError(err).Error("Error handling PullRequestEvent.") 189 s.Metrics.PluginHandleErrors.With(labels).Inc() 190 } 191 s.Metrics.PluginHandleDuration.With(labels).Observe(time.Since(start).Seconds()) 192 }(p, h) 193 } 194 action := github.GeneralizeCommentAction(string(pr.Action)) 195 if action == "" { 196 if !nonCommentPullRequestActions[pr.Action] { 197 l.Infof(FailedCommentCoerceFmt, "pull_request", string(pr.Action)) 198 } 199 return 200 } 201 202 gce, err := github.GeneralizeComment(pr) 203 if err != nil { 204 l.Errorln(err) 205 return 206 } 207 208 s.handleGenericComment(l, gce) 209 } 210 211 func (s *Server) handlePushEvent(l *logrus.Entry, pe github.PushEvent) { 212 defer s.wg.Done() 213 l = l.WithFields(logrus.Fields{ 214 github.OrgLogField: pe.Repo.Owner.Name, 215 github.RepoLogField: pe.Repo.Name, 216 "ref": pe.Ref, 217 "head": pe.After, 218 }) 219 l.Info("Push event.") 220 for p, h := range s.Plugins.PushEventHandlers(pe.Repo.Owner.Name, pe.Repo.Name) { 221 s.wg.Add(1) 222 go func(p string, h plugins.PushEventHandler) { 223 defer s.wg.Done() 224 agent := plugins.NewAgent(s.ConfigAgent, s.Plugins, s.ClientAgent, pe.Repo.Owner.Login, s.Metrics.Metrics, l, p) 225 start := time.Now() 226 err := errorOnPanic(func() error { return h(agent, pe) }) 227 labels := prometheus.Labels{"event_type": l.Data[eventTypeField].(string), "action": "none", "plugin": p, "took_action": strconv.FormatBool(agent.TookAction())} 228 if err != nil { 229 agent.Logger.WithError(err).Error("Error handling PushEvent.") 230 s.Metrics.PluginHandleErrors.With(labels).Inc() 231 } 232 s.Metrics.PluginHandleDuration.With(labels).Observe(time.Since(start).Seconds()) 233 }(p, h) 234 } 235 } 236 237 func (s *Server) handleIssueEvent(l *logrus.Entry, i github.IssueEvent) { 238 defer s.wg.Done() 239 l = l.WithFields(logrus.Fields{ 240 github.OrgLogField: i.Repo.Owner.Login, 241 github.RepoLogField: i.Repo.Name, 242 github.PrLogField: i.Issue.Number, 243 "author": i.Issue.User.Login, 244 "url": i.Issue.HTMLURL, 245 }) 246 l.Infof("Issue %s.", i.Action) 247 for p, h := range s.Plugins.IssueHandlers(i.Repo.Owner.Login, i.Repo.Name) { 248 s.wg.Add(1) 249 go func(p string, h plugins.IssueHandler) { 250 defer s.wg.Done() 251 agent := plugins.NewAgent(s.ConfigAgent, s.Plugins, s.ClientAgent, i.Repo.Owner.Login, s.Metrics.Metrics, l, p) 252 agent.InitializeCommentPruner( 253 i.Repo.Owner.Login, 254 i.Repo.Name, 255 i.Issue.Number, 256 ) 257 start := time.Now() 258 err := errorOnPanic(func() error { return h(agent, i) }) 259 labels := prometheus.Labels{"event_type": l.Data[eventTypeField].(string), "action": string(i.Action), "plugin": p, "took_action": strconv.FormatBool(agent.TookAction())} 260 if err != nil { 261 agent.Logger.WithError(err).Error("Error handling IssueEvent.") 262 s.Metrics.PluginHandleErrors.With(labels).Inc() 263 } 264 s.Metrics.PluginHandleDuration.With(labels).Observe(time.Since(start).Seconds()) 265 }(p, h) 266 } 267 action := github.GeneralizeCommentAction(string(i.Action)) 268 if action == "" { 269 if !nonCommentIssueActions[i.Action] { 270 l.Errorf(FailedCommentCoerceFmt, "issues", string(i.Action)) 271 } 272 return 273 } 274 275 gce, err := github.GeneralizeComment(i) 276 if err != nil { 277 l.Errorln(err) 278 return 279 } 280 281 s.handleGenericComment(l, gce) 282 } 283 284 func (s *Server) handleIssueCommentEvent(l *logrus.Entry, ic github.IssueCommentEvent) { 285 defer s.wg.Done() 286 l = l.WithFields(logrus.Fields{ 287 github.OrgLogField: ic.Repo.Owner.Login, 288 github.RepoLogField: ic.Repo.Name, 289 github.PrLogField: ic.Issue.Number, 290 "author": ic.Comment.User.Login, 291 "url": ic.Comment.HTMLURL, 292 }) 293 l.Infof("Issue comment %s.", ic.Action) 294 for p, h := range s.Plugins.IssueCommentHandlers(ic.Repo.Owner.Login, ic.Repo.Name) { 295 s.wg.Add(1) 296 go func(p string, h plugins.IssueCommentHandler) { 297 defer s.wg.Done() 298 agent := plugins.NewAgent(s.ConfigAgent, s.Plugins, s.ClientAgent, ic.Repo.Owner.Login, s.Metrics.Metrics, l, p) 299 agent.InitializeCommentPruner( 300 ic.Repo.Owner.Login, 301 ic.Repo.Name, 302 ic.Issue.Number, 303 ) 304 start := time.Now() 305 err := errorOnPanic(func() error { return h(agent, ic) }) 306 labels := prometheus.Labels{"event_type": l.Data[eventTypeField].(string), "action": string(ic.Action), "plugin": p, "took_action": strconv.FormatBool(agent.TookAction())} 307 if err != nil { 308 agent.Logger.WithError(err).Error("Error handling IssueCommentEvent.") 309 s.Metrics.PluginHandleErrors.With(labels).Inc() 310 } 311 s.Metrics.PluginHandleDuration.With(labels).Observe(time.Since(start).Seconds()) 312 }(p, h) 313 } 314 action := github.GeneralizeCommentAction(string(ic.Action)) 315 if action == "" { 316 l.Errorf(FailedCommentCoerceFmt, "issue_comment", string(ic.Action)) 317 return 318 } 319 320 gce, err := github.GeneralizeComment(ic) 321 if err != nil { 322 l.Errorln(err) 323 return 324 } 325 326 s.handleGenericComment(l, gce) 327 } 328 329 func (s *Server) handleStatusEvent(l *logrus.Entry, se github.StatusEvent) { 330 defer s.wg.Done() 331 l = l.WithFields(logrus.Fields{ 332 github.OrgLogField: se.Repo.Owner.Login, 333 github.RepoLogField: se.Repo.Name, 334 "context": se.Context, 335 "sha": se.SHA, 336 "state": se.State, 337 "id": se.ID, 338 }) 339 l.Infof("Status description %s.", se.Description) 340 for p, h := range s.Plugins.StatusEventHandlers(se.Repo.Owner.Login, se.Repo.Name) { 341 s.wg.Add(1) 342 go func(p string, h plugins.StatusEventHandler) { 343 defer s.wg.Done() 344 agent := plugins.NewAgent(s.ConfigAgent, s.Plugins, s.ClientAgent, se.Repo.Owner.Login, s.Metrics.Metrics, l, p) 345 start := time.Now() 346 err := errorOnPanic(func() error { return h(agent, se) }) 347 labels := prometheus.Labels{"event_type": l.Data[eventTypeField].(string), "action": "none", "plugin": p, "took_action": strconv.FormatBool(agent.TookAction())} 348 if err != nil { 349 agent.Logger.WithError(err).Error("Error handling StatusEvent.") 350 s.Metrics.PluginHandleErrors.With(labels).Inc() 351 } 352 s.Metrics.PluginHandleDuration.With(labels).Observe(time.Since(start).Seconds()) 353 }(p, h) 354 } 355 } 356 357 func (s *Server) handleGenericComment(l *logrus.Entry, ce *github.GenericCommentEvent) { 358 for p, h := range s.Plugins.GenericCommentHandlers(ce.Repo.Owner.Login, ce.Repo.Name) { 359 s.wg.Add(1) 360 go func(p string, h plugins.GenericCommentHandler) { 361 defer s.wg.Done() 362 agent := plugins.NewAgent(s.ConfigAgent, s.Plugins, s.ClientAgent, ce.Repo.Owner.Login, s.Metrics.Metrics, l, p) 363 agent.InitializeCommentPruner( 364 ce.Repo.Owner.Login, 365 ce.Repo.Name, 366 ce.Number, 367 ) 368 start := time.Now() 369 err := errorOnPanic(func() error { return h(agent, *ce) }) 370 labels := prometheus.Labels{"event_type": l.Data[eventTypeField].(string), "action": string(ce.Action), "plugin": p, "took_action": strconv.FormatBool(agent.TookAction())} 371 if err != nil { 372 agent.Logger.WithError(err).Error("Error handling GenericCommentEvent.") 373 s.Metrics.PluginHandleErrors.With(labels).Inc() 374 } 375 s.Metrics.PluginHandleDuration.With(labels).Observe(time.Since(start).Seconds()) 376 }(p, h) 377 } 378 } 379 380 func errorOnPanic(f func() error) (err error) { 381 defer func() { 382 if r := recover(); r != nil { 383 err = fmt.Errorf("panic caught: %v. stack is: %s", r, debug.Stack()) 384 } 385 }() 386 return f() 387 }