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.

webhook.go 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  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.HookEventPullRequest, &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.HookEventIssues, &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.HookEventPullRequest, 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.HookEventIssues, 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. if err := c.LoadPoster(); err != nil {
  315. log.Error("LoadPoster: %v", err)
  316. return
  317. }
  318. if err := c.LoadIssue(); err != nil {
  319. log.Error("LoadIssue: %v", err)
  320. return
  321. }
  322. if err := c.Issue.LoadAttributes(); err != nil {
  323. log.Error("LoadAttributes: %v", err)
  324. return
  325. }
  326. mode, _ := models.AccessLevel(doer, c.Issue.Repo)
  327. if err := webhook_module.PrepareWebhooks(c.Issue.Repo, models.HookEventIssueComment, &api.IssueCommentPayload{
  328. Action: api.HookIssueCommentEdited,
  329. Issue: convert.ToAPIIssue(c.Issue),
  330. Comment: c.APIFormat(),
  331. Changes: &api.ChangesPayload{
  332. Body: &api.ChangesFromPayload{
  333. From: oldContent,
  334. },
  335. },
  336. Repository: c.Issue.Repo.APIFormat(mode),
  337. Sender: doer.APIFormat(),
  338. IsPull: c.Issue.IsPull,
  339. }); err != nil {
  340. log.Error("PrepareWebhooks [comment_id: %d]: %v", c.ID, err)
  341. }
  342. }
  343. func (m *webhookNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
  344. issue *models.Issue, comment *models.Comment) {
  345. mode, _ := models.AccessLevel(doer, repo)
  346. if err := webhook_module.PrepareWebhooks(repo, models.HookEventIssueComment, &api.IssueCommentPayload{
  347. Action: api.HookIssueCommentCreated,
  348. Issue: convert.ToAPIIssue(issue),
  349. Comment: comment.APIFormat(),
  350. Repository: repo.APIFormat(mode),
  351. Sender: doer.APIFormat(),
  352. IsPull: issue.IsPull,
  353. }); err != nil {
  354. log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
  355. }
  356. }
  357. func (m *webhookNotifier) NotifyDeleteComment(doer *models.User, comment *models.Comment) {
  358. if err := comment.LoadPoster(); err != nil {
  359. log.Error("LoadPoster: %v", err)
  360. return
  361. }
  362. if err := comment.LoadIssue(); err != nil {
  363. log.Error("LoadIssue: %v", err)
  364. return
  365. }
  366. if err := comment.Issue.LoadAttributes(); err != nil {
  367. log.Error("LoadAttributes: %v", err)
  368. return
  369. }
  370. mode, _ := models.AccessLevel(doer, comment.Issue.Repo)
  371. if err := webhook_module.PrepareWebhooks(comment.Issue.Repo, models.HookEventIssueComment, &api.IssueCommentPayload{
  372. Action: api.HookIssueCommentDeleted,
  373. Issue: convert.ToAPIIssue(comment.Issue),
  374. Comment: comment.APIFormat(),
  375. Repository: comment.Issue.Repo.APIFormat(mode),
  376. Sender: doer.APIFormat(),
  377. IsPull: comment.Issue.IsPull,
  378. }); err != nil {
  379. log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
  380. }
  381. }
  382. func (m *webhookNotifier) NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
  383. addedLabels []*models.Label, removedLabels []*models.Label) {
  384. var err error
  385. if err = issue.LoadRepo(); err != nil {
  386. log.Error("LoadRepo: %v", err)
  387. return
  388. }
  389. if err = issue.LoadPoster(); err != nil {
  390. log.Error("LoadPoster: %v", err)
  391. return
  392. }
  393. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  394. if issue.IsPull {
  395. if err = issue.LoadPullRequest(); err != nil {
  396. log.Error("loadPullRequest: %v", err)
  397. return
  398. }
  399. if err = issue.PullRequest.LoadIssue(); err != nil {
  400. log.Error("LoadIssue: %v", err)
  401. return
  402. }
  403. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  404. Action: api.HookIssueLabelUpdated,
  405. Index: issue.Index,
  406. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  407. Repository: issue.Repo.APIFormat(models.AccessModeNone),
  408. Sender: doer.APIFormat(),
  409. })
  410. } else {
  411. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
  412. Action: api.HookIssueLabelUpdated,
  413. Index: issue.Index,
  414. Issue: convert.ToAPIIssue(issue),
  415. Repository: issue.Repo.APIFormat(mode),
  416. Sender: doer.APIFormat(),
  417. })
  418. }
  419. if err != nil {
  420. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  421. }
  422. }
  423. func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *models.User, issue *models.Issue, oldMilestoneID int64) {
  424. var hookAction api.HookIssueAction
  425. var err error
  426. if issue.MilestoneID > 0 {
  427. hookAction = api.HookIssueMilestoned
  428. } else {
  429. hookAction = api.HookIssueDemilestoned
  430. }
  431. if err = issue.LoadAttributes(); err != nil {
  432. log.Error("issue.LoadAttributes failed: %v", err)
  433. return
  434. }
  435. mode, _ := models.AccessLevel(doer, issue.Repo)
  436. if issue.IsPull {
  437. err = issue.PullRequest.LoadIssue()
  438. if err != nil {
  439. log.Error("LoadIssue: %v", err)
  440. return
  441. }
  442. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  443. Action: hookAction,
  444. Index: issue.Index,
  445. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  446. Repository: issue.Repo.APIFormat(mode),
  447. Sender: doer.APIFormat(),
  448. })
  449. } else {
  450. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
  451. Action: hookAction,
  452. Index: issue.Index,
  453. Issue: convert.ToAPIIssue(issue),
  454. Repository: issue.Repo.APIFormat(mode),
  455. Sender: doer.APIFormat(),
  456. })
  457. }
  458. if err != nil {
  459. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  460. }
  461. }
  462. func (m *webhookNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *repository.PushCommits) {
  463. apiPusher := pusher.APIFormat()
  464. apiCommits, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL())
  465. if err != nil {
  466. log.Error("commits.ToAPIPayloadCommits failed: %v", err)
  467. return
  468. }
  469. if err := webhook_module.PrepareWebhooks(repo, models.HookEventPush, &api.PushPayload{
  470. Ref: refName,
  471. Before: oldCommitID,
  472. After: newCommitID,
  473. CompareURL: setting.AppURL + commits.CompareURL,
  474. Commits: apiCommits,
  475. Repo: repo.APIFormat(models.AccessModeOwner),
  476. Pusher: apiPusher,
  477. Sender: apiPusher,
  478. }); err != nil {
  479. log.Error("PrepareWebhooks: %v", err)
  480. }
  481. }
  482. func (*webhookNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *models.User) {
  483. // Reload pull request information.
  484. if err := pr.LoadAttributes(); err != nil {
  485. log.Error("LoadAttributes: %v", err)
  486. return
  487. }
  488. if err := pr.LoadIssue(); err != nil {
  489. log.Error("LoadAttributes: %v", err)
  490. return
  491. }
  492. if err := pr.Issue.LoadRepo(); err != nil {
  493. log.Error("pr.Issue.LoadRepo: %v", err)
  494. return
  495. }
  496. mode, err := models.AccessLevel(doer, pr.Issue.Repo)
  497. if err != nil {
  498. log.Error("models.AccessLevel: %v", err)
  499. return
  500. }
  501. // Merge pull request calls issue.changeStatus so we need to handle separately.
  502. apiPullRequest := &api.PullRequestPayload{
  503. Index: pr.Issue.Index,
  504. PullRequest: convert.ToAPIPullRequest(pr),
  505. Repository: pr.Issue.Repo.APIFormat(mode),
  506. Sender: doer.APIFormat(),
  507. Action: api.HookIssueClosed,
  508. }
  509. err = webhook_module.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequest, apiPullRequest)
  510. if err != nil {
  511. log.Error("PrepareWebhooks: %v", err)
  512. }
  513. }
  514. func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullRequest, oldBranch string) {
  515. issue := pr.Issue
  516. if !issue.IsPull {
  517. return
  518. }
  519. var err error
  520. if err = issue.LoadPullRequest(); err != nil {
  521. log.Error("LoadPullRequest failed: %v", err)
  522. return
  523. }
  524. issue.PullRequest.Issue = issue
  525. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  526. err = webhook_module.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  527. Action: api.HookIssueEdited,
  528. Index: issue.Index,
  529. Changes: &api.ChangesPayload{
  530. Ref: &api.ChangesFromPayload{
  531. From: oldBranch,
  532. },
  533. },
  534. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  535. Repository: issue.Repo.APIFormat(mode),
  536. Sender: doer.APIFormat(),
  537. })
  538. if err != nil {
  539. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  540. }
  541. }
  542. func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
  543. var reviewHookType models.HookEventType
  544. switch review.Type {
  545. case models.ReviewTypeApprove:
  546. reviewHookType = models.HookEventPullRequestApproved
  547. case models.ReviewTypeComment:
  548. reviewHookType = models.HookEventPullRequestComment
  549. case models.ReviewTypeReject:
  550. reviewHookType = models.HookEventPullRequestRejected
  551. default:
  552. // unsupported review webhook type here
  553. log.Error("Unsupported review webhook type")
  554. return
  555. }
  556. if err := pr.LoadIssue(); err != nil {
  557. log.Error("pr.LoadIssue: %v", err)
  558. return
  559. }
  560. mode, err := models.AccessLevel(review.Issue.Poster, review.Issue.Repo)
  561. if err != nil {
  562. log.Error("models.AccessLevel: %v", err)
  563. return
  564. }
  565. if err := webhook_module.PrepareWebhooks(review.Issue.Repo, reviewHookType, &api.PullRequestPayload{
  566. Action: api.HookIssueSynchronized,
  567. Index: review.Issue.Index,
  568. PullRequest: convert.ToAPIPullRequest(pr),
  569. Repository: review.Issue.Repo.APIFormat(mode),
  570. Sender: review.Reviewer.APIFormat(),
  571. Review: &api.ReviewPayload{
  572. Type: string(reviewHookType),
  573. Content: review.Content,
  574. },
  575. }); err != nil {
  576. log.Error("PrepareWebhooks: %v", err)
  577. }
  578. }
  579. func (m *webhookNotifier) NotifyCreateRef(pusher *models.User, repo *models.Repository, refType, refFullName string) {
  580. apiPusher := pusher.APIFormat()
  581. apiRepo := repo.APIFormat(models.AccessModeNone)
  582. refName := git.RefEndName(refFullName)
  583. gitRepo, err := git.OpenRepository(repo.RepoPath())
  584. if err != nil {
  585. log.Error("OpenRepository[%s]: %v", repo.RepoPath(), err)
  586. return
  587. }
  588. shaSum, err := gitRepo.GetRefCommitID(refFullName)
  589. if err != nil {
  590. gitRepo.Close()
  591. log.Error("GetRefCommitID[%s]: %v", refFullName, err)
  592. return
  593. }
  594. gitRepo.Close()
  595. if err = webhook_module.PrepareWebhooks(repo, models.HookEventCreate, &api.CreatePayload{
  596. Ref: refName,
  597. Sha: shaSum,
  598. RefType: refType,
  599. Repo: apiRepo,
  600. Sender: apiPusher,
  601. }); err != nil {
  602. log.Error("PrepareWebhooks: %v", err)
  603. }
  604. }
  605. func (m *webhookNotifier) NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest) {
  606. if err := pr.LoadIssue(); err != nil {
  607. log.Error("pr.LoadIssue: %v", err)
  608. return
  609. }
  610. if err := pr.Issue.LoadAttributes(); err != nil {
  611. log.Error("LoadAttributes: %v", err)
  612. return
  613. }
  614. if err := webhook_module.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  615. Action: api.HookIssueSynchronized,
  616. Index: pr.Issue.Index,
  617. PullRequest: convert.ToAPIPullRequest(pr),
  618. Repository: pr.Issue.Repo.APIFormat(models.AccessModeNone),
  619. Sender: doer.APIFormat(),
  620. }); err != nil {
  621. log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
  622. }
  623. }
  624. func (m *webhookNotifier) NotifyDeleteRef(pusher *models.User, repo *models.Repository, refType, refFullName string) {
  625. apiPusher := pusher.APIFormat()
  626. apiRepo := repo.APIFormat(models.AccessModeNone)
  627. refName := git.RefEndName(refFullName)
  628. if err := webhook_module.PrepareWebhooks(repo, models.HookEventDelete, &api.DeletePayload{
  629. Ref: refName,
  630. RefType: refType,
  631. PusherType: api.PusherTypeUser,
  632. Repo: apiRepo,
  633. Sender: apiPusher,
  634. }); err != nil {
  635. log.Error("PrepareWebhooks.(delete %s): %v", refType, err)
  636. }
  637. }
  638. func sendReleaseHook(doer *models.User, rel *models.Release, action api.HookReleaseAction) {
  639. if err := rel.LoadAttributes(); err != nil {
  640. log.Error("LoadAttributes: %v", err)
  641. return
  642. }
  643. mode, _ := models.AccessLevel(rel.Publisher, rel.Repo)
  644. if err := webhook_module.PrepareWebhooks(rel.Repo, models.HookEventRelease, &api.ReleasePayload{
  645. Action: action,
  646. Release: rel.APIFormat(),
  647. Repository: rel.Repo.APIFormat(mode),
  648. Sender: rel.Publisher.APIFormat(),
  649. }); err != nil {
  650. log.Error("PrepareWebhooks: %v", err)
  651. }
  652. }
  653. func (m *webhookNotifier) NotifyNewRelease(rel *models.Release) {
  654. sendReleaseHook(rel.Publisher, rel, api.HookReleasePublished)
  655. }
  656. func (m *webhookNotifier) NotifyUpdateRelease(doer *models.User, rel *models.Release) {
  657. sendReleaseHook(doer, rel, api.HookReleaseUpdated)
  658. }
  659. func (m *webhookNotifier) NotifyDeleteRelease(doer *models.User, rel *models.Release) {
  660. sendReleaseHook(doer, rel, api.HookReleaseDeleted)
  661. }
  662. func (m *webhookNotifier) NotifySyncPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *repository.PushCommits) {
  663. apiPusher := pusher.APIFormat()
  664. apiCommits, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL())
  665. if err != nil {
  666. log.Error("commits.ToAPIPayloadCommits failed: %v", err)
  667. return
  668. }
  669. if err := webhook_module.PrepareWebhooks(repo, models.HookEventPush, &api.PushPayload{
  670. Ref: refName,
  671. Before: oldCommitID,
  672. After: newCommitID,
  673. CompareURL: setting.AppURL + commits.CompareURL,
  674. Commits: apiCommits,
  675. Repo: repo.APIFormat(models.AccessModeOwner),
  676. Pusher: apiPusher,
  677. Sender: apiPusher,
  678. }); err != nil {
  679. log.Error("PrepareWebhooks: %v", err)
  680. }
  681. }