gitea源码

notifier.go 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. // Copyright 2022 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package actions
  4. import (
  5. "context"
  6. actions_model "code.gitea.io/gitea/models/actions"
  7. issues_model "code.gitea.io/gitea/models/issues"
  8. "code.gitea.io/gitea/models/organization"
  9. packages_model "code.gitea.io/gitea/models/packages"
  10. perm_model "code.gitea.io/gitea/models/perm"
  11. access_model "code.gitea.io/gitea/models/perm/access"
  12. repo_model "code.gitea.io/gitea/models/repo"
  13. user_model "code.gitea.io/gitea/models/user"
  14. "code.gitea.io/gitea/modules/git"
  15. "code.gitea.io/gitea/modules/gitrepo"
  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. type actionsNotifier struct {
  25. notify_service.NullNotifier
  26. }
  27. var _ notify_service.Notifier = &actionsNotifier{}
  28. // NewNotifier create a new actionsNotifier notifier
  29. func NewNotifier() notify_service.Notifier {
  30. return &actionsNotifier{}
  31. }
  32. // NewIssue notifies issue created event
  33. func (n *actionsNotifier) NewIssue(ctx context.Context, issue *issues_model.Issue, _ []*user_model.User) {
  34. ctx = withMethod(ctx, "NewIssue")
  35. if err := issue.LoadRepo(ctx); err != nil {
  36. log.Error("issue.LoadRepo: %v", err)
  37. return
  38. }
  39. if err := issue.LoadPoster(ctx); err != nil {
  40. log.Error("issue.LoadPoster: %v", err)
  41. return
  42. }
  43. permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster)
  44. newNotifyInputFromIssue(issue, webhook_module.HookEventIssues).WithPayload(&api.IssuePayload{
  45. Action: api.HookIssueOpened,
  46. Index: issue.Index,
  47. Issue: convert.ToAPIIssue(ctx, issue.Poster, issue),
  48. Repository: convert.ToRepo(ctx, issue.Repo, permission),
  49. Sender: convert.ToUser(ctx, issue.Poster, nil),
  50. }).Notify(withMethod(ctx, "NewIssue"))
  51. }
  52. // IssueChangeContent notifies change content of issue
  53. func (n *actionsNotifier) IssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) {
  54. ctx = withMethod(ctx, "IssueChangeContent")
  55. n.notifyIssueChangeWithTitleOrContent(ctx, doer, issue)
  56. }
  57. func (n *actionsNotifier) IssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
  58. ctx = withMethod(ctx, "IssueChangeTitle")
  59. n.notifyIssueChangeWithTitleOrContent(ctx, doer, issue)
  60. }
  61. func (n *actionsNotifier) notifyIssueChangeWithTitleOrContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) {
  62. var err error
  63. if err = issue.LoadRepo(ctx); err != nil {
  64. log.Error("LoadRepo: %v", err)
  65. return
  66. }
  67. permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster)
  68. if issue.IsPull {
  69. if err = issue.LoadPullRequest(ctx); err != nil {
  70. log.Error("loadPullRequest: %v", err)
  71. return
  72. }
  73. newNotifyInputFromIssue(issue, webhook_module.HookEventPullRequest).
  74. WithDoer(doer).
  75. WithPayload(&api.PullRequestPayload{
  76. Action: api.HookIssueEdited,
  77. Index: issue.Index,
  78. PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
  79. Repository: convert.ToRepo(ctx, issue.Repo, access_model.Permission{AccessMode: perm_model.AccessModeNone}),
  80. Sender: convert.ToUser(ctx, doer, nil),
  81. }).
  82. WithPullRequest(issue.PullRequest).
  83. Notify(ctx)
  84. return
  85. }
  86. newNotifyInputFromIssue(issue, webhook_module.HookEventIssues).
  87. WithDoer(doer).
  88. WithPayload(&api.IssuePayload{
  89. Action: api.HookIssueEdited,
  90. Index: issue.Index,
  91. Issue: convert.ToAPIIssue(ctx, doer, issue),
  92. Repository: convert.ToRepo(ctx, issue.Repo, permission),
  93. Sender: convert.ToUser(ctx, doer, nil),
  94. }).
  95. Notify(ctx)
  96. }
  97. // IssueChangeStatus notifies close or reopen issue to notifiers
  98. func (n *actionsNotifier) IssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, _ *issues_model.Comment, isClosed bool) {
  99. ctx = withMethod(ctx, "IssueChangeStatus")
  100. permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster)
  101. if issue.IsPull {
  102. if err := issue.LoadPullRequest(ctx); err != nil {
  103. log.Error("LoadPullRequest: %v", err)
  104. return
  105. }
  106. // Merge pull request calls issue.changeStatus so we need to handle separately.
  107. apiPullRequest := &api.PullRequestPayload{
  108. Index: issue.Index,
  109. PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
  110. Repository: convert.ToRepo(ctx, issue.Repo, permission),
  111. Sender: convert.ToUser(ctx, doer, nil),
  112. CommitID: commitID,
  113. }
  114. if isClosed {
  115. apiPullRequest.Action = api.HookIssueClosed
  116. } else {
  117. apiPullRequest.Action = api.HookIssueReOpened
  118. }
  119. newNotifyInputFromIssue(issue, webhook_module.HookEventPullRequest).
  120. WithDoer(doer).
  121. WithPayload(apiPullRequest).
  122. WithPullRequest(issue.PullRequest).
  123. Notify(ctx)
  124. return
  125. }
  126. apiIssue := &api.IssuePayload{
  127. Index: issue.Index,
  128. Issue: convert.ToAPIIssue(ctx, doer, issue),
  129. Repository: convert.ToRepo(ctx, issue.Repo, permission),
  130. Sender: convert.ToUser(ctx, doer, nil),
  131. }
  132. if isClosed {
  133. apiIssue.Action = api.HookIssueClosed
  134. } else {
  135. apiIssue.Action = api.HookIssueReOpened
  136. }
  137. newNotifyInputFromIssue(issue, webhook_module.HookEventIssues).
  138. WithDoer(doer).
  139. WithPayload(apiIssue).
  140. Notify(ctx)
  141. }
  142. // IssueChangeAssignee notifies assigned or unassigned to notifiers
  143. func (n *actionsNotifier) IssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) {
  144. ctx = withMethod(ctx, "IssueChangeAssignee")
  145. var action api.HookIssueAction
  146. if removed {
  147. action = api.HookIssueUnassigned
  148. } else {
  149. action = api.HookIssueAssigned
  150. }
  151. hookEvent := webhook_module.HookEventIssueAssign
  152. if issue.IsPull {
  153. hookEvent = webhook_module.HookEventPullRequestAssign
  154. }
  155. notifyIssueChange(ctx, doer, issue, hookEvent, action, nil, nil)
  156. }
  157. // IssueChangeMilestone notifies assignee to notifiers
  158. func (n *actionsNotifier) IssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) {
  159. ctx = withMethod(ctx, "IssueChangeMilestone")
  160. var action api.HookIssueAction
  161. if issue.MilestoneID > 0 {
  162. action = api.HookIssueMilestoned
  163. } else {
  164. action = api.HookIssueDemilestoned
  165. }
  166. hookEvent := webhook_module.HookEventIssueMilestone
  167. if issue.IsPull {
  168. hookEvent = webhook_module.HookEventPullRequestMilestone
  169. }
  170. notifyIssueChange(ctx, doer, issue, hookEvent, action, nil, nil)
  171. }
  172. func (n *actionsNotifier) IssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue,
  173. addedLabels, removedLabels []*issues_model.Label,
  174. ) {
  175. ctx = withMethod(ctx, "IssueChangeLabels")
  176. hookEvent := webhook_module.HookEventIssueLabel
  177. if issue.IsPull {
  178. hookEvent = webhook_module.HookEventPullRequestLabel
  179. }
  180. notifyIssueChange(ctx, doer, issue, hookEvent, api.HookIssueLabelUpdated, addedLabels, removedLabels)
  181. }
  182. func notifyIssueChange(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, event webhook_module.HookEventType, action api.HookIssueAction, addedLabels, removedLabels []*issues_model.Label) {
  183. var err error
  184. if err = issue.LoadRepo(ctx); err != nil {
  185. log.Error("LoadRepo: %v", err)
  186. return
  187. }
  188. if err = issue.LoadPoster(ctx); err != nil {
  189. log.Error("LoadPoster: %v", err)
  190. return
  191. }
  192. var addedAPILabels []*api.Label
  193. if addedLabels != nil {
  194. addedAPILabels = make([]*api.Label, 0, len(addedLabels))
  195. for _, label := range addedLabels {
  196. addedAPILabels = append(addedAPILabels, convert.ToLabel(label, issue.Repo, doer))
  197. }
  198. }
  199. // Get removed labels from context if present
  200. var removedAPILabels []*api.Label
  201. if removedLabels != nil {
  202. removedAPILabels = make([]*api.Label, 0, len(removedLabels))
  203. for _, label := range removedLabels {
  204. removedAPILabels = append(removedAPILabels, convert.ToLabel(label, issue.Repo, doer))
  205. }
  206. }
  207. if issue.IsPull {
  208. if err = issue.LoadPullRequest(ctx); err != nil {
  209. log.Error("loadPullRequest: %v", err)
  210. return
  211. }
  212. payload := &api.PullRequestPayload{
  213. Action: action,
  214. Index: issue.Index,
  215. PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
  216. Repository: convert.ToRepo(ctx, issue.Repo, access_model.Permission{AccessMode: perm_model.AccessModeNone}),
  217. Sender: convert.ToUser(ctx, doer, nil),
  218. Changes: &api.ChangesPayload{
  219. AddedLabels: addedAPILabels,
  220. RemovedLabels: removedAPILabels,
  221. },
  222. }
  223. newNotifyInputFromIssue(issue, event).
  224. WithDoer(doer).
  225. WithPayload(payload).
  226. WithPullRequest(issue.PullRequest).
  227. Notify(ctx)
  228. return
  229. }
  230. permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster)
  231. payload := &api.IssuePayload{
  232. Action: action,
  233. Index: issue.Index,
  234. Issue: convert.ToAPIIssue(ctx, doer, issue),
  235. Repository: convert.ToRepo(ctx, issue.Repo, permission),
  236. Sender: convert.ToUser(ctx, doer, nil),
  237. Changes: &api.ChangesPayload{
  238. AddedLabels: addedAPILabels,
  239. RemovedLabels: removedAPILabels,
  240. },
  241. }
  242. newNotifyInputFromIssue(issue, event).
  243. WithDoer(doer).
  244. WithPayload(payload).
  245. Notify(ctx)
  246. }
  247. // CreateIssueComment notifies comment on an issue to notifiers
  248. func (n *actionsNotifier) CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository,
  249. issue *issues_model.Issue, comment *issues_model.Comment, _ []*user_model.User,
  250. ) {
  251. ctx = withMethod(ctx, "CreateIssueComment")
  252. if issue.IsPull {
  253. notifyIssueCommentChange(ctx, doer, comment, "", webhook_module.HookEventPullRequestComment, api.HookIssueCommentCreated)
  254. return
  255. }
  256. notifyIssueCommentChange(ctx, doer, comment, "", webhook_module.HookEventIssueComment, api.HookIssueCommentCreated)
  257. }
  258. func (n *actionsNotifier) UpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) {
  259. ctx = withMethod(ctx, "UpdateComment")
  260. if c.Issue.IsPull {
  261. notifyIssueCommentChange(ctx, doer, c, oldContent, webhook_module.HookEventPullRequestComment, api.HookIssueCommentEdited)
  262. return
  263. }
  264. notifyIssueCommentChange(ctx, doer, c, oldContent, webhook_module.HookEventIssueComment, api.HookIssueCommentEdited)
  265. }
  266. func (n *actionsNotifier) DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) {
  267. ctx = withMethod(ctx, "DeleteComment")
  268. if comment.Issue.IsPull {
  269. notifyIssueCommentChange(ctx, doer, comment, "", webhook_module.HookEventPullRequestComment, api.HookIssueCommentDeleted)
  270. return
  271. }
  272. notifyIssueCommentChange(ctx, doer, comment, "", webhook_module.HookEventIssueComment, api.HookIssueCommentDeleted)
  273. }
  274. func notifyIssueCommentChange(ctx context.Context, doer *user_model.User, comment *issues_model.Comment, oldContent string, event webhook_module.HookEventType, action api.HookIssueCommentAction) {
  275. comment.Issue = nil // force issue to be loaded
  276. if err := comment.LoadIssue(ctx); err != nil {
  277. log.Error("LoadIssue: %v", err)
  278. return
  279. }
  280. if err := comment.Issue.LoadAttributes(ctx); err != nil {
  281. log.Error("LoadAttributes: %v", err)
  282. return
  283. }
  284. permission, _ := access_model.GetUserRepoPermission(ctx, comment.Issue.Repo, doer)
  285. payload := &api.IssueCommentPayload{
  286. Action: action,
  287. Issue: convert.ToAPIIssue(ctx, doer, comment.Issue),
  288. Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment),
  289. Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission),
  290. Sender: convert.ToUser(ctx, doer, nil),
  291. IsPull: comment.Issue.IsPull,
  292. }
  293. if action == api.HookIssueCommentEdited {
  294. payload.Changes = &api.ChangesPayload{
  295. Body: &api.ChangesFromPayload{
  296. From: oldContent,
  297. },
  298. }
  299. }
  300. if comment.Issue.IsPull {
  301. if err := comment.Issue.LoadPullRequest(ctx); err != nil {
  302. log.Error("LoadPullRequest: %v", err)
  303. return
  304. }
  305. newNotifyInputFromIssue(comment.Issue, event).
  306. WithDoer(doer).
  307. WithPayload(payload).
  308. WithPullRequest(comment.Issue.PullRequest).
  309. Notify(ctx)
  310. return
  311. }
  312. newNotifyInputFromIssue(comment.Issue, event).
  313. WithDoer(doer).
  314. WithPayload(payload).
  315. Notify(ctx)
  316. }
  317. func (n *actionsNotifier) NewPullRequest(ctx context.Context, pull *issues_model.PullRequest, _ []*user_model.User) {
  318. ctx = withMethod(ctx, "NewPullRequest")
  319. if err := pull.LoadIssue(ctx); err != nil {
  320. log.Error("pull.LoadIssue: %v", err)
  321. return
  322. }
  323. if err := pull.Issue.LoadRepo(ctx); err != nil {
  324. log.Error("pull.Issue.LoadRepo: %v", err)
  325. return
  326. }
  327. if err := pull.Issue.LoadPoster(ctx); err != nil {
  328. log.Error("pull.Issue.LoadPoster: %v", err)
  329. return
  330. }
  331. permission, _ := access_model.GetUserRepoPermission(ctx, pull.Issue.Repo, pull.Issue.Poster)
  332. newNotifyInputFromIssue(pull.Issue, webhook_module.HookEventPullRequest).
  333. WithPayload(&api.PullRequestPayload{
  334. Action: api.HookIssueOpened,
  335. Index: pull.Issue.Index,
  336. PullRequest: convert.ToAPIPullRequest(ctx, pull, nil),
  337. Repository: convert.ToRepo(ctx, pull.Issue.Repo, permission),
  338. Sender: convert.ToUser(ctx, pull.Issue.Poster, nil),
  339. }).
  340. WithPullRequest(pull).
  341. Notify(ctx)
  342. }
  343. func (n *actionsNotifier) CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
  344. ctx = withMethod(ctx, "CreateRepository")
  345. newNotifyInput(repo, doer, webhook_module.HookEventRepository).WithPayload(&api.RepositoryPayload{
  346. Action: api.HookRepoCreated,
  347. Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeOwner}),
  348. Organization: convert.ToUser(ctx, u, nil),
  349. Sender: convert.ToUser(ctx, doer, nil),
  350. }).Notify(ctx)
  351. }
  352. func (n *actionsNotifier) ForkRepository(ctx context.Context, doer *user_model.User, oldRepo, repo *repo_model.Repository) {
  353. ctx = withMethod(ctx, "ForkRepository")
  354. oldPermission, _ := access_model.GetUserRepoPermission(ctx, oldRepo, doer)
  355. permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer)
  356. // forked webhook
  357. newNotifyInput(oldRepo, doer, webhook_module.HookEventFork).WithPayload(&api.ForkPayload{
  358. Forkee: convert.ToRepo(ctx, oldRepo, oldPermission),
  359. Repo: convert.ToRepo(ctx, repo, permission),
  360. Sender: convert.ToUser(ctx, doer, nil),
  361. }).Notify(ctx)
  362. u := repo.MustOwner(ctx)
  363. // Add to hook queue for created repo after session commit.
  364. if u.IsOrganization() {
  365. newNotifyInput(repo, doer, webhook_module.HookEventRepository).
  366. WithRef(git.RefNameFromBranch(oldRepo.DefaultBranch).String()).
  367. WithPayload(&api.RepositoryPayload{
  368. Action: api.HookRepoCreated,
  369. Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeOwner}),
  370. Organization: convert.ToUser(ctx, u, nil),
  371. Sender: convert.ToUser(ctx, doer, nil),
  372. }).Notify(ctx)
  373. }
  374. }
  375. func (n *actionsNotifier) PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, _ *issues_model.Comment, _ []*user_model.User) {
  376. ctx = withMethod(ctx, "PullRequestReview")
  377. var reviewHookType webhook_module.HookEventType
  378. switch review.Type {
  379. case issues_model.ReviewTypeApprove:
  380. reviewHookType = webhook_module.HookEventPullRequestReviewApproved
  381. case issues_model.ReviewTypeComment:
  382. reviewHookType = webhook_module.HookEventPullRequestReviewComment
  383. case issues_model.ReviewTypeReject:
  384. reviewHookType = webhook_module.HookEventPullRequestReviewRejected
  385. default:
  386. // unsupported review webhook type here
  387. log.Error("Unsupported review webhook type")
  388. return
  389. }
  390. if err := pr.LoadIssue(ctx); err != nil {
  391. log.Error("pr.LoadIssue: %v", err)
  392. return
  393. }
  394. permission, err := access_model.GetUserRepoPermission(ctx, review.Issue.Repo, review.Issue.Poster)
  395. if err != nil {
  396. log.Error("models.GetUserRepoPermission: %v", err)
  397. return
  398. }
  399. newNotifyInput(review.Issue.Repo, review.Reviewer, reviewHookType).
  400. WithRef(review.CommitID).
  401. WithPayload(&api.PullRequestPayload{
  402. Action: api.HookIssueReviewed,
  403. Index: review.Issue.Index,
  404. PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
  405. Repository: convert.ToRepo(ctx, review.Issue.Repo, permission),
  406. Sender: convert.ToUser(ctx, review.Reviewer, nil),
  407. Review: &api.ReviewPayload{
  408. Type: string(reviewHookType),
  409. Content: review.Content,
  410. },
  411. }).Notify(ctx)
  412. }
  413. func (n *actionsNotifier) PullRequestReviewRequest(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) {
  414. if !issue.IsPull {
  415. log.Warn("PullRequestReviewRequest: issue is not a pull request: %v", issue.ID)
  416. return
  417. }
  418. ctx = withMethod(ctx, "PullRequestReviewRequest")
  419. permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer)
  420. if err := issue.LoadPullRequest(ctx); err != nil {
  421. log.Error("LoadPullRequest failed: %v", err)
  422. return
  423. }
  424. var action api.HookIssueAction
  425. if isRequest {
  426. action = api.HookIssueReviewRequested
  427. } else {
  428. action = api.HookIssueReviewRequestRemoved
  429. }
  430. newNotifyInputFromIssue(issue, webhook_module.HookEventPullRequestReviewRequest).
  431. WithDoer(doer).
  432. WithPayload(&api.PullRequestPayload{
  433. Action: action,
  434. Index: issue.Index,
  435. PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
  436. RequestedReviewer: convert.ToUser(ctx, reviewer, nil),
  437. Repository: convert.ToRepo(ctx, issue.Repo, permission),
  438. Sender: convert.ToUser(ctx, doer, nil),
  439. }).
  440. WithPullRequest(issue.PullRequest).
  441. Notify(ctx)
  442. }
  443. func (*actionsNotifier) MergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
  444. ctx = withMethod(ctx, "MergePullRequest")
  445. // Reload pull request information.
  446. if err := pr.LoadAttributes(ctx); err != nil {
  447. log.Error("LoadAttributes: %v", err)
  448. return
  449. }
  450. if err := pr.LoadIssue(ctx); err != nil {
  451. log.Error("LoadAttributes: %v", err)
  452. return
  453. }
  454. if err := pr.Issue.LoadRepo(ctx); err != nil {
  455. log.Error("pr.Issue.LoadRepo: %v", err)
  456. return
  457. }
  458. permission, err := access_model.GetUserRepoPermission(ctx, pr.Issue.Repo, doer)
  459. if err != nil {
  460. log.Error("models.GetUserRepoPermission: %v", err)
  461. return
  462. }
  463. // Merge pull request calls issue.changeStatus so we need to handle separately.
  464. apiPullRequest := &api.PullRequestPayload{
  465. Index: pr.Issue.Index,
  466. PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
  467. Repository: convert.ToRepo(ctx, pr.Issue.Repo, permission),
  468. Sender: convert.ToUser(ctx, doer, nil),
  469. Action: api.HookIssueClosed,
  470. }
  471. newNotifyInput(pr.Issue.Repo, doer, webhook_module.HookEventPullRequest).
  472. WithRef(pr.MergedCommitID).
  473. WithPayload(apiPullRequest).
  474. WithPullRequest(pr).
  475. Notify(ctx)
  476. }
  477. func (n *actionsNotifier) PushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
  478. commitID, _ := git.NewIDFromString(opts.NewCommitID)
  479. if commitID.IsZero() {
  480. log.Trace("new commitID is empty")
  481. return
  482. }
  483. ctx = withMethod(ctx, "PushCommits")
  484. apiPusher := convert.ToUser(ctx, pusher, nil)
  485. apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo)
  486. if err != nil {
  487. log.Error("commits.ToAPIPayloadCommits failed: %v", err)
  488. return
  489. }
  490. newNotifyInput(repo, pusher, webhook_module.HookEventPush).
  491. WithRef(opts.RefFullName.String()).
  492. WithPayload(&api.PushPayload{
  493. Ref: opts.RefFullName.String(),
  494. Before: opts.OldCommitID,
  495. After: opts.NewCommitID,
  496. CompareURL: setting.AppURL + commits.CompareURL,
  497. Commits: apiCommits,
  498. HeadCommit: apiHeadCommit,
  499. Repo: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeOwner}),
  500. Pusher: apiPusher,
  501. Sender: apiPusher,
  502. }).
  503. Notify(ctx)
  504. }
  505. func (n *actionsNotifier) CreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) {
  506. ctx = withMethod(ctx, "CreateRef")
  507. apiPusher := convert.ToUser(ctx, pusher, nil)
  508. apiRepo := convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeNone})
  509. newNotifyInput(repo, pusher, webhook_module.HookEventCreate).
  510. WithRef(refFullName.String()).
  511. WithPayload(&api.CreatePayload{
  512. Ref: refFullName.String(), // HINT: here is inconsistent with the Webhook's payload: webhook uses ShortName
  513. Sha: refID,
  514. RefType: string(refFullName.RefType()),
  515. Repo: apiRepo,
  516. Sender: apiPusher,
  517. }).
  518. Notify(ctx)
  519. }
  520. func (n *actionsNotifier) DeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) {
  521. ctx = withMethod(ctx, "DeleteRef")
  522. apiPusher := convert.ToUser(ctx, pusher, nil)
  523. apiRepo := convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeNone})
  524. newNotifyInput(repo, pusher, webhook_module.HookEventDelete).
  525. WithPayload(&api.DeletePayload{
  526. Ref: refFullName.String(), // HINT: here is inconsistent with the Webhook's payload: webhook uses ShortName
  527. RefType: string(refFullName.RefType()),
  528. PusherType: api.PusherTypeUser,
  529. Repo: apiRepo,
  530. Sender: apiPusher,
  531. }).
  532. Notify(ctx)
  533. }
  534. func (n *actionsNotifier) SyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
  535. ctx = withMethod(ctx, "SyncPushCommits")
  536. apiPusher := convert.ToUser(ctx, pusher, nil)
  537. apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo)
  538. if err != nil {
  539. log.Error("commits.ToAPIPayloadCommits failed: %v", err)
  540. return
  541. }
  542. newNotifyInput(repo, pusher, webhook_module.HookEventPush).
  543. WithRef(opts.RefFullName.String()).
  544. WithPayload(&api.PushPayload{
  545. Ref: opts.RefFullName.String(),
  546. Before: opts.OldCommitID,
  547. After: opts.NewCommitID,
  548. CompareURL: setting.AppURL + commits.CompareURL,
  549. Commits: apiCommits,
  550. TotalCommits: commits.Len,
  551. HeadCommit: apiHeadCommit,
  552. Repo: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeOwner}),
  553. Pusher: apiPusher,
  554. Sender: apiPusher,
  555. }).
  556. Notify(ctx)
  557. }
  558. func (n *actionsNotifier) SyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) {
  559. ctx = withMethod(ctx, "SyncCreateRef")
  560. n.CreateRef(ctx, pusher, repo, refFullName, refID)
  561. }
  562. func (n *actionsNotifier) SyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) {
  563. ctx = withMethod(ctx, "SyncDeleteRef")
  564. n.DeleteRef(ctx, pusher, repo, refFullName)
  565. }
  566. func (n *actionsNotifier) NewRelease(ctx context.Context, rel *repo_model.Release) {
  567. ctx = withMethod(ctx, "NewRelease")
  568. notifyRelease(ctx, rel.Publisher, rel, api.HookReleasePublished)
  569. }
  570. func (n *actionsNotifier) UpdateRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) {
  571. ctx = withMethod(ctx, "UpdateRelease")
  572. notifyRelease(ctx, doer, rel, api.HookReleaseUpdated)
  573. }
  574. func (n *actionsNotifier) DeleteRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) {
  575. if rel.IsTag {
  576. // has sent same action in `PushCommits`, so skip it.
  577. return
  578. }
  579. ctx = withMethod(ctx, "DeleteRelease")
  580. notifyRelease(ctx, doer, rel, api.HookReleaseDeleted)
  581. }
  582. func (n *actionsNotifier) PackageCreate(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) {
  583. ctx = withMethod(ctx, "PackageCreate")
  584. notifyPackage(ctx, doer, pd, api.HookPackageCreated)
  585. }
  586. func (n *actionsNotifier) PackageDelete(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) {
  587. ctx = withMethod(ctx, "PackageDelete")
  588. notifyPackage(ctx, doer, pd, api.HookPackageDeleted)
  589. }
  590. func (n *actionsNotifier) AutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
  591. ctx = withMethod(ctx, "AutoMergePullRequest")
  592. n.MergePullRequest(ctx, doer, pr)
  593. }
  594. func (n *actionsNotifier) PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
  595. ctx = withMethod(ctx, "PullRequestSynchronized")
  596. if err := pr.LoadIssue(ctx); err != nil {
  597. log.Error("LoadAttributes: %v", err)
  598. return
  599. }
  600. if err := pr.Issue.LoadRepo(ctx); err != nil {
  601. log.Error("pr.Issue.LoadRepo: %v", err)
  602. return
  603. }
  604. newNotifyInput(pr.Issue.Repo, doer, webhook_module.HookEventPullRequestSync).
  605. WithPayload(&api.PullRequestPayload{
  606. Action: api.HookIssueSynchronized,
  607. Index: pr.Issue.Index,
  608. PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
  609. Repository: convert.ToRepo(ctx, pr.Issue.Repo, access_model.Permission{AccessMode: perm_model.AccessModeNone}),
  610. Sender: convert.ToUser(ctx, doer, nil),
  611. }).
  612. WithPullRequest(pr).
  613. Notify(ctx)
  614. }
  615. func (n *actionsNotifier) PullRequestChangeTargetBranch(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) {
  616. ctx = withMethod(ctx, "PullRequestChangeTargetBranch")
  617. if err := pr.LoadIssue(ctx); err != nil {
  618. log.Error("LoadAttributes: %v", err)
  619. return
  620. }
  621. if err := pr.Issue.LoadRepo(ctx); err != nil {
  622. log.Error("pr.Issue.LoadRepo: %v", err)
  623. return
  624. }
  625. permission, _ := access_model.GetUserRepoPermission(ctx, pr.Issue.Repo, pr.Issue.Poster)
  626. newNotifyInput(pr.Issue.Repo, doer, webhook_module.HookEventPullRequest).
  627. WithPayload(&api.PullRequestPayload{
  628. Action: api.HookIssueEdited,
  629. Index: pr.Issue.Index,
  630. Changes: &api.ChangesPayload{
  631. Ref: &api.ChangesFromPayload{
  632. From: oldBranch,
  633. },
  634. },
  635. PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
  636. Repository: convert.ToRepo(ctx, pr.Issue.Repo, permission),
  637. Sender: convert.ToUser(ctx, doer, nil),
  638. }).
  639. WithPullRequest(pr).
  640. Notify(ctx)
  641. }
  642. func (n *actionsNotifier) NewWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) {
  643. ctx = withMethod(ctx, "NewWikiPage")
  644. newNotifyInput(repo, doer, webhook_module.HookEventWiki).WithPayload(&api.WikiPayload{
  645. Action: api.HookWikiCreated,
  646. Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeOwner}),
  647. Sender: convert.ToUser(ctx, doer, nil),
  648. Page: page,
  649. Comment: comment,
  650. }).Notify(ctx)
  651. }
  652. func (n *actionsNotifier) EditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) {
  653. ctx = withMethod(ctx, "EditWikiPage")
  654. newNotifyInput(repo, doer, webhook_module.HookEventWiki).WithPayload(&api.WikiPayload{
  655. Action: api.HookWikiEdited,
  656. Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeOwner}),
  657. Sender: convert.ToUser(ctx, doer, nil),
  658. Page: page,
  659. Comment: comment,
  660. }).Notify(ctx)
  661. }
  662. func (n *actionsNotifier) DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page string) {
  663. ctx = withMethod(ctx, "DeleteWikiPage")
  664. newNotifyInput(repo, doer, webhook_module.HookEventWiki).WithPayload(&api.WikiPayload{
  665. Action: api.HookWikiDeleted,
  666. Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeOwner}),
  667. Sender: convert.ToUser(ctx, doer, nil),
  668. Page: page,
  669. }).Notify(ctx)
  670. }
  671. // MigrateRepository is used to detect workflows after a repository has been migrated
  672. func (n *actionsNotifier) MigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
  673. ctx = withMethod(ctx, "MigrateRepository")
  674. newNotifyInput(repo, doer, webhook_module.HookEventRepository).WithPayload(&api.RepositoryPayload{
  675. Action: api.HookRepoCreated,
  676. Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeOwner}),
  677. Organization: convert.ToUser(ctx, u, nil),
  678. Sender: convert.ToUser(ctx, doer, nil),
  679. }).Notify(ctx)
  680. }
  681. func (n *actionsNotifier) WorkflowRunStatusUpdate(ctx context.Context, repo *repo_model.Repository, sender *user_model.User, run *actions_model.ActionRun) {
  682. ctx = withMethod(ctx, "WorkflowRunStatusUpdate")
  683. var org *api.Organization
  684. if repo.Owner.IsOrganization() {
  685. org = convert.ToOrganization(ctx, organization.OrgFromUser(repo.Owner))
  686. }
  687. status := convert.ToWorkflowRunAction(run.Status)
  688. gitRepo, err := gitrepo.OpenRepository(ctx, repo)
  689. if err != nil {
  690. log.Error("OpenRepository: %v", err)
  691. return
  692. }
  693. defer gitRepo.Close()
  694. convertedWorkflow, err := convert.GetActionWorkflow(ctx, gitRepo, repo, run.WorkflowID)
  695. if err != nil {
  696. log.Error("GetActionWorkflow: %v", err)
  697. return
  698. }
  699. convertedRun, err := convert.ToActionWorkflowRun(ctx, repo, run)
  700. if err != nil {
  701. log.Error("ToActionWorkflowRun: %v", err)
  702. return
  703. }
  704. newNotifyInput(repo, sender, webhook_module.HookEventWorkflowRun).WithPayload(&api.WorkflowRunPayload{
  705. Action: status,
  706. Workflow: convertedWorkflow,
  707. WorkflowRun: convertedRun,
  708. Organization: org,
  709. Repo: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeOwner}),
  710. Sender: convert.ToUser(ctx, sender, nil),
  711. }).Notify(ctx)
  712. }