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

webhook.go 27 kB

Change target branch for pull request (#6488) * Adds functionality to change target branch of created pull requests Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use const instead of var in JavaScript additions Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Check if branches are equal and if PR already exists before changing target branch Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Make sure to check all commits Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Print error messages for user as error flash message Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Disallow changing target branch of closed or merged pull requests Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Resolve conflicts after merge of upstream/master Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Change order of branch select fields Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes duplicate check Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use ctx.Tr for translations Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Recompile JS Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use correct translation namespace Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Remove redundant if condition Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Moves most change branch logic into pull service Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Completes comment Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Add Ref to ChangesPayload for logging changed target branches instead of creating a new struct Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Revert changes to go.mod Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Directly use createComment method Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Return 404 if pull request is not found. Move written check up Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Remove variable declaration Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Return client errors on change pull request target errors Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Return error in commit.HasPreviousCommit Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adds blank line Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Test patch before persisting new target branch Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Update patch before testing (not working) Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes patch calls when changeing pull request target Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes unneeded check for base name Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Moves ChangeTargetBranch completely to pull service. Update patch status. Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Set webhook mode after errors were validated Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Update PR in one transaction Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Move logic for check if head is equal with branch to pull model Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adds missing comment and simplify return Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adjust CreateComment method call Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>
5 years ago
Change target branch for pull request (#6488) * Adds functionality to change target branch of created pull requests Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use const instead of var in JavaScript additions Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Check if branches are equal and if PR already exists before changing target branch Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Make sure to check all commits Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Print error messages for user as error flash message Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Disallow changing target branch of closed or merged pull requests Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Resolve conflicts after merge of upstream/master Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Change order of branch select fields Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes duplicate check Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use ctx.Tr for translations Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Recompile JS Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use correct translation namespace Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Remove redundant if condition Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Moves most change branch logic into pull service Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Completes comment Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Add Ref to ChangesPayload for logging changed target branches instead of creating a new struct Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Revert changes to go.mod Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Directly use createComment method Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Return 404 if pull request is not found. Move written check up Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Remove variable declaration Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Return client errors on change pull request target errors Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Return error in commit.HasPreviousCommit Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adds blank line Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Test patch before persisting new target branch Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Update patch before testing (not working) Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes patch calls when changeing pull request target Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes unneeded check for base name Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Moves ChangeTargetBranch completely to pull service. Update patch status. Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Set webhook mode after errors were validated Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Update PR in one transaction Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Move logic for check if head is equal with branch to pull model Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adds missing comment and simplify return Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adjust CreateComment method call Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>
5 years ago
Change target branch for pull request (#6488) * Adds functionality to change target branch of created pull requests Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use const instead of var in JavaScript additions Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Check if branches are equal and if PR already exists before changing target branch Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Make sure to check all commits Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Print error messages for user as error flash message Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Disallow changing target branch of closed or merged pull requests Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Resolve conflicts after merge of upstream/master Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Change order of branch select fields Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes duplicate check Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use ctx.Tr for translations Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Recompile JS Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use correct translation namespace Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Remove redundant if condition Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Moves most change branch logic into pull service Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Completes comment Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Add Ref to ChangesPayload for logging changed target branches instead of creating a new struct Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Revert changes to go.mod Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Directly use createComment method Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Return 404 if pull request is not found. Move written check up Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Remove variable declaration Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Return client errors on change pull request target errors Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Return error in commit.HasPreviousCommit Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adds blank line Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Test patch before persisting new target branch Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Update patch before testing (not working) Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes patch calls when changeing pull request target Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes unneeded check for base name Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Moves ChangeTargetBranch completely to pull service. Update patch status. Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Set webhook mode after errors were validated Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Update PR in one transaction Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Move logic for check if head is equal with branch to pull model Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adds missing comment and simplify return Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adjust CreateComment method call Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  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_services "code.gitea.io/gitea/services/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_services.PrepareWebhooks(issue.Repo, models.HookEventPullRequestLabel, &api.PullRequestPayload{
  43. Action: api.HookIssueLabelCleared,
  44. Index: issue.Index,
  45. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  46. Repository: convert.ToRepo(issue.Repo, mode),
  47. Sender: convert.ToUser(doer, false, false),
  48. })
  49. } else {
  50. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventIssueLabel, &api.IssuePayload{
  51. Action: api.HookIssueLabelCleared,
  52. Index: issue.Index,
  53. Issue: convert.ToAPIIssue(issue),
  54. Repository: convert.ToRepo(issue.Repo, mode),
  55. Sender: convert.ToUser(doer, false, false),
  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_services.PrepareWebhooks(oldRepo, models.HookEventFork, &api.ForkPayload{
  67. Forkee: convert.ToRepo(oldRepo, oldMode),
  68. Repo: convert.ToRepo(repo, mode),
  69. Sender: convert.ToUser(doer, false, false),
  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_services.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
  77. Action: api.HookRepoCreated,
  78. Repository: convert.ToRepo(repo, models.AccessModeOwner),
  79. Organization: convert.ToUser(u, false, false),
  80. Sender: convert.ToUser(doer, false, false),
  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 err := webhook_services.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
  89. Action: api.HookRepoCreated,
  90. Repository: convert.ToRepo(repo, models.AccessModeOwner),
  91. Organization: convert.ToUser(u, false, false),
  92. Sender: convert.ToUser(doer, false, false),
  93. }); err != nil {
  94. log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
  95. }
  96. }
  97. func (m *webhookNotifier) NotifyDeleteRepository(doer *models.User, repo *models.Repository) {
  98. u := repo.MustOwner()
  99. if err := webhook_services.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
  100. Action: api.HookRepoDeleted,
  101. Repository: convert.ToRepo(repo, models.AccessModeOwner),
  102. Organization: convert.ToUser(u, false, false),
  103. Sender: convert.ToUser(doer, false, false),
  104. }); err != nil {
  105. log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
  106. }
  107. }
  108. func (m *webhookNotifier) NotifyMigrateRepository(doer *models.User, u *models.User, repo *models.Repository) {
  109. // Add to hook queue for created repo after session commit.
  110. if err := webhook_services.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
  111. Action: api.HookRepoCreated,
  112. Repository: convert.ToRepo(repo, models.AccessModeOwner),
  113. Organization: convert.ToUser(u, false, false),
  114. Sender: convert.ToUser(doer, false, false),
  115. }); err != nil {
  116. log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
  117. }
  118. }
  119. func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment) {
  120. if issue.IsPull {
  121. mode, _ := models.AccessLevelUnit(doer, issue.Repo, models.UnitTypePullRequests)
  122. if err := issue.LoadPullRequest(); err != nil {
  123. log.Error("LoadPullRequest failed: %v", err)
  124. return
  125. }
  126. issue.PullRequest.Issue = issue
  127. apiPullRequest := &api.PullRequestPayload{
  128. Index: issue.Index,
  129. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  130. Repository: convert.ToRepo(issue.Repo, mode),
  131. Sender: convert.ToUser(doer, false, false),
  132. }
  133. if removed {
  134. apiPullRequest.Action = api.HookIssueUnassigned
  135. } else {
  136. apiPullRequest.Action = api.HookIssueAssigned
  137. }
  138. // Assignee comment triggers a webhook
  139. if err := webhook_services.PrepareWebhooks(issue.Repo, models.HookEventPullRequestAssign, apiPullRequest); err != nil {
  140. log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
  141. return
  142. }
  143. } else {
  144. mode, _ := models.AccessLevelUnit(doer, issue.Repo, models.UnitTypeIssues)
  145. apiIssue := &api.IssuePayload{
  146. Index: issue.Index,
  147. Issue: convert.ToAPIIssue(issue),
  148. Repository: convert.ToRepo(issue.Repo, mode),
  149. Sender: convert.ToUser(doer, false, false),
  150. }
  151. if removed {
  152. apiIssue.Action = api.HookIssueUnassigned
  153. } else {
  154. apiIssue.Action = api.HookIssueAssigned
  155. }
  156. // Assignee comment triggers a webhook
  157. if err := webhook_services.PrepareWebhooks(issue.Repo, models.HookEventIssueAssign, apiIssue); err != nil {
  158. log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
  159. return
  160. }
  161. }
  162. }
  163. func (m *webhookNotifier) NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle string) {
  164. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  165. var err error
  166. if issue.IsPull {
  167. if err = issue.LoadPullRequest(); err != nil {
  168. log.Error("LoadPullRequest failed: %v", err)
  169. return
  170. }
  171. issue.PullRequest.Issue = issue
  172. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  173. Action: api.HookIssueEdited,
  174. Index: issue.Index,
  175. Changes: &api.ChangesPayload{
  176. Title: &api.ChangesFromPayload{
  177. From: oldTitle,
  178. },
  179. },
  180. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  181. Repository: convert.ToRepo(issue.Repo, mode),
  182. Sender: convert.ToUser(doer, false, false),
  183. })
  184. } else {
  185. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
  186. Action: api.HookIssueEdited,
  187. Index: issue.Index,
  188. Changes: &api.ChangesPayload{
  189. Title: &api.ChangesFromPayload{
  190. From: oldTitle,
  191. },
  192. },
  193. Issue: convert.ToAPIIssue(issue),
  194. Repository: convert.ToRepo(issue.Repo, mode),
  195. Sender: convert.ToUser(issue.Poster, false, false),
  196. })
  197. }
  198. if err != nil {
  199. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  200. }
  201. }
  202. func (m *webhookNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
  203. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  204. var err error
  205. if issue.IsPull {
  206. if err = issue.LoadPullRequest(); err != nil {
  207. log.Error("LoadPullRequest: %v", err)
  208. return
  209. }
  210. // Merge pull request calls issue.changeStatus so we need to handle separately.
  211. apiPullRequest := &api.PullRequestPayload{
  212. Index: issue.Index,
  213. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  214. Repository: convert.ToRepo(issue.Repo, mode),
  215. Sender: convert.ToUser(doer, false, false),
  216. }
  217. if isClosed {
  218. apiPullRequest.Action = api.HookIssueClosed
  219. } else {
  220. apiPullRequest.Action = api.HookIssueReOpened
  221. }
  222. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, apiPullRequest)
  223. } else {
  224. apiIssue := &api.IssuePayload{
  225. Index: issue.Index,
  226. Issue: convert.ToAPIIssue(issue),
  227. Repository: convert.ToRepo(issue.Repo, mode),
  228. Sender: convert.ToUser(doer, false, false),
  229. }
  230. if isClosed {
  231. apiIssue.Action = api.HookIssueClosed
  232. } else {
  233. apiIssue.Action = api.HookIssueReOpened
  234. }
  235. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventIssues, apiIssue)
  236. }
  237. if err != nil {
  238. log.Error("PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
  239. }
  240. }
  241. func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue) {
  242. if err := issue.LoadRepo(); err != nil {
  243. log.Error("issue.LoadRepo: %v", err)
  244. return
  245. }
  246. if err := issue.LoadPoster(); err != nil {
  247. log.Error("issue.LoadPoster: %v", err)
  248. return
  249. }
  250. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  251. if err := webhook_services.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
  252. Action: api.HookIssueOpened,
  253. Index: issue.Index,
  254. Issue: convert.ToAPIIssue(issue),
  255. Repository: convert.ToRepo(issue.Repo, mode),
  256. Sender: convert.ToUser(issue.Poster, false, false),
  257. }); err != nil {
  258. log.Error("PrepareWebhooks: %v", err)
  259. }
  260. }
  261. func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
  262. if err := pull.LoadIssue(); err != nil {
  263. log.Error("pull.LoadIssue: %v", err)
  264. return
  265. }
  266. if err := pull.Issue.LoadRepo(); err != nil {
  267. log.Error("pull.Issue.LoadRepo: %v", err)
  268. return
  269. }
  270. if err := pull.Issue.LoadPoster(); err != nil {
  271. log.Error("pull.Issue.LoadPoster: %v", err)
  272. return
  273. }
  274. mode, _ := models.AccessLevel(pull.Issue.Poster, pull.Issue.Repo)
  275. if err := webhook_services.PrepareWebhooks(pull.Issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  276. Action: api.HookIssueOpened,
  277. Index: pull.Issue.Index,
  278. PullRequest: convert.ToAPIPullRequest(pull),
  279. Repository: convert.ToRepo(pull.Issue.Repo, mode),
  280. Sender: convert.ToUser(pull.Issue.Poster, false, false),
  281. }); err != nil {
  282. log.Error("PrepareWebhooks: %v", err)
  283. }
  284. }
  285. func (m *webhookNotifier) NotifyIssueChangeContent(doer *models.User, issue *models.Issue, oldContent string) {
  286. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  287. var err error
  288. if issue.IsPull {
  289. issue.PullRequest.Issue = issue
  290. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  291. Action: api.HookIssueEdited,
  292. Index: issue.Index,
  293. Changes: &api.ChangesPayload{
  294. Body: &api.ChangesFromPayload{
  295. From: oldContent,
  296. },
  297. },
  298. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  299. Repository: convert.ToRepo(issue.Repo, mode),
  300. Sender: convert.ToUser(doer, false, false),
  301. })
  302. } else {
  303. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
  304. Action: api.HookIssueEdited,
  305. Index: issue.Index,
  306. Changes: &api.ChangesPayload{
  307. Body: &api.ChangesFromPayload{
  308. From: oldContent,
  309. },
  310. },
  311. Issue: convert.ToAPIIssue(issue),
  312. Repository: convert.ToRepo(issue.Repo, mode),
  313. Sender: convert.ToUser(doer, false, false),
  314. })
  315. }
  316. if err != nil {
  317. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  318. }
  319. }
  320. func (m *webhookNotifier) NotifyUpdateComment(doer *models.User, c *models.Comment, oldContent string) {
  321. var err error
  322. if err = c.LoadPoster(); err != nil {
  323. log.Error("LoadPoster: %v", err)
  324. return
  325. }
  326. if err = c.LoadIssue(); err != nil {
  327. log.Error("LoadIssue: %v", err)
  328. return
  329. }
  330. if err = c.Issue.LoadAttributes(); err != nil {
  331. log.Error("LoadAttributes: %v", err)
  332. return
  333. }
  334. mode, _ := models.AccessLevel(doer, c.Issue.Repo)
  335. if c.Issue.IsPull {
  336. err = webhook_services.PrepareWebhooks(c.Issue.Repo, models.HookEventPullRequestComment, &api.IssueCommentPayload{
  337. Action: api.HookIssueCommentEdited,
  338. Issue: convert.ToAPIIssue(c.Issue),
  339. Comment: convert.ToComment(c),
  340. Changes: &api.ChangesPayload{
  341. Body: &api.ChangesFromPayload{
  342. From: oldContent,
  343. },
  344. },
  345. Repository: convert.ToRepo(c.Issue.Repo, mode),
  346. Sender: convert.ToUser(doer, false, false),
  347. IsPull: true,
  348. })
  349. } else {
  350. err = webhook_services.PrepareWebhooks(c.Issue.Repo, models.HookEventIssueComment, &api.IssueCommentPayload{
  351. Action: api.HookIssueCommentEdited,
  352. Issue: convert.ToAPIIssue(c.Issue),
  353. Comment: convert.ToComment(c),
  354. Changes: &api.ChangesPayload{
  355. Body: &api.ChangesFromPayload{
  356. From: oldContent,
  357. },
  358. },
  359. Repository: convert.ToRepo(c.Issue.Repo, mode),
  360. Sender: convert.ToUser(doer, false, false),
  361. IsPull: false,
  362. })
  363. }
  364. if err != nil {
  365. log.Error("PrepareWebhooks [comment_id: %d]: %v", c.ID, err)
  366. }
  367. }
  368. func (m *webhookNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
  369. issue *models.Issue, comment *models.Comment) {
  370. mode, _ := models.AccessLevel(doer, repo)
  371. var err error
  372. if issue.IsPull {
  373. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventPullRequestComment, &api.IssueCommentPayload{
  374. Action: api.HookIssueCommentCreated,
  375. Issue: convert.ToAPIIssue(issue),
  376. Comment: convert.ToComment(comment),
  377. Repository: convert.ToRepo(repo, mode),
  378. Sender: convert.ToUser(doer, false, false),
  379. IsPull: true,
  380. })
  381. } else {
  382. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventIssueComment, &api.IssueCommentPayload{
  383. Action: api.HookIssueCommentCreated,
  384. Issue: convert.ToAPIIssue(issue),
  385. Comment: convert.ToComment(comment),
  386. Repository: convert.ToRepo(repo, mode),
  387. Sender: convert.ToUser(doer, false, false),
  388. IsPull: false,
  389. })
  390. }
  391. if err != nil {
  392. log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
  393. }
  394. }
  395. func (m *webhookNotifier) NotifyDeleteComment(doer *models.User, comment *models.Comment) {
  396. var err error
  397. if err = comment.LoadPoster(); err != nil {
  398. log.Error("LoadPoster: %v", err)
  399. return
  400. }
  401. if err = comment.LoadIssue(); err != nil {
  402. log.Error("LoadIssue: %v", err)
  403. return
  404. }
  405. if err = comment.Issue.LoadAttributes(); err != nil {
  406. log.Error("LoadAttributes: %v", err)
  407. return
  408. }
  409. mode, _ := models.AccessLevel(doer, comment.Issue.Repo)
  410. if comment.Issue.IsPull {
  411. err = webhook_services.PrepareWebhooks(comment.Issue.Repo, models.HookEventPullRequestComment, &api.IssueCommentPayload{
  412. Action: api.HookIssueCommentDeleted,
  413. Issue: convert.ToAPIIssue(comment.Issue),
  414. Comment: convert.ToComment(comment),
  415. Repository: convert.ToRepo(comment.Issue.Repo, mode),
  416. Sender: convert.ToUser(doer, false, false),
  417. IsPull: true,
  418. })
  419. } else {
  420. err = webhook_services.PrepareWebhooks(comment.Issue.Repo, models.HookEventIssueComment, &api.IssueCommentPayload{
  421. Action: api.HookIssueCommentDeleted,
  422. Issue: convert.ToAPIIssue(comment.Issue),
  423. Comment: convert.ToComment(comment),
  424. Repository: convert.ToRepo(comment.Issue.Repo, mode),
  425. Sender: convert.ToUser(doer, false, false),
  426. IsPull: false,
  427. })
  428. }
  429. if err != nil {
  430. log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
  431. }
  432. }
  433. func (m *webhookNotifier) NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
  434. addedLabels []*models.Label, removedLabels []*models.Label) {
  435. var err error
  436. if err = issue.LoadRepo(); err != nil {
  437. log.Error("LoadRepo: %v", err)
  438. return
  439. }
  440. if err = issue.LoadPoster(); err != nil {
  441. log.Error("LoadPoster: %v", err)
  442. return
  443. }
  444. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  445. if issue.IsPull {
  446. if err = issue.LoadPullRequest(); err != nil {
  447. log.Error("loadPullRequest: %v", err)
  448. return
  449. }
  450. if err = issue.PullRequest.LoadIssue(); err != nil {
  451. log.Error("LoadIssue: %v", err)
  452. return
  453. }
  454. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventPullRequestLabel, &api.PullRequestPayload{
  455. Action: api.HookIssueLabelUpdated,
  456. Index: issue.Index,
  457. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  458. Repository: convert.ToRepo(issue.Repo, models.AccessModeNone),
  459. Sender: convert.ToUser(doer, false, false),
  460. })
  461. } else {
  462. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventIssueLabel, &api.IssuePayload{
  463. Action: api.HookIssueLabelUpdated,
  464. Index: issue.Index,
  465. Issue: convert.ToAPIIssue(issue),
  466. Repository: convert.ToRepo(issue.Repo, mode),
  467. Sender: convert.ToUser(doer, false, false),
  468. })
  469. }
  470. if err != nil {
  471. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  472. }
  473. }
  474. func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *models.User, issue *models.Issue, oldMilestoneID int64) {
  475. var hookAction api.HookIssueAction
  476. var err error
  477. if issue.MilestoneID > 0 {
  478. hookAction = api.HookIssueMilestoned
  479. } else {
  480. hookAction = api.HookIssueDemilestoned
  481. }
  482. if err = issue.LoadAttributes(); err != nil {
  483. log.Error("issue.LoadAttributes failed: %v", err)
  484. return
  485. }
  486. mode, _ := models.AccessLevel(doer, issue.Repo)
  487. if issue.IsPull {
  488. err = issue.PullRequest.LoadIssue()
  489. if err != nil {
  490. log.Error("LoadIssue: %v", err)
  491. return
  492. }
  493. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventPullRequestMilestone, &api.PullRequestPayload{
  494. Action: hookAction,
  495. Index: issue.Index,
  496. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  497. Repository: convert.ToRepo(issue.Repo, mode),
  498. Sender: convert.ToUser(doer, false, false),
  499. })
  500. } else {
  501. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventIssueMilestone, &api.IssuePayload{
  502. Action: hookAction,
  503. Index: issue.Index,
  504. Issue: convert.ToAPIIssue(issue),
  505. Repository: convert.ToRepo(issue.Repo, mode),
  506. Sender: convert.ToUser(doer, false, false),
  507. })
  508. }
  509. if err != nil {
  510. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  511. }
  512. }
  513. func (m *webhookNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
  514. apiPusher := convert.ToUser(pusher, false, false)
  515. apiCommits, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL())
  516. if err != nil {
  517. log.Error("commits.ToAPIPayloadCommits failed: %v", err)
  518. return
  519. }
  520. if err := webhook_services.PrepareWebhooks(repo, models.HookEventPush, &api.PushPayload{
  521. Ref: opts.RefFullName,
  522. Before: opts.OldCommitID,
  523. After: opts.NewCommitID,
  524. CompareURL: setting.AppURL + commits.CompareURL,
  525. Commits: apiCommits,
  526. Repo: convert.ToRepo(repo, models.AccessModeOwner),
  527. Pusher: apiPusher,
  528. Sender: apiPusher,
  529. }); err != nil {
  530. log.Error("PrepareWebhooks: %v", err)
  531. }
  532. }
  533. func (*webhookNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *models.User) {
  534. // Reload pull request information.
  535. if err := pr.LoadAttributes(); err != nil {
  536. log.Error("LoadAttributes: %v", err)
  537. return
  538. }
  539. if err := pr.LoadIssue(); err != nil {
  540. log.Error("LoadAttributes: %v", err)
  541. return
  542. }
  543. if err := pr.Issue.LoadRepo(); err != nil {
  544. log.Error("pr.Issue.LoadRepo: %v", err)
  545. return
  546. }
  547. mode, err := models.AccessLevel(doer, pr.Issue.Repo)
  548. if err != nil {
  549. log.Error("models.AccessLevel: %v", err)
  550. return
  551. }
  552. // Merge pull request calls issue.changeStatus so we need to handle separately.
  553. apiPullRequest := &api.PullRequestPayload{
  554. Index: pr.Issue.Index,
  555. PullRequest: convert.ToAPIPullRequest(pr),
  556. Repository: convert.ToRepo(pr.Issue.Repo, mode),
  557. Sender: convert.ToUser(doer, false, false),
  558. Action: api.HookIssueClosed,
  559. }
  560. err = webhook_services.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequest, apiPullRequest)
  561. if err != nil {
  562. log.Error("PrepareWebhooks: %v", err)
  563. }
  564. }
  565. func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullRequest, oldBranch string) {
  566. issue := pr.Issue
  567. if !issue.IsPull {
  568. return
  569. }
  570. var err error
  571. if err = issue.LoadPullRequest(); err != nil {
  572. log.Error("LoadPullRequest failed: %v", err)
  573. return
  574. }
  575. issue.PullRequest.Issue = issue
  576. mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
  577. err = webhook_services.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
  578. Action: api.HookIssueEdited,
  579. Index: issue.Index,
  580. Changes: &api.ChangesPayload{
  581. Ref: &api.ChangesFromPayload{
  582. From: oldBranch,
  583. },
  584. },
  585. PullRequest: convert.ToAPIPullRequest(issue.PullRequest),
  586. Repository: convert.ToRepo(issue.Repo, mode),
  587. Sender: convert.ToUser(doer, false, false),
  588. })
  589. if err != nil {
  590. log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
  591. }
  592. }
  593. func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
  594. var reviewHookType models.HookEventType
  595. switch review.Type {
  596. case models.ReviewTypeApprove:
  597. reviewHookType = models.HookEventPullRequestReviewApproved
  598. case models.ReviewTypeComment:
  599. reviewHookType = models.HookEventPullRequestComment
  600. case models.ReviewTypeReject:
  601. reviewHookType = models.HookEventPullRequestReviewRejected
  602. default:
  603. // unsupported review webhook type here
  604. log.Error("Unsupported review webhook type")
  605. return
  606. }
  607. if err := pr.LoadIssue(); err != nil {
  608. log.Error("pr.LoadIssue: %v", err)
  609. return
  610. }
  611. mode, err := models.AccessLevel(review.Issue.Poster, review.Issue.Repo)
  612. if err != nil {
  613. log.Error("models.AccessLevel: %v", err)
  614. return
  615. }
  616. if err := webhook_services.PrepareWebhooks(review.Issue.Repo, reviewHookType, &api.PullRequestPayload{
  617. Action: api.HookIssueReviewed,
  618. Index: review.Issue.Index,
  619. PullRequest: convert.ToAPIPullRequest(pr),
  620. Repository: convert.ToRepo(review.Issue.Repo, mode),
  621. Sender: convert.ToUser(review.Reviewer, false, false),
  622. Review: &api.ReviewPayload{
  623. Type: string(reviewHookType),
  624. Content: review.Content,
  625. },
  626. }); err != nil {
  627. log.Error("PrepareWebhooks: %v", err)
  628. }
  629. }
  630. func (m *webhookNotifier) NotifyCreateRef(pusher *models.User, repo *models.Repository, refType, refFullName string) {
  631. apiPusher := convert.ToUser(pusher, false, false)
  632. apiRepo := convert.ToRepo(repo, models.AccessModeNone)
  633. refName := git.RefEndName(refFullName)
  634. gitRepo, err := git.OpenRepository(repo.RepoPath())
  635. if err != nil {
  636. log.Error("OpenRepository[%s]: %v", repo.RepoPath(), err)
  637. return
  638. }
  639. shaSum, err := gitRepo.GetRefCommitID(refFullName)
  640. if err != nil {
  641. gitRepo.Close()
  642. log.Error("GetRefCommitID[%s]: %v", refFullName, err)
  643. return
  644. }
  645. gitRepo.Close()
  646. if err = webhook_services.PrepareWebhooks(repo, models.HookEventCreate, &api.CreatePayload{
  647. Ref: refName,
  648. Sha: shaSum,
  649. RefType: refType,
  650. Repo: apiRepo,
  651. Sender: apiPusher,
  652. }); err != nil {
  653. log.Error("PrepareWebhooks: %v", err)
  654. }
  655. }
  656. func (m *webhookNotifier) NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest) {
  657. if err := pr.LoadIssue(); err != nil {
  658. log.Error("pr.LoadIssue: %v", err)
  659. return
  660. }
  661. if err := pr.Issue.LoadAttributes(); err != nil {
  662. log.Error("LoadAttributes: %v", err)
  663. return
  664. }
  665. if err := webhook_services.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequestSync, &api.PullRequestPayload{
  666. Action: api.HookIssueSynchronized,
  667. Index: pr.Issue.Index,
  668. PullRequest: convert.ToAPIPullRequest(pr),
  669. Repository: convert.ToRepo(pr.Issue.Repo, models.AccessModeNone),
  670. Sender: convert.ToUser(doer, false, false),
  671. }); err != nil {
  672. log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
  673. }
  674. }
  675. func (m *webhookNotifier) NotifyDeleteRef(pusher *models.User, repo *models.Repository, refType, refFullName string) {
  676. apiPusher := convert.ToUser(pusher, false, false)
  677. apiRepo := convert.ToRepo(repo, models.AccessModeNone)
  678. refName := git.RefEndName(refFullName)
  679. if err := webhook_services.PrepareWebhooks(repo, models.HookEventDelete, &api.DeletePayload{
  680. Ref: refName,
  681. RefType: refType,
  682. PusherType: api.PusherTypeUser,
  683. Repo: apiRepo,
  684. Sender: apiPusher,
  685. }); err != nil {
  686. log.Error("PrepareWebhooks.(delete %s): %v", refType, err)
  687. }
  688. }
  689. func sendReleaseHook(doer *models.User, rel *models.Release, action api.HookReleaseAction) {
  690. if err := rel.LoadAttributes(); err != nil {
  691. log.Error("LoadAttributes: %v", err)
  692. return
  693. }
  694. mode, _ := models.AccessLevel(rel.Publisher, rel.Repo)
  695. if err := webhook_services.PrepareWebhooks(rel.Repo, models.HookEventRelease, &api.ReleasePayload{
  696. Action: action,
  697. Release: convert.ToRelease(rel),
  698. Repository: convert.ToRepo(rel.Repo, mode),
  699. Sender: convert.ToUser(rel.Publisher, false, false),
  700. }); err != nil {
  701. log.Error("PrepareWebhooks: %v", err)
  702. }
  703. }
  704. func (m *webhookNotifier) NotifyNewRelease(rel *models.Release) {
  705. sendReleaseHook(rel.Publisher, rel, api.HookReleasePublished)
  706. }
  707. func (m *webhookNotifier) NotifyUpdateRelease(doer *models.User, rel *models.Release) {
  708. sendReleaseHook(doer, rel, api.HookReleaseUpdated)
  709. }
  710. func (m *webhookNotifier) NotifyDeleteRelease(doer *models.User, rel *models.Release) {
  711. sendReleaseHook(doer, rel, api.HookReleaseDeleted)
  712. }
  713. func (m *webhookNotifier) NotifySyncPushCommits(pusher *models.User, repo *models.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
  714. apiPusher := convert.ToUser(pusher, false, false)
  715. apiCommits, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL())
  716. if err != nil {
  717. log.Error("commits.ToAPIPayloadCommits failed: %v", err)
  718. return
  719. }
  720. if err := webhook_services.PrepareWebhooks(repo, models.HookEventPush, &api.PushPayload{
  721. Ref: opts.RefFullName,
  722. Before: opts.OldCommitID,
  723. After: opts.NewCommitID,
  724. CompareURL: setting.AppURL + commits.CompareURL,
  725. Commits: apiCommits,
  726. Repo: convert.ToRepo(repo, models.AccessModeOwner),
  727. Pusher: apiPusher,
  728. Sender: apiPusher,
  729. }); err != nil {
  730. log.Error("PrepareWebhooks: %v", err)
  731. }
  732. }
  733. func (m *webhookNotifier) NotifySyncCreateRef(pusher *models.User, repo *models.Repository, refType, refFullName string) {
  734. m.NotifyCreateRef(pusher, repo, refType, refFullName)
  735. }
  736. func (m *webhookNotifier) NotifySyncDeleteRef(pusher *models.User, repo *models.Repository, refType, refFullName string) {
  737. m.NotifyDeleteRef(pusher, repo, refType, refFullName)
  738. }