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.

hook.go 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2017 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package gitea
  6. import (
  7. "bytes"
  8. "encoding/json"
  9. "errors"
  10. "fmt"
  11. "strings"
  12. "time"
  13. )
  14. var (
  15. // ErrInvalidReceiveHook FIXME
  16. ErrInvalidReceiveHook = errors.New("Invalid JSON payload received over webhook")
  17. )
  18. // Hook a hook is a web hook when one repository changed
  19. type Hook struct {
  20. ID int64 `json:"id"`
  21. Type string `json:"type"`
  22. URL string `json:"-"`
  23. Config map[string]string `json:"config"`
  24. Events []string `json:"events"`
  25. Active bool `json:"active"`
  26. // swagger:strfmt date-time
  27. Updated time.Time `json:"updated_at"`
  28. // swagger:strfmt date-time
  29. Created time.Time `json:"created_at"`
  30. }
  31. // HookList represents a list of API hook.
  32. type HookList []*Hook
  33. // ListOrgHooks list all the hooks of one organization
  34. func (c *Client) ListOrgHooks(org string) (HookList, error) {
  35. hooks := make([]*Hook, 0, 10)
  36. return hooks, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/hooks", org), nil, nil, &hooks)
  37. }
  38. // ListRepoHooks list all the hooks of one repository
  39. func (c *Client) ListRepoHooks(user, repo string) (HookList, error) {
  40. hooks := make([]*Hook, 0, 10)
  41. return hooks, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks", user, repo), nil, nil, &hooks)
  42. }
  43. // GetOrgHook get a hook of an organization
  44. func (c *Client) GetOrgHook(org string, id int64) (*Hook, error) {
  45. h := new(Hook)
  46. return h, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/hooks/%d", org, id), nil, nil, h)
  47. }
  48. // GetRepoHook get a hook of a repository
  49. func (c *Client) GetRepoHook(user, repo string, id int64) (*Hook, error) {
  50. h := new(Hook)
  51. return h, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil, h)
  52. }
  53. // CreateHookOption options when create a hook
  54. type CreateHookOption struct {
  55. // required: true
  56. // enum: gitea,gogs,slack,discord
  57. Type string `json:"type" binding:"Required"`
  58. // required: true
  59. Config map[string]string `json:"config" binding:"Required"`
  60. Events []string `json:"events"`
  61. // default: false
  62. Active bool `json:"active"`
  63. }
  64. // CreateOrgHook create one hook for an organization, with options
  65. func (c *Client) CreateOrgHook(org string, opt CreateHookOption) (*Hook, error) {
  66. body, err := json.Marshal(&opt)
  67. if err != nil {
  68. return nil, err
  69. }
  70. h := new(Hook)
  71. return h, c.getParsedResponse("POST", fmt.Sprintf("/orgs/%s/hooks", org), jsonHeader, bytes.NewReader(body), h)
  72. }
  73. // CreateRepoHook create one hook for a repository, with options
  74. func (c *Client) CreateRepoHook(user, repo string, opt CreateHookOption) (*Hook, error) {
  75. body, err := json.Marshal(&opt)
  76. if err != nil {
  77. return nil, err
  78. }
  79. h := new(Hook)
  80. return h, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/hooks", user, repo), jsonHeader, bytes.NewReader(body), h)
  81. }
  82. // EditHookOption options when modify one hook
  83. type EditHookOption struct {
  84. Config map[string]string `json:"config"`
  85. Events []string `json:"events"`
  86. Active *bool `json:"active"`
  87. }
  88. // EditOrgHook modify one hook of an organization, with hook id and options
  89. func (c *Client) EditOrgHook(org string, id int64, opt EditHookOption) error {
  90. body, err := json.Marshal(&opt)
  91. if err != nil {
  92. return err
  93. }
  94. _, err = c.getResponse("PATCH", fmt.Sprintf("/orgs/%s/hooks/%d", org, id), jsonHeader, bytes.NewReader(body))
  95. return err
  96. }
  97. // EditRepoHook modify one hook of a repository, with hook id and options
  98. func (c *Client) EditRepoHook(user, repo string, id int64, opt EditHookOption) error {
  99. body, err := json.Marshal(&opt)
  100. if err != nil {
  101. return err
  102. }
  103. _, err = c.getResponse("PATCH", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), jsonHeader, bytes.NewReader(body))
  104. return err
  105. }
  106. // DeleteOrgHook delete one hook from an organization, with hook id
  107. func (c *Client) DeleteOrgHook(org string, id int64) error {
  108. _, err := c.getResponse("DELETE", fmt.Sprintf("/org/%s/hooks/%d", org, id), nil, nil)
  109. return err
  110. }
  111. // DeleteRepoHook delete one hook from a repository, with hook id
  112. func (c *Client) DeleteRepoHook(user, repo string, id int64) error {
  113. _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil)
  114. return err
  115. }
  116. // Payloader payload is some part of one hook
  117. type Payloader interface {
  118. SetSecret(string)
  119. JSONPayload() ([]byte, error)
  120. }
  121. // PayloadUser represents the author or committer of a commit
  122. type PayloadUser struct {
  123. // Full name of the commit author
  124. Name string `json:"name"`
  125. // swagger:strfmt email
  126. Email string `json:"email"`
  127. UserName string `json:"username"`
  128. }
  129. // FIXME: consider using same format as API when commits API are added.
  130. // applies to PayloadCommit and PayloadCommitVerification
  131. // PayloadCommit represents a commit
  132. type PayloadCommit struct {
  133. // sha1 hash of the commit
  134. ID string `json:"id"`
  135. Message string `json:"message"`
  136. URL string `json:"url"`
  137. Author *PayloadUser `json:"author"`
  138. Committer *PayloadUser `json:"committer"`
  139. Verification *PayloadCommitVerification `json:"verification"`
  140. // swagger:strfmt date-time
  141. Timestamp time.Time `json:"timestamp"`
  142. }
  143. // PayloadCommitVerification represents the GPG verification of a commit
  144. type PayloadCommitVerification struct {
  145. Verified bool `json:"verified"`
  146. Reason string `json:"reason"`
  147. Signature string `json:"signature"`
  148. Payload string `json:"payload"`
  149. }
  150. var (
  151. _ Payloader = &CreatePayload{}
  152. _ Payloader = &PushPayload{}
  153. _ Payloader = &IssuePayload{}
  154. _ Payloader = &PullRequestPayload{}
  155. )
  156. // _________ __
  157. // \_ ___ \_______ ____ _____ _/ |_ ____
  158. // / \ \/\_ __ \_/ __ \\__ \\ __\/ __ \
  159. // \ \____| | \/\ ___/ / __ \| | \ ___/
  160. // \______ /|__| \___ >____ /__| \___ >
  161. // \/ \/ \/ \/
  162. // CreatePayload FIXME
  163. type CreatePayload struct {
  164. Secret string `json:"secret"`
  165. Sha string `json:"sha"`
  166. Ref string `json:"ref"`
  167. RefType string `json:"ref_type"`
  168. Repo *Repository `json:"repository"`
  169. Sender *User `json:"sender"`
  170. }
  171. // SetSecret FIXME
  172. func (p *CreatePayload) SetSecret(secret string) {
  173. p.Secret = secret
  174. }
  175. // JSONPayload return payload information
  176. func (p *CreatePayload) JSONPayload() ([]byte, error) {
  177. return json.MarshalIndent(p, "", " ")
  178. }
  179. // ParseCreateHook parses create event hook content.
  180. func ParseCreateHook(raw []byte) (*CreatePayload, error) {
  181. hook := new(CreatePayload)
  182. if err := json.Unmarshal(raw, hook); err != nil {
  183. return nil, err
  184. }
  185. // it is possible the JSON was parsed, however,
  186. // was not from Gogs (maybe was from Bitbucket)
  187. // So we'll check to be sure certain key fields
  188. // were populated
  189. switch {
  190. case hook.Repo == nil:
  191. return nil, ErrInvalidReceiveHook
  192. case len(hook.Ref) == 0:
  193. return nil, ErrInvalidReceiveHook
  194. }
  195. return hook, nil
  196. }
  197. // __________ .__
  198. // \______ \__ __ _____| |__
  199. // | ___/ | \/ ___/ | \
  200. // | | | | /\___ \| Y \
  201. // |____| |____//____ >___| /
  202. // \/ \/
  203. // PushPayload represents a payload information of push event.
  204. type PushPayload struct {
  205. Secret string `json:"secret"`
  206. Ref string `json:"ref"`
  207. Before string `json:"before"`
  208. After string `json:"after"`
  209. CompareURL string `json:"compare_url"`
  210. Commits []*PayloadCommit `json:"commits"`
  211. Repo *Repository `json:"repository"`
  212. Pusher *User `json:"pusher"`
  213. Sender *User `json:"sender"`
  214. }
  215. // SetSecret FIXME
  216. func (p *PushPayload) SetSecret(secret string) {
  217. p.Secret = secret
  218. }
  219. // JSONPayload FIXME
  220. func (p *PushPayload) JSONPayload() ([]byte, error) {
  221. return json.MarshalIndent(p, "", " ")
  222. }
  223. // ParsePushHook parses push event hook content.
  224. func ParsePushHook(raw []byte) (*PushPayload, error) {
  225. hook := new(PushPayload)
  226. if err := json.Unmarshal(raw, hook); err != nil {
  227. return nil, err
  228. }
  229. switch {
  230. case hook.Repo == nil:
  231. return nil, ErrInvalidReceiveHook
  232. case len(hook.Ref) == 0:
  233. return nil, ErrInvalidReceiveHook
  234. }
  235. return hook, nil
  236. }
  237. // Branch returns branch name from a payload
  238. func (p *PushPayload) Branch() string {
  239. return strings.Replace(p.Ref, "refs/heads/", "", -1)
  240. }
  241. // .___
  242. // | | ______ ________ __ ____
  243. // | |/ ___// ___/ | \_/ __ \
  244. // | |\___ \ \___ \| | /\ ___/
  245. // |___/____ >____ >____/ \___ >
  246. // \/ \/ \/
  247. // HookIssueAction FIXME
  248. type HookIssueAction string
  249. const (
  250. // HookIssueOpened opened
  251. HookIssueOpened HookIssueAction = "opened"
  252. // HookIssueClosed closed
  253. HookIssueClosed HookIssueAction = "closed"
  254. // HookIssueReOpened reopened
  255. HookIssueReOpened HookIssueAction = "reopened"
  256. // HookIssueEdited edited
  257. HookIssueEdited HookIssueAction = "edited"
  258. // HookIssueAssigned assigned
  259. HookIssueAssigned HookIssueAction = "assigned"
  260. // HookIssueUnassigned unassigned
  261. HookIssueUnassigned HookIssueAction = "unassigned"
  262. // HookIssueLabelUpdated label_updated
  263. HookIssueLabelUpdated HookIssueAction = "label_updated"
  264. // HookIssueLabelCleared label_cleared
  265. HookIssueLabelCleared HookIssueAction = "label_cleared"
  266. // HookIssueSynchronized synchronized
  267. HookIssueSynchronized HookIssueAction = "synchronized"
  268. // HookIssueMilestoned is an issue action for when a milestone is set on an issue.
  269. HookIssueMilestoned HookIssueAction = "milestoned"
  270. // HookIssueDemilestoned is an issue action for when a milestone is cleared on an issue.
  271. HookIssueDemilestoned HookIssueAction = "demilestoned"
  272. )
  273. // IssuePayload represents the payload information that is sent along with an issue event.
  274. type IssuePayload struct {
  275. Secret string `json:"secret"`
  276. Action HookIssueAction `json:"action"`
  277. Index int64 `json:"number"`
  278. Changes *ChangesPayload `json:"changes,omitempty"`
  279. Issue *Issue `json:"issue"`
  280. Repository *Repository `json:"repository"`
  281. Sender *User `json:"sender"`
  282. }
  283. // SetSecret modifies the secret of the IssuePayload.
  284. func (p *IssuePayload) SetSecret(secret string) {
  285. p.Secret = secret
  286. }
  287. // JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces.
  288. func (p *IssuePayload) JSONPayload() ([]byte, error) {
  289. return json.MarshalIndent(p, "", " ")
  290. }
  291. // ChangesFromPayload FIXME
  292. type ChangesFromPayload struct {
  293. From string `json:"from"`
  294. }
  295. // ChangesPayload FIXME
  296. type ChangesPayload struct {
  297. Title *ChangesFromPayload `json:"title,omitempty"`
  298. Body *ChangesFromPayload `json:"body,omitempty"`
  299. }
  300. // __________ .__ .__ __________ __
  301. // \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_
  302. // | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
  303. // | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | |
  304. // |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__|
  305. // \/ \/ |__| \/ \/
  306. // PullRequestPayload represents a payload information of pull request event.
  307. type PullRequestPayload struct {
  308. Secret string `json:"secret"`
  309. Action HookIssueAction `json:"action"`
  310. Index int64 `json:"number"`
  311. Changes *ChangesPayload `json:"changes,omitempty"`
  312. PullRequest *PullRequest `json:"pull_request"`
  313. Repository *Repository `json:"repository"`
  314. Sender *User `json:"sender"`
  315. }
  316. // SetSecret modifies the secret of the PullRequestPayload.
  317. func (p *PullRequestPayload) SetSecret(secret string) {
  318. p.Secret = secret
  319. }
  320. // JSONPayload FIXME
  321. func (p *PullRequestPayload) JSONPayload() ([]byte, error) {
  322. return json.MarshalIndent(p, "", " ")
  323. }
  324. //__________ .__ __
  325. //\______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__.
  326. // | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | |
  327. // | | \ ___/| |_> > <_> )___ \| || | ( <_> ) | \/\___ |
  328. // |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____|
  329. // \/ \/|__| \/ \/
  330. // HookRepoAction an action that happens to a repo
  331. type HookRepoAction string
  332. const (
  333. // HookRepoCreated created
  334. HookRepoCreated HookRepoAction = "created"
  335. // HookRepoDeleted deleted
  336. HookRepoDeleted HookRepoAction = "deleted"
  337. )
  338. // RepositoryPayload payload for repository webhooks
  339. type RepositoryPayload struct {
  340. Secret string `json:"secret"`
  341. Action HookRepoAction `json:"action"`
  342. Repository *Repository `json:"repository"`
  343. Organization *User `json:"organization"`
  344. Sender *User `json:"sender"`
  345. }
  346. // SetSecret set the payload's secret
  347. func (p *RepositoryPayload) SetSecret(secret string) {
  348. p.Secret = secret
  349. }
  350. // JSONPayload JSON representation of the payload
  351. func (p *RepositoryPayload) JSONPayload() ([]byte, error) {
  352. return json.MarshalIndent(p, "", " ")
  353. }