repo_hook.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // Copyright 2014 The Gogs 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 gogs
  5. import (
  6. "bytes"
  7. "encoding/json"
  8. "errors"
  9. "fmt"
  10. "strings"
  11. "time"
  12. )
  13. var (
  14. ErrInvalidReceiveHook = errors.New("Invalid JSON payload received over webhook")
  15. )
  16. type Hook struct {
  17. ID int64 `json:"id"`
  18. Type string `json:"type"`
  19. URL string `json:"-"`
  20. Config map[string]string `json:"config"`
  21. Events []string `json:"events"`
  22. Active bool `json:"active"`
  23. Updated time.Time `json:"updated_at"`
  24. Created time.Time `json:"created_at"`
  25. }
  26. func (c *Client) ListRepoHooks(user, repo string) ([]*Hook, error) {
  27. hooks := make([]*Hook, 0, 10)
  28. return hooks, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks", user, repo), nil, nil, &hooks)
  29. }
  30. type CreateHookOption struct {
  31. Type string `json:"type" binding:"Required"`
  32. Config map[string]string `json:"config" binding:"Required"`
  33. Events []string `json:"events"`
  34. Active bool `json:"active"`
  35. }
  36. func (c *Client) CreateRepoHook(user, repo string, opt CreateHookOption) (*Hook, error) {
  37. body, err := json.Marshal(&opt)
  38. if err != nil {
  39. return nil, err
  40. }
  41. h := new(Hook)
  42. return h, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/hooks", user, repo), jsonHeader, bytes.NewReader(body), h)
  43. }
  44. type EditHookOption struct {
  45. Config map[string]string `json:"config"`
  46. Events []string `json:"events"`
  47. Active *bool `json:"active"`
  48. }
  49. func (c *Client) EditRepoHook(user, repo string, id int64, opt EditHookOption) error {
  50. body, err := json.Marshal(&opt)
  51. if err != nil {
  52. return err
  53. }
  54. _, err = c.getResponse("PATCH", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), jsonHeader, bytes.NewReader(body))
  55. return err
  56. }
  57. func (c *Client) DeleteRepoHook(user, repo string, id int64) error {
  58. _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil)
  59. return err
  60. }
  61. type Payloader interface {
  62. JSONPayload() ([]byte, error)
  63. }
  64. type PayloadUser struct {
  65. Name string `json:"name"`
  66. Email string `json:"email"`
  67. UserName string `json:"username"`
  68. }
  69. // FIXME: consider use same format as API when commits API are added.
  70. type PayloadCommit struct {
  71. ID string `json:"id"`
  72. Message string `json:"message"`
  73. URL string `json:"url"`
  74. Author *PayloadUser `json:"author"`
  75. Committer *PayloadUser `json:"committer"`
  76. Added []string `json:"added"`
  77. Removed []string `json:"removed"`
  78. Modified []string `json:"modified"`
  79. Timestamp time.Time `json:"timestamp"`
  80. }
  81. var (
  82. _ Payloader = &CreatePayload{}
  83. _ Payloader = &DeletePayload{}
  84. _ Payloader = &ForkPayload{}
  85. _ Payloader = &PushPayload{}
  86. _ Payloader = &IssuesPayload{}
  87. _ Payloader = &IssueCommentPayload{}
  88. _ Payloader = &PullRequestPayload{}
  89. )
  90. // _________ __
  91. // \_ ___ \_______ ____ _____ _/ |_ ____
  92. // / \ \/\_ __ \_/ __ \\__ \\ __\/ __ \
  93. // \ \____| | \/\ ___/ / __ \| | \ ___/
  94. // \______ /|__| \___ >____ /__| \___ >
  95. // \/ \/ \/ \/
  96. type CreatePayload struct {
  97. Ref string `json:"ref"`
  98. RefType string `json:"ref_type"`
  99. Sha string `json:"sha"`
  100. DefaultBranch string `json:"default_branch"`
  101. Repo *Repository `json:"repository"`
  102. Sender *User `json:"sender"`
  103. }
  104. func (p *CreatePayload) JSONPayload() ([]byte, error) {
  105. return json.MarshalIndent(p, "", " ")
  106. }
  107. // ParseCreateHook parses create event hook content.
  108. func ParseCreateHook(raw []byte) (*CreatePayload, error) {
  109. hook := new(CreatePayload)
  110. if err := json.Unmarshal(raw, hook); err != nil {
  111. return nil, err
  112. }
  113. // it is possible the JSON was parsed, however,
  114. // was not from Gogs (maybe was from Bitbucket)
  115. // So we'll check to be sure certain key fields
  116. // were populated
  117. switch {
  118. case hook.Repo == nil:
  119. return nil, ErrInvalidReceiveHook
  120. case len(hook.Ref) == 0:
  121. return nil, ErrInvalidReceiveHook
  122. }
  123. return hook, nil
  124. }
  125. // ________ .__ __
  126. // \______ \ ____ | | _____/ |_ ____
  127. // | | \_/ __ \| | _/ __ \ __\/ __ \
  128. // | ` \ ___/| |_\ ___/| | \ ___/
  129. // /_______ /\___ >____/\___ >__| \___ >
  130. // \/ \/ \/ \/
  131. type PusherType string
  132. const (
  133. PUSHER_TYPE_USER PusherType = "user"
  134. )
  135. type DeletePayload struct {
  136. Ref string `json:"ref"`
  137. RefType string `json:"ref_type"`
  138. PusherType PusherType `json:"pusher_type"`
  139. Repo *Repository `json:"repository"`
  140. Sender *User `json:"sender"`
  141. }
  142. func (p *DeletePayload) JSONPayload() ([]byte, error) {
  143. return json.MarshalIndent(p, "", " ")
  144. }
  145. // ___________ __
  146. // \_ _____/__________| | __
  147. // | __)/ _ \_ __ \ |/ /
  148. // | \( <_> ) | \/ <
  149. // \___ / \____/|__| |__|_ \
  150. // \/ \/
  151. type ForkPayload struct {
  152. Forkee *Repository `json:"forkee"`
  153. Repo *Repository `json:"repository"`
  154. Sender *User `json:"sender"`
  155. }
  156. func (p *ForkPayload) JSONPayload() ([]byte, error) {
  157. return json.MarshalIndent(p, "", " ")
  158. }
  159. // __________ .__
  160. // \______ \__ __ _____| |__
  161. // | ___/ | \/ ___/ | \
  162. // | | | | /\___ \| Y \
  163. // |____| |____//____ >___| /
  164. // \/ \/
  165. // PushPayload represents a payload information of push event.
  166. type PushPayload struct {
  167. Ref string `json:"ref"`
  168. Before string `json:"before"`
  169. After string `json:"after"`
  170. CompareURL string `json:"compare_url"`
  171. Commits []*PayloadCommit `json:"commits"`
  172. Repo *Repository `json:"repository"`
  173. Pusher *User `json:"pusher"`
  174. Sender *User `json:"sender"`
  175. }
  176. func (p *PushPayload) JSONPayload() ([]byte, error) {
  177. return json.MarshalIndent(p, "", " ")
  178. }
  179. // ParsePushHook parses push event hook content.
  180. func ParsePushHook(raw []byte) (*PushPayload, error) {
  181. hook := new(PushPayload)
  182. if err := json.Unmarshal(raw, hook); err != nil {
  183. return nil, err
  184. }
  185. switch {
  186. case hook.Repo == nil:
  187. return nil, ErrInvalidReceiveHook
  188. case len(hook.Ref) == 0:
  189. return nil, ErrInvalidReceiveHook
  190. }
  191. return hook, nil
  192. }
  193. // Branch returns branch name from a payload
  194. func (p *PushPayload) Branch() string {
  195. return strings.Replace(p.Ref, "refs/heads/", "", -1)
  196. }
  197. // .___
  198. // | | ______ ________ __ ____
  199. // | |/ ___// ___/ | \_/ __ \
  200. // | |\___ \ \___ \| | /\ ___/
  201. // |___/____ >____ >____/ \___ >
  202. // \/ \/ \/
  203. type HookIssueAction string
  204. const (
  205. HOOK_ISSUE_OPENED HookIssueAction = "opened"
  206. HOOK_ISSUE_CLOSED HookIssueAction = "closed"
  207. HOOK_ISSUE_REOPENED HookIssueAction = "reopened"
  208. HOOK_ISSUE_EDITED HookIssueAction = "edited"
  209. HOOK_ISSUE_ASSIGNED HookIssueAction = "assigned"
  210. HOOK_ISSUE_UNASSIGNED HookIssueAction = "unassigned"
  211. HOOK_ISSUE_LABEL_UPDATED HookIssueAction = "label_updated"
  212. HOOK_ISSUE_LABEL_CLEARED HookIssueAction = "label_cleared"
  213. HOOK_ISSUE_MILESTONED HookIssueAction = "milestoned"
  214. HOOK_ISSUE_DEMILESTONED HookIssueAction = "demilestoned"
  215. HOOK_ISSUE_SYNCHRONIZED HookIssueAction = "synchronized"
  216. )
  217. type ChangesFromPayload struct {
  218. From string `json:"from"`
  219. }
  220. type ChangesPayload struct {
  221. Title *ChangesFromPayload `json:"title,omitempty"`
  222. Body *ChangesFromPayload `json:"body,omitempty"`
  223. }
  224. // IssuesPayload represents a payload information of issues event.
  225. type IssuesPayload struct {
  226. Action HookIssueAction `json:"action"`
  227. Index int64 `json:"number"`
  228. Issue *Issue `json:"issue"`
  229. Changes *ChangesPayload `json:"changes,omitempty"`
  230. Repository *Repository `json:"repository"`
  231. Sender *User `json:"sender"`
  232. }
  233. func (p *IssuesPayload) JSONPayload() ([]byte, error) {
  234. return json.MarshalIndent(p, "", " ")
  235. }
  236. type HookIssueCommentAction string
  237. const (
  238. HOOK_ISSUE_COMMENT_CREATED HookIssueCommentAction = "created"
  239. HOOK_ISSUE_COMMENT_EDITED HookIssueCommentAction = "edited"
  240. HOOK_ISSUE_COMMENT_DELETED HookIssueCommentAction = "deleted"
  241. )
  242. // IssueCommentPayload represents a payload information of issue comment event.
  243. type IssueCommentPayload struct {
  244. Action HookIssueCommentAction `json:"action"`
  245. Issue *Issue `json:"issue"`
  246. Comment *Comment `json:"comment"`
  247. Changes *ChangesPayload `json:"changes,omitempty"`
  248. Repository *Repository `json:"repository"`
  249. Sender *User `json:"sender"`
  250. }
  251. func (p *IssueCommentPayload) JSONPayload() ([]byte, error) {
  252. return json.MarshalIndent(p, "", " ")
  253. }
  254. // __________ .__ .__ __________ __
  255. // \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_
  256. // | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
  257. // | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | |
  258. // |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__|
  259. // \/ \/ |__| \/ \/
  260. // PullRequestPayload represents a payload information of pull request event.
  261. type PullRequestPayload struct {
  262. Action HookIssueAction `json:"action"`
  263. Index int64 `json:"number"`
  264. PullRequest *PullRequest `json:"pull_request"`
  265. Changes *ChangesPayload `json:"changes,omitempty"`
  266. Repository *Repository `json:"repository"`
  267. Sender *User `json:"sender"`
  268. }
  269. func (p *PullRequestPayload) JSONPayload() ([]byte, error) {
  270. return json.MarshalIndent(p, "", " ")
  271. }
  272. // __________ .__
  273. // \______ \ ____ | | ____ _____ ______ ____
  274. // | _// __ \| | _/ __ \\__ \ / ___// __ \
  275. // | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/
  276. // |____|_ /\___ >____/\___ >____ /____ >\___ >
  277. // \/ \/ \/ \/ \/ \/
  278. type HookReleaseAction string
  279. const (
  280. HOOK_RELEASE_PUBLISHED HookReleaseAction = "published"
  281. )
  282. // ReleasePayload represents a payload information of release event.
  283. type ReleasePayload struct {
  284. Action HookReleaseAction `json:"action"`
  285. Release *Release `json:"release"`
  286. Repository *Repository `json:"repository"`
  287. Sender *User `json:"sender"`
  288. }
  289. func (p *ReleasePayload) JSONPayload() ([]byte, error) {
  290. return json.MarshalIndent(p, "", " ")
  291. }