code.gitea.io/gitea@v1.21.7/services/webhook/notifier.go (about) 1 // Copyright 2019 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package webhook 5 6 import ( 7 "context" 8 9 issues_model "code.gitea.io/gitea/models/issues" 10 packages_model "code.gitea.io/gitea/models/packages" 11 "code.gitea.io/gitea/models/perm" 12 access_model "code.gitea.io/gitea/models/perm/access" 13 repo_model "code.gitea.io/gitea/models/repo" 14 user_model "code.gitea.io/gitea/models/user" 15 "code.gitea.io/gitea/modules/git" 16 "code.gitea.io/gitea/modules/log" 17 "code.gitea.io/gitea/modules/repository" 18 "code.gitea.io/gitea/modules/setting" 19 api "code.gitea.io/gitea/modules/structs" 20 webhook_module "code.gitea.io/gitea/modules/webhook" 21 "code.gitea.io/gitea/services/convert" 22 notify_service "code.gitea.io/gitea/services/notify" 23 ) 24 25 func init() { 26 notify_service.RegisterNotifier(&webhookNotifier{}) 27 } 28 29 type webhookNotifier struct { 30 notify_service.NullNotifier 31 } 32 33 var _ notify_service.Notifier = &webhookNotifier{} 34 35 // NewNotifier create a new webhookNotifier notifier 36 func NewNotifier() notify_service.Notifier { 37 return &webhookNotifier{} 38 } 39 40 func (m *webhookNotifier) IssueClearLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) { 41 if err := issue.LoadPoster(ctx); err != nil { 42 log.Error("LoadPoster: %v", err) 43 return 44 } 45 46 if err := issue.LoadRepo(ctx); err != nil { 47 log.Error("LoadRepo: %v", err) 48 return 49 } 50 51 permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster) 52 var err error 53 if issue.IsPull { 54 if err = issue.LoadPullRequest(ctx); err != nil { 55 log.Error("LoadPullRequest: %v", err) 56 return 57 } 58 59 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestLabel, &api.PullRequestPayload{ 60 Action: api.HookIssueLabelCleared, 61 Index: issue.Index, 62 PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), 63 Repository: convert.ToRepo(ctx, issue.Repo, permission), 64 Sender: convert.ToUser(ctx, doer, nil), 65 }) 66 } else { 67 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ 68 Action: api.HookIssueLabelCleared, 69 Index: issue.Index, 70 Issue: convert.ToAPIIssue(ctx, issue), 71 Repository: convert.ToRepo(ctx, issue.Repo, permission), 72 Sender: convert.ToUser(ctx, doer, nil), 73 }) 74 } 75 if err != nil { 76 log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) 77 } 78 } 79 80 func (m *webhookNotifier) ForkRepository(ctx context.Context, doer *user_model.User, oldRepo, repo *repo_model.Repository) { 81 oldPermission, _ := access_model.GetUserRepoPermission(ctx, oldRepo, doer) 82 permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer) 83 84 // forked webhook 85 if err := PrepareWebhooks(ctx, EventSource{Repository: oldRepo}, webhook_module.HookEventFork, &api.ForkPayload{ 86 Forkee: convert.ToRepo(ctx, oldRepo, oldPermission), 87 Repo: convert.ToRepo(ctx, repo, permission), 88 Sender: convert.ToUser(ctx, doer, nil), 89 }); err != nil { 90 log.Error("PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err) 91 } 92 93 u := repo.MustOwner(ctx) 94 95 // Add to hook queue for created repo after session commit. 96 if u.IsOrganization() { 97 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ 98 Action: api.HookRepoCreated, 99 Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 100 Organization: convert.ToUser(ctx, u, nil), 101 Sender: convert.ToUser(ctx, doer, nil), 102 }); err != nil { 103 log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) 104 } 105 } 106 } 107 108 func (m *webhookNotifier) CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { 109 // Add to hook queue for created repo after session commit. 110 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ 111 Action: api.HookRepoCreated, 112 Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 113 Organization: convert.ToUser(ctx, u, nil), 114 Sender: convert.ToUser(ctx, doer, nil), 115 }); err != nil { 116 log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) 117 } 118 } 119 120 func (m *webhookNotifier) DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) { 121 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ 122 Action: api.HookRepoDeleted, 123 Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 124 Organization: convert.ToUser(ctx, repo.MustOwner(ctx), nil), 125 Sender: convert.ToUser(ctx, doer, nil), 126 }); err != nil { 127 log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) 128 } 129 } 130 131 func (m *webhookNotifier) MigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { 132 // Add to hook queue for created repo after session commit. 133 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ 134 Action: api.HookRepoCreated, 135 Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 136 Organization: convert.ToUser(ctx, u, nil), 137 Sender: convert.ToUser(ctx, doer, nil), 138 }); err != nil { 139 log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) 140 } 141 } 142 143 func (m *webhookNotifier) IssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) { 144 if issue.IsPull { 145 permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) 146 147 if err := issue.LoadPullRequest(ctx); err != nil { 148 log.Error("LoadPullRequest failed: %v", err) 149 return 150 } 151 apiPullRequest := &api.PullRequestPayload{ 152 Index: issue.Index, 153 PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), 154 Repository: convert.ToRepo(ctx, issue.Repo, permission), 155 Sender: convert.ToUser(ctx, doer, nil), 156 } 157 if removed { 158 apiPullRequest.Action = api.HookIssueUnassigned 159 } else { 160 apiPullRequest.Action = api.HookIssueAssigned 161 } 162 // Assignee comment triggers a webhook 163 if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestAssign, apiPullRequest); err != nil { 164 log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err) 165 return 166 } 167 } else { 168 permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) 169 apiIssue := &api.IssuePayload{ 170 Index: issue.Index, 171 Issue: convert.ToAPIIssue(ctx, issue), 172 Repository: convert.ToRepo(ctx, issue.Repo, permission), 173 Sender: convert.ToUser(ctx, doer, nil), 174 } 175 if removed { 176 apiIssue.Action = api.HookIssueUnassigned 177 } else { 178 apiIssue.Action = api.HookIssueAssigned 179 } 180 // Assignee comment triggers a webhook 181 if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueAssign, apiIssue); err != nil { 182 log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err) 183 return 184 } 185 } 186 } 187 188 func (m *webhookNotifier) IssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) { 189 permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster) 190 var err error 191 if issue.IsPull { 192 if err = issue.LoadPullRequest(ctx); err != nil { 193 log.Error("LoadPullRequest failed: %v", err) 194 return 195 } 196 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequest, &api.PullRequestPayload{ 197 Action: api.HookIssueEdited, 198 Index: issue.Index, 199 Changes: &api.ChangesPayload{ 200 Title: &api.ChangesFromPayload{ 201 From: oldTitle, 202 }, 203 }, 204 PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), 205 Repository: convert.ToRepo(ctx, issue.Repo, permission), 206 Sender: convert.ToUser(ctx, doer, nil), 207 }) 208 } else { 209 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ 210 Action: api.HookIssueEdited, 211 Index: issue.Index, 212 Changes: &api.ChangesPayload{ 213 Title: &api.ChangesFromPayload{ 214 From: oldTitle, 215 }, 216 }, 217 Issue: convert.ToAPIIssue(ctx, issue), 218 Repository: convert.ToRepo(ctx, issue.Repo, permission), 219 Sender: convert.ToUser(ctx, doer, nil), 220 }) 221 } 222 223 if err != nil { 224 log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) 225 } 226 } 227 228 func (m *webhookNotifier) IssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { 229 permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster) 230 var err error 231 if issue.IsPull { 232 if err = issue.LoadPullRequest(ctx); err != nil { 233 log.Error("LoadPullRequest: %v", err) 234 return 235 } 236 // Merge pull request calls issue.changeStatus so we need to handle separately. 237 apiPullRequest := &api.PullRequestPayload{ 238 Index: issue.Index, 239 PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), 240 Repository: convert.ToRepo(ctx, issue.Repo, permission), 241 Sender: convert.ToUser(ctx, doer, nil), 242 CommitID: commitID, 243 } 244 if isClosed { 245 apiPullRequest.Action = api.HookIssueClosed 246 } else { 247 apiPullRequest.Action = api.HookIssueReOpened 248 } 249 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequest, apiPullRequest) 250 } else { 251 apiIssue := &api.IssuePayload{ 252 Index: issue.Index, 253 Issue: convert.ToAPIIssue(ctx, issue), 254 Repository: convert.ToRepo(ctx, issue.Repo, permission), 255 Sender: convert.ToUser(ctx, doer, nil), 256 CommitID: commitID, 257 } 258 if isClosed { 259 apiIssue.Action = api.HookIssueClosed 260 } else { 261 apiIssue.Action = api.HookIssueReOpened 262 } 263 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, apiIssue) 264 } 265 if err != nil { 266 log.Error("PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err) 267 } 268 } 269 270 func (m *webhookNotifier) NewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) { 271 if err := issue.LoadRepo(ctx); err != nil { 272 log.Error("issue.LoadRepo: %v", err) 273 return 274 } 275 if err := issue.LoadPoster(ctx); err != nil { 276 log.Error("issue.LoadPoster: %v", err) 277 return 278 } 279 280 permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster) 281 if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ 282 Action: api.HookIssueOpened, 283 Index: issue.Index, 284 Issue: convert.ToAPIIssue(ctx, issue), 285 Repository: convert.ToRepo(ctx, issue.Repo, permission), 286 Sender: convert.ToUser(ctx, issue.Poster, nil), 287 }); err != nil { 288 log.Error("PrepareWebhooks: %v", err) 289 } 290 } 291 292 func (m *webhookNotifier) NewPullRequest(ctx context.Context, pull *issues_model.PullRequest, mentions []*user_model.User) { 293 if err := pull.LoadIssue(ctx); err != nil { 294 log.Error("pull.LoadIssue: %v", err) 295 return 296 } 297 if err := pull.Issue.LoadRepo(ctx); err != nil { 298 log.Error("pull.Issue.LoadRepo: %v", err) 299 return 300 } 301 if err := pull.Issue.LoadPoster(ctx); err != nil { 302 log.Error("pull.Issue.LoadPoster: %v", err) 303 return 304 } 305 306 permission, _ := access_model.GetUserRepoPermission(ctx, pull.Issue.Repo, pull.Issue.Poster) 307 if err := PrepareWebhooks(ctx, EventSource{Repository: pull.Issue.Repo}, webhook_module.HookEventPullRequest, &api.PullRequestPayload{ 308 Action: api.HookIssueOpened, 309 Index: pull.Issue.Index, 310 PullRequest: convert.ToAPIPullRequest(ctx, pull, nil), 311 Repository: convert.ToRepo(ctx, pull.Issue.Repo, permission), 312 Sender: convert.ToUser(ctx, pull.Issue.Poster, nil), 313 }); err != nil { 314 log.Error("PrepareWebhooks: %v", err) 315 } 316 } 317 318 func (m *webhookNotifier) IssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) { 319 if err := issue.LoadRepo(ctx); err != nil { 320 log.Error("LoadRepo: %v", err) 321 return 322 } 323 324 permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster) 325 var err error 326 if issue.IsPull { 327 if err := issue.LoadPullRequest(ctx); err != nil { 328 log.Error("LoadPullRequest: %v", err) 329 return 330 } 331 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequest, &api.PullRequestPayload{ 332 Action: api.HookIssueEdited, 333 Index: issue.Index, 334 Changes: &api.ChangesPayload{ 335 Body: &api.ChangesFromPayload{ 336 From: oldContent, 337 }, 338 }, 339 PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), 340 Repository: convert.ToRepo(ctx, issue.Repo, permission), 341 Sender: convert.ToUser(ctx, doer, nil), 342 }) 343 } else { 344 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ 345 Action: api.HookIssueEdited, 346 Index: issue.Index, 347 Changes: &api.ChangesPayload{ 348 Body: &api.ChangesFromPayload{ 349 From: oldContent, 350 }, 351 }, 352 Issue: convert.ToAPIIssue(ctx, issue), 353 Repository: convert.ToRepo(ctx, issue.Repo, permission), 354 Sender: convert.ToUser(ctx, doer, nil), 355 }) 356 } 357 if err != nil { 358 log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) 359 } 360 } 361 362 func (m *webhookNotifier) UpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) { 363 if err := c.LoadPoster(ctx); err != nil { 364 log.Error("LoadPoster: %v", err) 365 return 366 } 367 if err := c.LoadIssue(ctx); err != nil { 368 log.Error("LoadIssue: %v", err) 369 return 370 } 371 372 if err := c.Issue.LoadAttributes(ctx); err != nil { 373 log.Error("LoadAttributes: %v", err) 374 return 375 } 376 377 var eventType webhook_module.HookEventType 378 if c.Issue.IsPull { 379 eventType = webhook_module.HookEventPullRequestComment 380 } else { 381 eventType = webhook_module.HookEventIssueComment 382 } 383 384 permission, _ := access_model.GetUserRepoPermission(ctx, c.Issue.Repo, doer) 385 if err := PrepareWebhooks(ctx, EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{ 386 Action: api.HookIssueCommentEdited, 387 Issue: convert.ToAPIIssue(ctx, c.Issue), 388 Comment: convert.ToAPIComment(ctx, c.Issue.Repo, c), 389 Changes: &api.ChangesPayload{ 390 Body: &api.ChangesFromPayload{ 391 From: oldContent, 392 }, 393 }, 394 Repository: convert.ToRepo(ctx, c.Issue.Repo, permission), 395 Sender: convert.ToUser(ctx, doer, nil), 396 IsPull: c.Issue.IsPull, 397 }); err != nil { 398 log.Error("PrepareWebhooks [comment_id: %d]: %v", c.ID, err) 399 } 400 } 401 402 func (m *webhookNotifier) CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, 403 issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User, 404 ) { 405 var eventType webhook_module.HookEventType 406 if issue.IsPull { 407 eventType = webhook_module.HookEventPullRequestComment 408 } else { 409 eventType = webhook_module.HookEventIssueComment 410 } 411 412 permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer) 413 if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{ 414 Action: api.HookIssueCommentCreated, 415 Issue: convert.ToAPIIssue(ctx, issue), 416 Comment: convert.ToAPIComment(ctx, repo, comment), 417 Repository: convert.ToRepo(ctx, repo, permission), 418 Sender: convert.ToUser(ctx, doer, nil), 419 IsPull: issue.IsPull, 420 }); err != nil { 421 log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err) 422 } 423 } 424 425 func (m *webhookNotifier) DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) { 426 var err error 427 428 if err = comment.LoadPoster(ctx); err != nil { 429 log.Error("LoadPoster: %v", err) 430 return 431 } 432 if err = comment.LoadIssue(ctx); err != nil { 433 log.Error("LoadIssue: %v", err) 434 return 435 } 436 437 if err = comment.Issue.LoadAttributes(ctx); err != nil { 438 log.Error("LoadAttributes: %v", err) 439 return 440 } 441 442 var eventType webhook_module.HookEventType 443 if comment.Issue.IsPull { 444 eventType = webhook_module.HookEventPullRequestComment 445 } else { 446 eventType = webhook_module.HookEventIssueComment 447 } 448 449 permission, _ := access_model.GetUserRepoPermission(ctx, comment.Issue.Repo, doer) 450 if err := PrepareWebhooks(ctx, EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{ 451 Action: api.HookIssueCommentDeleted, 452 Issue: convert.ToAPIIssue(ctx, comment.Issue), 453 Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment), 454 Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission), 455 Sender: convert.ToUser(ctx, doer, nil), 456 IsPull: comment.Issue.IsPull, 457 }); err != nil { 458 log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err) 459 } 460 } 461 462 func (m *webhookNotifier) NewWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) { 463 // Add to hook queue for created wiki page. 464 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{ 465 Action: api.HookWikiCreated, 466 Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 467 Sender: convert.ToUser(ctx, doer, nil), 468 Page: page, 469 Comment: comment, 470 }); err != nil { 471 log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) 472 } 473 } 474 475 func (m *webhookNotifier) EditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) { 476 // Add to hook queue for edit wiki page. 477 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{ 478 Action: api.HookWikiEdited, 479 Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 480 Sender: convert.ToUser(ctx, doer, nil), 481 Page: page, 482 Comment: comment, 483 }); err != nil { 484 log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) 485 } 486 } 487 488 func (m *webhookNotifier) DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page string) { 489 // Add to hook queue for edit wiki page. 490 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{ 491 Action: api.HookWikiDeleted, 492 Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 493 Sender: convert.ToUser(ctx, doer, nil), 494 Page: page, 495 }); err != nil { 496 log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) 497 } 498 } 499 500 func (m *webhookNotifier) IssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, 501 addedLabels, removedLabels []*issues_model.Label, 502 ) { 503 var err error 504 505 if err = issue.LoadRepo(ctx); err != nil { 506 log.Error("LoadRepo: %v", err) 507 return 508 } 509 510 if err = issue.LoadPoster(ctx); err != nil { 511 log.Error("LoadPoster: %v", err) 512 return 513 } 514 515 permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster) 516 if issue.IsPull { 517 if err = issue.LoadPullRequest(ctx); err != nil { 518 log.Error("loadPullRequest: %v", err) 519 return 520 } 521 if err = issue.PullRequest.LoadIssue(ctx); err != nil { 522 log.Error("LoadIssue: %v", err) 523 return 524 } 525 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestLabel, &api.PullRequestPayload{ 526 Action: api.HookIssueLabelUpdated, 527 Index: issue.Index, 528 PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), 529 Repository: convert.ToRepo(ctx, issue.Repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 530 Sender: convert.ToUser(ctx, doer, nil), 531 }) 532 } else { 533 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ 534 Action: api.HookIssueLabelUpdated, 535 Index: issue.Index, 536 Issue: convert.ToAPIIssue(ctx, issue), 537 Repository: convert.ToRepo(ctx, issue.Repo, permission), 538 Sender: convert.ToUser(ctx, doer, nil), 539 }) 540 } 541 if err != nil { 542 log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) 543 } 544 } 545 546 func (m *webhookNotifier) IssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) { 547 var hookAction api.HookIssueAction 548 var err error 549 if issue.MilestoneID > 0 { 550 hookAction = api.HookIssueMilestoned 551 } else { 552 hookAction = api.HookIssueDemilestoned 553 } 554 555 if err = issue.LoadAttributes(ctx); err != nil { 556 log.Error("issue.LoadAttributes failed: %v", err) 557 return 558 } 559 560 permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) 561 if issue.IsPull { 562 err = issue.PullRequest.LoadIssue(ctx) 563 if err != nil { 564 log.Error("LoadIssue: %v", err) 565 return 566 } 567 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestMilestone, &api.PullRequestPayload{ 568 Action: hookAction, 569 Index: issue.Index, 570 PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), 571 Repository: convert.ToRepo(ctx, issue.Repo, permission), 572 Sender: convert.ToUser(ctx, doer, nil), 573 }) 574 } else { 575 err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueMilestone, &api.IssuePayload{ 576 Action: hookAction, 577 Index: issue.Index, 578 Issue: convert.ToAPIIssue(ctx, issue), 579 Repository: convert.ToRepo(ctx, issue.Repo, permission), 580 Sender: convert.ToUser(ctx, doer, nil), 581 }) 582 } 583 if err != nil { 584 log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err) 585 } 586 } 587 588 func (m *webhookNotifier) PushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { 589 apiPusher := convert.ToUser(ctx, pusher, nil) 590 apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL()) 591 if err != nil { 592 log.Error("commits.ToAPIPayloadCommits failed: %v", err) 593 return 594 } 595 596 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{ 597 Ref: opts.RefFullName.String(), 598 Before: opts.OldCommitID, 599 After: opts.NewCommitID, 600 CompareURL: setting.AppURL + commits.CompareURL, 601 Commits: apiCommits, 602 TotalCommits: commits.Len, 603 HeadCommit: apiHeadCommit, 604 Repo: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 605 Pusher: apiPusher, 606 Sender: apiPusher, 607 }); err != nil { 608 log.Error("PrepareWebhooks: %v", err) 609 } 610 } 611 612 func (m *webhookNotifier) AutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { 613 // just redirect to the MergePullRequest 614 m.MergePullRequest(ctx, doer, pr) 615 } 616 617 func (*webhookNotifier) MergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { 618 // Reload pull request information. 619 if err := pr.LoadAttributes(ctx); err != nil { 620 log.Error("LoadAttributes: %v", err) 621 return 622 } 623 624 if err := pr.LoadIssue(ctx); err != nil { 625 log.Error("LoadIssue: %v", err) 626 return 627 } 628 629 if err := pr.Issue.LoadRepo(ctx); err != nil { 630 log.Error("pr.Issue.LoadRepo: %v", err) 631 return 632 } 633 634 permission, err := access_model.GetUserRepoPermission(ctx, pr.Issue.Repo, doer) 635 if err != nil { 636 log.Error("models.GetUserRepoPermission: %v", err) 637 return 638 } 639 640 // Merge pull request calls issue.changeStatus so we need to handle separately. 641 apiPullRequest := &api.PullRequestPayload{ 642 Index: pr.Issue.Index, 643 PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), 644 Repository: convert.ToRepo(ctx, pr.Issue.Repo, permission), 645 Sender: convert.ToUser(ctx, doer, nil), 646 Action: api.HookIssueClosed, 647 } 648 649 if err := PrepareWebhooks(ctx, EventSource{Repository: pr.Issue.Repo}, webhook_module.HookEventPullRequest, apiPullRequest); err != nil { 650 log.Error("PrepareWebhooks: %v", err) 651 } 652 } 653 654 func (m *webhookNotifier) PullRequestChangeTargetBranch(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) { 655 if err := pr.LoadIssue(ctx); err != nil { 656 log.Error("LoadIssue: %v", err) 657 return 658 } 659 660 issue := pr.Issue 661 662 mode, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster) 663 if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequest, &api.PullRequestPayload{ 664 Action: api.HookIssueEdited, 665 Index: issue.Index, 666 Changes: &api.ChangesPayload{ 667 Ref: &api.ChangesFromPayload{ 668 From: oldBranch, 669 }, 670 }, 671 PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), 672 Repository: convert.ToRepo(ctx, issue.Repo, mode), 673 Sender: convert.ToUser(ctx, doer, nil), 674 }); err != nil { 675 log.Error("PrepareWebhooks [pr: %d]: %v", pr.ID, err) 676 } 677 } 678 679 func (m *webhookNotifier) PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { 680 var reviewHookType webhook_module.HookEventType 681 682 switch review.Type { 683 case issues_model.ReviewTypeApprove: 684 reviewHookType = webhook_module.HookEventPullRequestReviewApproved 685 case issues_model.ReviewTypeComment: 686 reviewHookType = webhook_module.HookEventPullRequestReviewComment 687 case issues_model.ReviewTypeReject: 688 reviewHookType = webhook_module.HookEventPullRequestReviewRejected 689 default: 690 // unsupported review webhook type here 691 log.Error("Unsupported review webhook type") 692 return 693 } 694 695 if err := pr.LoadIssue(ctx); err != nil { 696 log.Error("LoadIssue: %v", err) 697 return 698 } 699 700 permission, err := access_model.GetUserRepoPermission(ctx, review.Issue.Repo, review.Issue.Poster) 701 if err != nil { 702 log.Error("models.GetUserRepoPermission: %v", err) 703 return 704 } 705 if err := PrepareWebhooks(ctx, EventSource{Repository: review.Issue.Repo}, reviewHookType, &api.PullRequestPayload{ 706 Action: api.HookIssueReviewed, 707 Index: review.Issue.Index, 708 PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), 709 Repository: convert.ToRepo(ctx, review.Issue.Repo, permission), 710 Sender: convert.ToUser(ctx, review.Reviewer, nil), 711 Review: &api.ReviewPayload{ 712 Type: string(reviewHookType), 713 Content: review.Content, 714 }, 715 }); err != nil { 716 log.Error("PrepareWebhooks: %v", err) 717 } 718 } 719 720 func (m *webhookNotifier) PullRequestReviewRequest(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) { 721 if !issue.IsPull { 722 log.Warn("PullRequestReviewRequest: issue is not a pull request: %v", issue.ID) 723 return 724 } 725 permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) 726 if err := issue.LoadPullRequest(ctx); err != nil { 727 log.Error("LoadPullRequest failed: %v", err) 728 return 729 } 730 apiPullRequest := &api.PullRequestPayload{ 731 Index: issue.Index, 732 PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), 733 RequestedReviewer: convert.ToUser(ctx, reviewer, nil), 734 Repository: convert.ToRepo(ctx, issue.Repo, permission), 735 Sender: convert.ToUser(ctx, doer, nil), 736 } 737 if isRequest { 738 apiPullRequest.Action = api.HookIssueReviewRequested 739 } else { 740 apiPullRequest.Action = api.HookIssueReviewRequestRemoved 741 } 742 if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestReviewRequest, apiPullRequest); err != nil { 743 log.Error("PrepareWebhooks [review_requested: %v]: %v", isRequest, err) 744 return 745 } 746 } 747 748 func (m *webhookNotifier) CreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { 749 apiPusher := convert.ToUser(ctx, pusher, nil) 750 apiRepo := convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeNone}) 751 refName := refFullName.ShortName() 752 753 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventCreate, &api.CreatePayload{ 754 Ref: refName, // FIXME: should it be a full ref name? 755 Sha: refID, 756 RefType: refFullName.RefType(), 757 Repo: apiRepo, 758 Sender: apiPusher, 759 }); err != nil { 760 log.Error("PrepareWebhooks: %v", err) 761 } 762 } 763 764 func (m *webhookNotifier) PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) { 765 if err := pr.LoadIssue(ctx); err != nil { 766 log.Error("LoadIssue: %v", err) 767 return 768 } 769 if err := pr.Issue.LoadAttributes(ctx); err != nil { 770 log.Error("LoadAttributes: %v", err) 771 return 772 } 773 774 if err := PrepareWebhooks(ctx, EventSource{Repository: pr.Issue.Repo}, webhook_module.HookEventPullRequestSync, &api.PullRequestPayload{ 775 Action: api.HookIssueSynchronized, 776 Index: pr.Issue.Index, 777 PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), 778 Repository: convert.ToRepo(ctx, pr.Issue.Repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 779 Sender: convert.ToUser(ctx, doer, nil), 780 }); err != nil { 781 log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err) 782 } 783 } 784 785 func (m *webhookNotifier) DeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { 786 apiPusher := convert.ToUser(ctx, pusher, nil) 787 apiRepo := convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}) 788 refName := refFullName.ShortName() 789 790 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventDelete, &api.DeletePayload{ 791 Ref: refName, // FIXME: should it be a full ref name? 792 RefType: refFullName.RefType(), 793 PusherType: api.PusherTypeUser, 794 Repo: apiRepo, 795 Sender: apiPusher, 796 }); err != nil { 797 log.Error("PrepareWebhooks.(delete %s): %v", refFullName.RefType(), err) 798 } 799 } 800 801 func sendReleaseHook(ctx context.Context, doer *user_model.User, rel *repo_model.Release, action api.HookReleaseAction) { 802 if err := rel.LoadAttributes(ctx); err != nil { 803 log.Error("LoadAttributes: %v", err) 804 return 805 } 806 807 permission, _ := access_model.GetUserRepoPermission(ctx, rel.Repo, doer) 808 if err := PrepareWebhooks(ctx, EventSource{Repository: rel.Repo}, webhook_module.HookEventRelease, &api.ReleasePayload{ 809 Action: action, 810 Release: convert.ToAPIRelease(ctx, rel.Repo, rel), 811 Repository: convert.ToRepo(ctx, rel.Repo, permission), 812 Sender: convert.ToUser(ctx, doer, nil), 813 }); err != nil { 814 log.Error("PrepareWebhooks: %v", err) 815 } 816 } 817 818 func (m *webhookNotifier) NewRelease(ctx context.Context, rel *repo_model.Release) { 819 sendReleaseHook(ctx, rel.Publisher, rel, api.HookReleasePublished) 820 } 821 822 func (m *webhookNotifier) UpdateRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) { 823 sendReleaseHook(ctx, doer, rel, api.HookReleaseUpdated) 824 } 825 826 func (m *webhookNotifier) DeleteRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) { 827 sendReleaseHook(ctx, doer, rel, api.HookReleaseDeleted) 828 } 829 830 func (m *webhookNotifier) SyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { 831 apiPusher := convert.ToUser(ctx, pusher, nil) 832 apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL()) 833 if err != nil { 834 log.Error("commits.ToAPIPayloadCommits failed: %v", err) 835 return 836 } 837 838 if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{ 839 Ref: opts.RefFullName.String(), 840 Before: opts.OldCommitID, 841 After: opts.NewCommitID, 842 CompareURL: setting.AppURL + commits.CompareURL, 843 Commits: apiCommits, 844 TotalCommits: commits.Len, 845 HeadCommit: apiHeadCommit, 846 Repo: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), 847 Pusher: apiPusher, 848 Sender: apiPusher, 849 }); err != nil { 850 log.Error("PrepareWebhooks: %v", err) 851 } 852 } 853 854 func (m *webhookNotifier) SyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { 855 m.CreateRef(ctx, pusher, repo, refFullName, refID) 856 } 857 858 func (m *webhookNotifier) SyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { 859 m.DeleteRef(ctx, pusher, repo, refFullName) 860 } 861 862 func (m *webhookNotifier) PackageCreate(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) { 863 notifyPackage(ctx, doer, pd, api.HookPackageCreated) 864 } 865 866 func (m *webhookNotifier) PackageDelete(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) { 867 notifyPackage(ctx, doer, pd, api.HookPackageDeleted) 868 } 869 870 func notifyPackage(ctx context.Context, sender *user_model.User, pd *packages_model.PackageDescriptor, action api.HookPackageAction) { 871 source := EventSource{ 872 Repository: pd.Repository, 873 Owner: pd.Owner, 874 } 875 876 apiPackage, err := convert.ToPackage(ctx, pd, sender) 877 if err != nil { 878 log.Error("Error converting package: %v", err) 879 return 880 } 881 882 if err := PrepareWebhooks(ctx, source, webhook_module.HookEventPackage, &api.PackagePayload{ 883 Action: action, 884 Package: apiPackage, 885 Sender: convert.ToUser(ctx, sender, nil), 886 }); err != nil { 887 log.Error("PrepareWebhooks: %v", err) 888 } 889 }