You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package webhook
  5. import (
  6. "code.gitea.io/gitea/models"
  7. "code.gitea.io/gitea/modules/convert"
  8. "code.gitea.io/gitea/modules/git"
  9. "code.gitea.io/gitea/modules/log"
  10. "code.gitea.io/gitea/modules/notification/base"
  11. "code.gitea.io/gitea/modules/repository"
  12. "code.gitea.io/gitea/modules/setting"
  13. api "code.gitea.io/gitea/modules/structs"
  14. webhook_module "code.gitea.io/gitea/modules/webhook"
  15. )
  16. type webhookNotifier struct {
  17. base.NullNotifier
  18. }
  19. var (
  20. _ base.Notifier = &webhookNotifier{}
  21. )
  22. // NewNotifier create a new webhookNotifier notifier
  23. func NewNotifier() base.Notifier {
  24. return &webhookNotifier{}
  25. }
  26. func (m *webhookNotifier) NotifyIssueClearLabels(doer *models.User, issue *models.Issue) {
  27. if err := issue.LoadPoster(); err != nil {
  28. log.Error("loadPoster: %v", err)
  29. return
  30. }
  31. if err := issue.LoadRepo(); err != nil {
  32. log.Error("LoadRepo: %v", err)
  33. return
  34. }
  35. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  36. var err error
  37. if issue.IsPull {
  38. if err = issue.LoadPullRequest(); err != nil {
  39. log.Error("LoadPullRequest: %v", err)
  40. return
  41. }
  42. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequestLabel, &api.PullRequestPayload{
  43. Action: api.HookIssueLabelCleared,
  44. Index: issue.Index,
  45. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  46. Repository: issue.Repo.APIFormat(mode),
  47. Sender: doer.APIFormat(),
  48. })
  49. } else {
  50. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssueLabel, &api.IssuePayload{
  51. Action: api.HookIssueLabelCleared,
  52. Index: issue.Index,
  53. Issue: convert.ToAPIIssue(issue),
  54. Repository: issue.Repo.APIFormat(mode),
  55. Sender: doer.APIFormat(),
  56. })
  57. }
  58. if err != nil {
  59. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  60. }
  61. }
  62. func (m *webhookNotifier) NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) {
  63. oldMode, _ := models.AccessLevel(doer, oldRepo)
  64. mode, _ := models.AccessLevel(doer, repo)
  65. // forked webhook
  66. if err := webhook_module.PrepareWebhooks(oldRepo, models.HookEventFork, &api.ForkPayload{
  67. Forkee: oldRepo.APIFormat(oldMode),
  68. Repo: repo.APIFormat(mode),
  69. Sender: doer.APIFormat(),
  70. }); err != nil {
  71. log.Error("PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err)
  72. }
  73. u := repo.MustOwner()
  74. // Add to hook queue for created repo after session commit.
  75. if u.IsOrganization() {
  76. if err := webhook_module.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
  77. Action: api.HookRepoCreated,
  78. Repository: repo.APIFormat(models.AccessModeOwner),
  79. Organization: u.APIFormat(),
  80. Sender: doer.APIFormat(),
  81. }); err != nil {
  82. log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
  83. }
  84. }
  85. }
  86. func (m *webhookNotifier) NotifyCreateRepository(doer *models.User, u *models.User, repo *models.Repository) {
  87. // Add to hook queue for created repo after session commit.
  88. if u.IsOrganization() {
  89. if err := webhook_module.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
  90. Action: api.HookRepoCreated,
  91. Repository: repo.APIFormat(models.AccessModeOwner),
  92. Organization: u.APIFormat(),
  93. Sender: doer.APIFormat(),
  94. }); err != nil {
  95. log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
  96. }
  97. }
  98. }
  99. func (m *webhookNotifier) NotifyDeleteRepository(doer *models.User, repo *models.Repository) {
  100. u := repo.MustOwner()
  101. if u.IsOrganization() {
  102. if err := webhook_module.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
  103. Action: api.HookRepoDeleted,
  104. Repository: repo.APIFormat(models.AccessModeOwner),
  105. Organization: u.APIFormat(),
  106. Sender: doer.APIFormat(),
  107. }); err != nil {
  108. log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
  109. }
  110. }
  111. }
  112. func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment) {
  113. if issue.IsPull {
  114. mode, _ := models.AccessLevelUnit(doer, issue.Repo, models.UnitTypePullRequests)
  115. if err := issue.LoadPullRequest(); err != nil {
  116. log.Error("LoadPullRequest failed: %v", err)
  117. return
  118. }
  119. issue.PullRequest.Issue = issue
  120. apiPullRequest := &api.PullRequestPayload{
  121. Index: issue.Index,
  122. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  123. Repository: issue.Repo.APIFormat(mode),
  124. Sender: doer.APIFormat(),
  125. }
  126. if removed {
  127. apiPullRequest.Action = api.HookIssueUnassigned
  128. } else {
  129. apiPullRequest.Action = api.HookIssueAssigned
  130. }
  131. // Assignee comment triggers a webhook
  132. if err := webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequestAssign, apiPullRequest); err != nil {
  133. log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
  134. return
  135. }
  136. } else {
  137. mode, _ := models.AccessLevelUnit(doer, issue.Repo, models.UnitTypeIssues)
  138. apiIssue := &api.IssuePayload{
  139. Index: issue.Index,
  140. Issue: convert.ToAPIIssue(issue),
  141. Repository: issue.Repo.APIFormat(mode),
  142. Sender: doer.APIFormat(),
  143. }
  144. if removed {
  145. apiIssue.Action = api.HookIssueUnassigned
  146. } else {
  147. apiIssue.Action = api.HookIssueAssigned
  148. }
  149. // Assignee comment triggers a webhook
  150. if err := webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssueAssign, apiIssue); err != nil {
  151. log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
  152. return
  153. }
  154. }
  155. }
  156. func (m *webhookNotifier) NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle string) {
  157. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  158. var err error
  159. if issue.IsPull {
  160. if err = issue.LoadPullRequest(); err != nil {
  161. log.Error("LoadPullRequest failed: %v", err)
  162. return
  163. }
  164. issue.PullRequest.Issue = issue
  165. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  166. Action: api.HookIssueEdited,
  167. Index: issue.Index,
  168. Changes: &api.ChangesPayload{
  169. Title: &api.ChangesFromPayload{
  170. From: oldTitle,
  171. },
  172. },
  173. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  174. Repository: issue.Repo.APIFormat(mode),
  175. Sender: doer.APIFormat(),
  176. })
  177. } else {
  178. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
  179. Action: api.HookIssueEdited,
  180. Index: issue.Index,
  181. Changes: &api.ChangesPayload{
  182. Title: &api.ChangesFromPayload{
  183. From: oldTitle,
  184. },
  185. },
  186. Issue: convert.ToAPIIssue(issue),
  187. Repository: issue.Repo.APIFormat(mode),
  188. Sender: issue.Poster.APIFormat(),
  189. })
  190. }
  191. if err != nil {
  192. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  193. }
  194. }
  195. func (m *webhookNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
  196. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  197. var err error
  198. if issue.IsPull {
  199. if err = issue.LoadPullRequest(); err != nil {
  200. log.Error("LoadPullRequest: %v", err)
  201. return
  202. }
  203. // Merge pull request calls issue.changeStatus so we need to handle separately.
  204. apiPullRequest := &api.PullRequestPayload{
  205. Index: issue.Index,
  206. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  207. Repository: issue.Repo.APIFormat(mode),
  208. Sender: doer.APIFormat(),
  209. }
  210. if isClosed {
  211. apiPullRequest.Action = api.HookIssueClosed
  212. } else {
  213. apiPullRequest.Action = api.HookIssueReOpened
  214. }
  215. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, apiPullRequest)
  216. } else {
  217. apiIssue := &api.IssuePayload{
  218. Index: issue.Index,
  219. Issue: convert.ToAPIIssue(issue),
  220. Repository: issue.Repo.APIFormat(mode),
  221. Sender: doer.APIFormat(),
  222. }
  223. if isClosed {
  224. apiIssue.Action = api.HookIssueClosed
  225. } else {
  226. apiIssue.Action = api.HookIssueReOpened
  227. }
  228. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssues, apiIssue)
  229. }
  230. if err != nil {
  231. log.Error("PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
  232. }
  233. }
  234. func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue) {
  235. if err := issue.LoadRepo(); err != nil {
  236. log.Error("issue.LoadRepo: %v", err)
  237. return
  238. }
  239. if err := issue.LoadPoster(); err != nil {
  240. log.Error("issue.LoadPoster: %v", err)
  241. return
  242. }
  243. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  244. if err := webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
  245. Action: api.HookIssueOpened,
  246. Index: issue.Index,
  247. Issue: convert.ToAPIIssue(issue),
  248. Repository: issue.Repo.APIFormat(mode),
  249. Sender: issue.Poster.APIFormat(),
  250. }); err != nil {
  251. log.Error("PrepareWebhooks: %v", err)
  252. }
  253. }
  254. func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
  255. if err := pull.LoadIssue(); err != nil {
  256. log.Error("pull.LoadIssue: %v", err)
  257. return
  258. }
  259. if err := pull.Issue.LoadRepo(); err != nil {
  260. log.Error("pull.Issue.LoadRepo: %v", err)
  261. return
  262. }
  263. if err := pull.Issue.LoadPoster(); err != nil {
  264. log.Error("pull.Issue.LoadPoster: %v", err)
  265. return
  266. }
  267. mode, _ := models.AccessLevel(pull.Issue.Poster, pull.Issue.Repo)
  268. if err := webhook_module.PrepareWebhooks(pull.Issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  269. Action: api.HookIssueOpened,
  270. Index: pull.Issue.Index,
  271. PullRequest: convert.ToAPIPullRequest(pull),
  272. Repository: pull.Issue.Repo.APIFormat(mode),
  273. Sender: pull.Issue.Poster.APIFormat(),
  274. }); err != nil {
  275. log.Error("PrepareWebhooks: %v", err)
  276. }
  277. }
  278. func (m *webhookNotifier) NotifyIssueChangeContent(doer *models.User, issue *models.Issue, oldContent string) {
  279. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  280. var err error
  281. if issue.IsPull {
  282. issue.PullRequest.Issue = issue
  283. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  284. Action: api.HookIssueEdited,
  285. Index: issue.Index,
  286. Changes: &api.ChangesPayload{
  287. Body: &api.ChangesFromPayload{
  288. From: oldContent,
  289. },
  290. },
  291. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  292. Repository: issue.Repo.APIFormat(mode),
  293. Sender: doer.APIFormat(),
  294. })
  295. } else {
  296. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
  297. Action: api.HookIssueEdited,
  298. Index: issue.Index,
  299. Changes: &api.ChangesPayload{
  300. Body: &api.ChangesFromPayload{
  301. From: oldContent,
  302. },
  303. },
  304. Issue: convert.ToAPIIssue(issue),
  305. Repository: issue.Repo.APIFormat(mode),
  306. Sender: doer.APIFormat(),
  307. })
  308. }
  309. if err != nil {
  310. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  311. }
  312. }
  313. func (m *webhookNotifier) NotifyUpdateComment(doer *models.User, c *models.Comment, oldContent string) {
  314. var err error
  315. if err = c.LoadPoster(); err != nil {
  316. log.Error("LoadPoster: %v", err)
  317. return
  318. }
  319. if err = c.LoadIssue(); err != nil {
  320. log.Error("LoadIssue: %v", err)
  321. return
  322. }
  323. if err = c.Issue.LoadAttributes(); err != nil {
  324. log.Error("LoadAttributes: %v", err)
  325. return
  326. }
  327. mode, _ := models.AccessLevel(doer, c.Issue.Repo)
  328. if c.Issue.IsPull {
  329. err = webhook_module.PrepareWebhooks(c.Issue.Repo, models.HookEventPullRequestComment, &api.IssueCommentPayload{
  330. Action: api.HookIssueCommentEdited,
  331. Issue: convert.ToAPIIssue(c.Issue),
  332. Comment: c.APIFormat(),
  333. Changes: &api.ChangesPayload{
  334. Body: &api.ChangesFromPayload{
  335. From: oldContent,
  336. },
  337. },
  338. Repository: c.Issue.Repo.APIFormat(mode),
  339. Sender: doer.APIFormat(),
  340. IsPull: true,
  341. })
  342. } else {
  343. err = webhook_module.PrepareWebhooks(c.Issue.Repo, models.HookEventIssueComment, &api.IssueCommentPayload{
  344. Action: api.HookIssueCommentEdited,
  345. Issue: convert.ToAPIIssue(c.Issue),
  346. Comment: c.APIFormat(),
  347. Changes: &api.ChangesPayload{
  348. Body: &api.ChangesFromPayload{
  349. From: oldContent,
  350. },
  351. },
  352. Repository: c.Issue.Repo.APIFormat(mode),
  353. Sender: doer.APIFormat(),
  354. IsPull: false,
  355. })
  356. }
  357. if err != nil {
  358. log.Error("PrepareWebhooks [comment_id: %d]: %v", c.ID, err)
  359. }
  360. }
  361. func (m *webhookNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
  362. issue *models.Issue, comment *models.Comment) {
  363. mode, _ := models.AccessLevel(doer, repo)
  364. var err error
  365. if issue.IsPull {
  366. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequestComment, &api.IssueCommentPayload{
  367. Action: api.HookIssueCommentCreated,
  368. Issue: convert.ToAPIIssue(issue),
  369. Comment: comment.APIFormat(),
  370. Repository: repo.APIFormat(mode),
  371. Sender: doer.APIFormat(),
  372. IsPull: true,
  373. })
  374. } else {
  375. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssueComment, &api.IssueCommentPayload{
  376. Action: api.HookIssueCommentCreated,
  377. Issue: convert.ToAPIIssue(issue),
  378. Comment: comment.APIFormat(),
  379. Repository: repo.APIFormat(mode),
  380. Sender: doer.APIFormat(),
  381. IsPull: false,
  382. })
  383. }
  384. if err != nil {
  385. log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
  386. }
  387. }
  388. func (m *webhookNotifier) NotifyDeleteComment(doer *models.User, comment *models.Comment) {
  389. var err error
  390. if err = comment.LoadPoster(); err != nil {
  391. log.Error("LoadPoster: %v", err)
  392. return
  393. }
  394. if err = comment.LoadIssue(); err != nil {
  395. log.Error("LoadIssue: %v", err)
  396. return
  397. }
  398. if err = comment.Issue.LoadAttributes(); err != nil {
  399. log.Error("LoadAttributes: %v", err)
  400. return
  401. }
  402. mode, _ := models.AccessLevel(doer, comment.Issue.Repo)
  403. if comment.Issue.IsPull {
  404. err = webhook_module.PrepareWebhooks(comment.Issue.Repo, models.HookEventPullRequestComment, &api.IssueCommentPayload{
  405. Action: api.HookIssueCommentDeleted,
  406. Issue: convert.ToAPIIssue(comment.Issue),
  407. Comment: comment.APIFormat(),
  408. Repository: comment.Issue.Repo.APIFormat(mode),
  409. Sender: doer.APIFormat(),
  410. IsPull: true,
  411. })
  412. } else {
  413. err = webhook_module.PrepareWebhooks(comment.Issue.Repo, models.HookEventIssueComment, &api.IssueCommentPayload{
  414. Action: api.HookIssueCommentDeleted,
  415. Issue: convert.ToAPIIssue(comment.Issue),
  416. Comment: comment.APIFormat(),
  417. Repository: comment.Issue.Repo.APIFormat(mode),
  418. Sender: doer.APIFormat(),
  419. IsPull: false,
  420. })
  421. }
  422. if err != nil {
  423. log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
  424. }
  425. }
  426. func (m *webhookNotifier) NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
  427. addedLabels []*models.Label, removedLabels []*models.Label) {
  428. var err error
  429. if err = issue.LoadRepo(); err != nil {
  430. log.Error("LoadRepo: %v", err)
  431. return
  432. }
  433. if err = issue.LoadPoster(); err != nil {
  434. log.Error("LoadPoster: %v", err)
  435. return
  436. }
  437. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  438. if issue.IsPull {
  439. if err = issue.LoadPullRequest(); err != nil {
  440. log.Error("loadPullRequest: %v", err)
  441. return
  442. }
  443. if err = issue.PullRequest.LoadIssue(); err != nil {
  444. log.Error("LoadIssue: %v", err)
  445. return
  446. }
  447. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequestLabel, &api.PullRequestPayload{
  448. Action: api.HookIssueLabelUpdated,
  449. Index: issue.Index,
  450. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  451. Repository: issue.Repo.APIFormat(models.AccessModeNone),
  452. Sender: doer.APIFormat(),
  453. })
  454. } else {
  455. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssueLabel, &api.IssuePayload{
  456. Action: api.HookIssueLabelUpdated,
  457. Index: issue.Index,
  458. Issue: convert.ToAPIIssue(issue),
  459. Repository: issue.Repo.APIFormat(mode),
  460. Sender: doer.APIFormat(),
  461. })
  462. }
  463. if err != nil {
  464. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  465. }
  466. }
  467. func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *models.User, issue *models.Issue, oldMilestoneID int64) {
  468. var hookAction api.HookIssueAction
  469. var err error
  470. if issue.MilestoneID > 0 {
  471. hookAction = api.HookIssueMilestoned
  472. } else {
  473. hookAction = api.HookIssueDemilestoned
  474. }
  475. if err = issue.LoadAttributes(); err != nil {
  476. log.Error("issue.LoadAttributes failed: %v", err)
  477. return
  478. }
  479. mode, _ := models.AccessLevel(doer, issue.Repo)
  480. if issue.IsPull {
  481. err = issue.PullRequest.LoadIssue()
  482. if err != nil {
  483. log.Error("LoadIssue: %v", err)
  484. return
  485. }
  486. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequestMilestone, &api.PullRequestPayload{
  487. Action: hookAction,
  488. Index: issue.Index,
  489. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  490. Repository: issue.Repo.APIFormat(mode),
  491. Sender: doer.APIFormat(),
  492. })
  493. } else {
  494. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssueMilestone, &api.IssuePayload{
  495. Action: hookAction,
  496. Index: issue.Index,
  497. Issue: convert.ToAPIIssue(issue),
  498. Repository: issue.Repo.APIFormat(mode),
  499. Sender: doer.APIFormat(),
  500. })
  501. }
  502. if err != nil {
  503. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  504. }
  505. }
  506. func (m *webhookNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *repository.PushCommits) {
  507. apiPusher := pusher.APIFormat()
  508. apiCommits, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL())
  509. if err != nil {
  510. log.Error("commits.ToAPIPayloadCommits failed: %v", err)
  511. return
  512. }
  513. if err := webhook_module.PrepareWebhooks(repo, models.HookEventPush, &api.PushPayload{
  514. Ref: refName,
  515. Before: oldCommitID,
  516. After: newCommitID,
  517. CompareURL: setting.AppURL + commits.CompareURL,
  518. Commits: apiCommits,
  519. Repo: repo.APIFormat(models.AccessModeOwner),
  520. Pusher: apiPusher,
  521. Sender: apiPusher,
  522. }); err != nil {
  523. log.Error("PrepareWebhooks: %v", err)
  524. }
  525. }
  526. func (*webhookNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *models.User) {
  527. // Reload pull request information.
  528. if err := pr.LoadAttributes(); err != nil {
  529. log.Error("LoadAttributes: %v", err)
  530. return
  531. }
  532. if err := pr.LoadIssue(); err != nil {
  533. log.Error("LoadAttributes: %v", err)
  534. return
  535. }
  536. if err := pr.Issue.LoadRepo(); err != nil {
  537. log.Error("pr.Issue.LoadRepo: %v", err)
  538. return
  539. }
  540. mode, err := models.AccessLevel(doer, pr.Issue.Repo)
  541. if err != nil {
  542. log.Error("models.AccessLevel: %v", err)
  543. return
  544. }
  545. // Merge pull request calls issue.changeStatus so we need to handle separately.
  546. apiPullRequest := &api.PullRequestPayload{
  547. Index: pr.Issue.Index,
  548. PullRequest: convert.ToAPIPullRequest(pr),
  549. Repository: pr.Issue.Repo.APIFormat(mode),
  550. Sender: doer.APIFormat(),
  551. Action: api.HookIssueClosed,
  552. }
  553. err = webhook_module.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequest, apiPullRequest)
  554. if err != nil {
  555. log.Error("PrepareWebhooks: %v", err)
  556. }
  557. }
  558. func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullRequest, oldBranch string) {
  559. issue := pr.Issue
  560. if !issue.IsPull {
  561. return
  562. }
  563. var err error
  564. if err = issue.LoadPullRequest(); err != nil {
  565. log.Error("LoadPullRequest failed: %v", err)
  566. return
  567. }
  568. issue.PullRequest.Issue = issue
  569. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  570. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  571. Action: api.HookIssueEdited,
  572. Index: issue.Index,
  573. Changes: &api.ChangesPayload{
  574. Ref: &api.ChangesFromPayload{
  575. From: oldBranch,
  576. },
  577. },
  578. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  579. Repository: issue.Repo.APIFormat(mode),
  580. Sender: doer.APIFormat(),
  581. })
  582. if err != nil {
  583. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  584. }
  585. }
  586. func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
  587. var reviewHookType models.HookEventType
  588. switch review.Type {
  589. case models.ReviewTypeApprove:
  590. reviewHookType = models.HookEventPullRequestReviewApproved
  591. case models.ReviewTypeComment:
  592. reviewHookType = models.HookEventPullRequestComment
  593. case models.ReviewTypeReject:
  594. reviewHookType = models.HookEventPullRequestReviewRejected
  595. default:
  596. // unsupported review webhook type here
  597. log.Error("Unsupported review webhook type")
  598. return
  599. }
  600. if err := pr.LoadIssue(); err != nil {
  601. log.Error("pr.LoadIssue: %v", err)
  602. return
  603. }
  604. mode, err := models.AccessLevel(review.Issue.Poster, review.Issue.Repo)
  605. if err != nil {
  606. log.Error("models.AccessLevel: %v", err)
  607. return
  608. }
  609. if err := webhook_module.PrepareWebhooks(review.Issue.Repo, reviewHookType, &api.PullRequestPayload{
  610. Action: api.HookIssueReviewed,
  611. Index: review.Issue.Index,
  612. PullRequest: convert.ToAPIPullRequest(pr),
  613. Repository: review.Issue.Repo.APIFormat(mode),
  614. Sender: review.Reviewer.APIFormat(),
  615. Review: &api.ReviewPayload{
  616. Type: string(reviewHookType),
  617. Content: review.Content,
  618. },
  619. }); err != nil {
  620. log.Error("PrepareWebhooks: %v", err)
  621. }
  622. }
  623. func (m *webhookNotifier) NotifyCreateRef(pusher *models.User, repo *models.Repository, refType, refFullName string) {
  624. apiPusher := pusher.APIFormat()
  625. apiRepo := repo.APIFormat(models.AccessModeNone)
  626. refName := git.RefEndName(refFullName)
  627. gitRepo, err := git.OpenRepository(repo.RepoPath())
  628. if err != nil {
  629. log.Error("OpenRepository[%s]: %v", repo.RepoPath(), err)
  630. return
  631. }
  632. shaSum, err := gitRepo.GetRefCommitID(refFullName)
  633. if err != nil {
  634. gitRepo.Close()
  635. log.Error("GetRefCommitID[%s]: %v", refFullName, err)
  636. return
  637. }
  638. gitRepo.Close()
  639. if err = webhook_module.PrepareWebhooks(repo, models.HookEventCreate, &api.CreatePayload{
  640. Ref: refName,
  641. Sha: shaSum,
  642. RefType: refType,
  643. Repo: apiRepo,
  644. Sender: apiPusher,
  645. }); err != nil {
  646. log.Error("PrepareWebhooks: %v", err)
  647. }
  648. }
  649. func (m *webhookNotifier) NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest) {
  650. if err := pr.LoadIssue(); err != nil {
  651. log.Error("pr.LoadIssue: %v", err)
  652. return
  653. }
  654. if err := pr.Issue.LoadAttributes(); err != nil {
  655. log.Error("LoadAttributes: %v", err)
  656. return
  657. }
  658. if err := webhook_module.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequestSync, &api.PullRequestPayload{
  659. Action: api.HookIssueSynchronized,
  660. Index: pr.Issue.Index,
  661. PullRequest: convert.ToAPIPullRequest(pr),
  662. Repository: pr.Issue.Repo.APIFormat(models.AccessModeNone),
  663. Sender: doer.APIFormat(),
  664. }); err != nil {
  665. log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
  666. }
  667. }
  668. func (m *webhookNotifier) NotifyDeleteRef(pusher *models.User, repo *models.Repository, refType, refFullName string) {
  669. apiPusher := pusher.APIFormat()
  670. apiRepo := repo.APIFormat(models.AccessModeNone)
  671. refName := git.RefEndName(refFullName)
  672. if err := webhook_module.PrepareWebhooks(repo, models.HookEventDelete, &api.DeletePayload{
  673. Ref: refName,
  674. RefType: refType,
  675. PusherType: api.PusherTypeUser,
  676. Repo: apiRepo,
  677. Sender: apiPusher,
  678. }); err != nil {
  679. log.Error("PrepareWebhooks.(delete %s): %v", refType, err)
  680. }
  681. }
  682. func sendReleaseHook(doer *models.User, rel *models.Release, action api.HookReleaseAction) {
  683. if err := rel.LoadAttributes(); err != nil {
  684. log.Error("LoadAttributes: %v", err)
  685. return
  686. }
  687. mode, _ := models.AccessLevel(rel.Publisher, rel.Repo)
  688. if err := webhook_module.PrepareWebhooks(rel.Repo, models.HookEventRelease, &api.ReleasePayload{
  689. Action: action,
  690. Release: rel.APIFormat(),
  691. Repository: rel.Repo.APIFormat(mode),
  692. Sender: rel.Publisher.APIFormat(),
  693. }); err != nil {
  694. log.Error("PrepareWebhooks: %v", err)
  695. }
  696. }
  697. func (m *webhookNotifier) NotifyNewRelease(rel *models.Release) {
  698. sendReleaseHook(rel.Publisher, rel, api.HookReleasePublished)
  699. }
  700. func (m *webhookNotifier) NotifyUpdateRelease(doer *models.User, rel *models.Release) {
  701. sendReleaseHook(doer, rel, api.HookReleaseUpdated)
  702. }
  703. func (m *webhookNotifier) NotifyDeleteRelease(doer *models.User, rel *models.Release) {
  704. sendReleaseHook(doer, rel, api.HookReleaseDeleted)
  705. }
  706. func (m *webhookNotifier) NotifySyncPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *repository.PushCommits) {
  707. apiPusher := pusher.APIFormat()
  708. apiCommits, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL())
  709. if err != nil {
  710. log.Error("commits.ToAPIPayloadCommits failed: %v", err)
  711. return
  712. }
  713. if err := webhook_module.PrepareWebhooks(repo, models.HookEventPush, &api.PushPayload{
  714. Ref: refName,
  715. Before: oldCommitID,
  716. After: newCommitID,
  717. CompareURL: setting.AppURL + commits.CompareURL,
  718. Commits: apiCommits,
  719. Repo: repo.APIFormat(models.AccessModeOwner),
  720. Pusher: apiPusher,
  721. Sender: apiPusher,
  722. }); err != nil {
  723. log.Error("PrepareWebhooks: %v", err)
  724. }
  725. }