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 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  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 = &DeletePayload{}
  153. _ Payloader = &ForkPayload{}
  154. _ Payloader = &PushPayload{}
  155. _ Payloader = &IssuePayload{}
  156. _ Payloader = &IssueCommentPayload{}
  157. _ Payloader = &PullRequestPayload{}
  158. _ Payloader = &RepositoryPayload{}
  159. _ Payloader = &ReleasePayload{}
  160. )
  161. // _________ __
  162. // \_ ___ \_______ ____ _____ _/ |_ ____
  163. // / \ \/\_ __ \_/ __ \\__ \\ __\/ __ \
  164. // \ \____| | \/\ ___/ / __ \| | \ ___/
  165. // \______ /|__| \___ >____ /__| \___ >
  166. // \/ \/ \/ \/
  167. // CreatePayload FIXME
  168. type CreatePayload struct {
  169. Secret string `json:"secret"`
  170. Sha string `json:"sha"`
  171. Ref string `json:"ref"`
  172. RefType string `json:"ref_type"`
  173. Repo *Repository `json:"repository"`
  174. Sender *User `json:"sender"`
  175. }
  176. // SetSecret modifies the secret of the CreatePayload
  177. func (p *CreatePayload) SetSecret(secret string) {
  178. p.Secret = secret
  179. }
  180. // JSONPayload return payload information
  181. func (p *CreatePayload) JSONPayload() ([]byte, error) {
  182. return json.MarshalIndent(p, "", " ")
  183. }
  184. // ParseCreateHook parses create event hook content.
  185. func ParseCreateHook(raw []byte) (*CreatePayload, error) {
  186. hook := new(CreatePayload)
  187. if err := json.Unmarshal(raw, hook); err != nil {
  188. return nil, err
  189. }
  190. // it is possible the JSON was parsed, however,
  191. // was not from Gogs (maybe was from Bitbucket)
  192. // So we'll check to be sure certain key fields
  193. // were populated
  194. switch {
  195. case hook.Repo == nil:
  196. return nil, ErrInvalidReceiveHook
  197. case len(hook.Ref) == 0:
  198. return nil, ErrInvalidReceiveHook
  199. }
  200. return hook, nil
  201. }
  202. // ________ .__ __
  203. // \______ \ ____ | | _____/ |_ ____
  204. // | | \_/ __ \| | _/ __ \ __\/ __ \
  205. // | ` \ ___/| |_\ ___/| | \ ___/
  206. // /_______ /\___ >____/\___ >__| \___ >
  207. // \/ \/ \/ \/
  208. // PusherType define the type to push
  209. type PusherType string
  210. // describe all the PusherTypes
  211. const (
  212. PusherTypeUser PusherType = "user"
  213. )
  214. // DeletePayload represents delete payload
  215. type DeletePayload struct {
  216. Secret string `json:"secret"`
  217. Ref string `json:"ref"`
  218. RefType string `json:"ref_type"`
  219. PusherType PusherType `json:"pusher_type"`
  220. Repo *Repository `json:"repository"`
  221. Sender *User `json:"sender"`
  222. }
  223. // SetSecret modifies the secret of the DeletePayload
  224. func (p *DeletePayload) SetSecret(secret string) {
  225. p.Secret = secret
  226. }
  227. // JSONPayload implements Payload
  228. func (p *DeletePayload) JSONPayload() ([]byte, error) {
  229. return json.MarshalIndent(p, "", " ")
  230. }
  231. // ___________ __
  232. // \_ _____/__________| | __
  233. // | __)/ _ \_ __ \ |/ /
  234. // | \( <_> ) | \/ <
  235. // \___ / \____/|__| |__|_ \
  236. // \/ \/
  237. // ForkPayload represents fork payload
  238. type ForkPayload struct {
  239. Secret string `json:"secret"`
  240. Forkee *Repository `json:"forkee"`
  241. Repo *Repository `json:"repository"`
  242. Sender *User `json:"sender"`
  243. }
  244. // SetSecret modifies the secret of the ForkPayload
  245. func (p *ForkPayload) SetSecret(secret string) {
  246. p.Secret = secret
  247. }
  248. // JSONPayload implements Payload
  249. func (p *ForkPayload) JSONPayload() ([]byte, error) {
  250. return json.MarshalIndent(p, "", " ")
  251. }
  252. // HookIssueCommentAction defines hook issue comment action
  253. type HookIssueCommentAction string
  254. // all issue comment actions
  255. const (
  256. HookIssueCommentCreated HookIssueCommentAction = "created"
  257. HookIssueCommentEdited HookIssueCommentAction = "edited"
  258. HookIssueCommentDeleted HookIssueCommentAction = "deleted"
  259. )
  260. // IssueCommentPayload represents a payload information of issue comment event.
  261. type IssueCommentPayload struct {
  262. Secret string `json:"secret"`
  263. Action HookIssueCommentAction `json:"action"`
  264. Issue *Issue `json:"issue"`
  265. Comment *Comment `json:"comment"`
  266. Changes *ChangesPayload `json:"changes,omitempty"`
  267. Repository *Repository `json:"repository"`
  268. Sender *User `json:"sender"`
  269. }
  270. // SetSecret modifies the secret of the IssueCommentPayload
  271. func (p *IssueCommentPayload) SetSecret(secret string) {
  272. p.Secret = secret
  273. }
  274. // JSONPayload implements Payload
  275. func (p *IssueCommentPayload) JSONPayload() ([]byte, error) {
  276. return json.MarshalIndent(p, "", " ")
  277. }
  278. // __________ .__
  279. // \______ \ ____ | | ____ _____ ______ ____
  280. // | _// __ \| | _/ __ \\__ \ / ___// __ \
  281. // | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/
  282. // |____|_ /\___ >____/\___ >____ /____ >\___ >
  283. // \/ \/ \/ \/ \/ \/
  284. // HookReleaseAction defines hook release action type
  285. type HookReleaseAction string
  286. // all release actions
  287. const (
  288. HookReleasePublished HookReleaseAction = "published"
  289. HookReleaseUpdated HookReleaseAction = "updated"
  290. HookReleaseDeleted HookReleaseAction = "deleted"
  291. )
  292. // ReleasePayload represents a payload information of release event.
  293. type ReleasePayload struct {
  294. Secret string `json:"secret"`
  295. Action HookReleaseAction `json:"action"`
  296. Release *Release `json:"release"`
  297. Repository *Repository `json:"repository"`
  298. Sender *User `json:"sender"`
  299. }
  300. // SetSecret modifies the secret of the ReleasePayload
  301. func (p *ReleasePayload) SetSecret(secret string) {
  302. p.Secret = secret
  303. }
  304. // JSONPayload implements Payload
  305. func (p *ReleasePayload) JSONPayload() ([]byte, error) {
  306. return json.MarshalIndent(p, "", " ")
  307. }
  308. // __________ .__
  309. // \______ \__ __ _____| |__
  310. // | ___/ | \/ ___/ | \
  311. // | | | | /\___ \| Y \
  312. // |____| |____//____ >___| /
  313. // \/ \/
  314. // PushPayload represents a payload information of push event.
  315. type PushPayload struct {
  316. Secret string `json:"secret"`
  317. Ref string `json:"ref"`
  318. Before string `json:"before"`
  319. After string `json:"after"`
  320. CompareURL string `json:"compare_url"`
  321. Commits []*PayloadCommit `json:"commits"`
  322. Repo *Repository `json:"repository"`
  323. Pusher *User `json:"pusher"`
  324. Sender *User `json:"sender"`
  325. }
  326. // SetSecret modifies the secret of the PushPayload
  327. func (p *PushPayload) SetSecret(secret string) {
  328. p.Secret = secret
  329. }
  330. // JSONPayload FIXME
  331. func (p *PushPayload) JSONPayload() ([]byte, error) {
  332. return json.MarshalIndent(p, "", " ")
  333. }
  334. // ParsePushHook parses push event hook content.
  335. func ParsePushHook(raw []byte) (*PushPayload, error) {
  336. hook := new(PushPayload)
  337. if err := json.Unmarshal(raw, hook); err != nil {
  338. return nil, err
  339. }
  340. switch {
  341. case hook.Repo == nil:
  342. return nil, ErrInvalidReceiveHook
  343. case len(hook.Ref) == 0:
  344. return nil, ErrInvalidReceiveHook
  345. }
  346. return hook, nil
  347. }
  348. // Branch returns branch name from a payload
  349. func (p *PushPayload) Branch() string {
  350. return strings.Replace(p.Ref, "refs/heads/", "", -1)
  351. }
  352. // .___
  353. // | | ______ ________ __ ____
  354. // | |/ ___// ___/ | \_/ __ \
  355. // | |\___ \ \___ \| | /\ ___/
  356. // |___/____ >____ >____/ \___ >
  357. // \/ \/ \/
  358. // HookIssueAction FIXME
  359. type HookIssueAction string
  360. const (
  361. // HookIssueOpened opened
  362. HookIssueOpened HookIssueAction = "opened"
  363. // HookIssueClosed closed
  364. HookIssueClosed HookIssueAction = "closed"
  365. // HookIssueReOpened reopened
  366. HookIssueReOpened HookIssueAction = "reopened"
  367. // HookIssueEdited edited
  368. HookIssueEdited HookIssueAction = "edited"
  369. // HookIssueAssigned assigned
  370. HookIssueAssigned HookIssueAction = "assigned"
  371. // HookIssueUnassigned unassigned
  372. HookIssueUnassigned HookIssueAction = "unassigned"
  373. // HookIssueLabelUpdated label_updated
  374. HookIssueLabelUpdated HookIssueAction = "label_updated"
  375. // HookIssueLabelCleared label_cleared
  376. HookIssueLabelCleared HookIssueAction = "label_cleared"
  377. // HookIssueSynchronized synchronized
  378. HookIssueSynchronized HookIssueAction = "synchronized"
  379. // HookIssueMilestoned is an issue action for when a milestone is set on an issue.
  380. HookIssueMilestoned HookIssueAction = "milestoned"
  381. // HookIssueDemilestoned is an issue action for when a milestone is cleared on an issue.
  382. HookIssueDemilestoned HookIssueAction = "demilestoned"
  383. )
  384. // IssuePayload represents the payload information that is sent along with an issue event.
  385. type IssuePayload struct {
  386. Secret string `json:"secret"`
  387. Action HookIssueAction `json:"action"`
  388. Index int64 `json:"number"`
  389. Changes *ChangesPayload `json:"changes,omitempty"`
  390. Issue *Issue `json:"issue"`
  391. Repository *Repository `json:"repository"`
  392. Sender *User `json:"sender"`
  393. }
  394. // SetSecret modifies the secret of the IssuePayload.
  395. func (p *IssuePayload) SetSecret(secret string) {
  396. p.Secret = secret
  397. }
  398. // JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces.
  399. func (p *IssuePayload) JSONPayload() ([]byte, error) {
  400. return json.MarshalIndent(p, "", " ")
  401. }
  402. // ChangesFromPayload FIXME
  403. type ChangesFromPayload struct {
  404. From string `json:"from"`
  405. }
  406. // ChangesPayload FIXME
  407. type ChangesPayload struct {
  408. Title *ChangesFromPayload `json:"title,omitempty"`
  409. Body *ChangesFromPayload `json:"body,omitempty"`
  410. }
  411. // __________ .__ .__ __________ __
  412. // \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_
  413. // | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
  414. // | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | |
  415. // |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__|
  416. // \/ \/ |__| \/ \/
  417. // PullRequestPayload represents a payload information of pull request event.
  418. type PullRequestPayload struct {
  419. Secret string `json:"secret"`
  420. Action HookIssueAction `json:"action"`
  421. Index int64 `json:"number"`
  422. Changes *ChangesPayload `json:"changes,omitempty"`
  423. PullRequest *PullRequest `json:"pull_request"`
  424. Repository *Repository `json:"repository"`
  425. Sender *User `json:"sender"`
  426. }
  427. // SetSecret modifies the secret of the PullRequestPayload.
  428. func (p *PullRequestPayload) SetSecret(secret string) {
  429. p.Secret = secret
  430. }
  431. // JSONPayload FIXME
  432. func (p *PullRequestPayload) JSONPayload() ([]byte, error) {
  433. return json.MarshalIndent(p, "", " ")
  434. }
  435. //__________ .__ __
  436. //\______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__.
  437. // | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | |
  438. // | | \ ___/| |_> > <_> )___ \| || | ( <_> ) | \/\___ |
  439. // |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____|
  440. // \/ \/|__| \/ \/
  441. // HookRepoAction an action that happens to a repo
  442. type HookRepoAction string
  443. const (
  444. // HookRepoCreated created
  445. HookRepoCreated HookRepoAction = "created"
  446. // HookRepoDeleted deleted
  447. HookRepoDeleted HookRepoAction = "deleted"
  448. )
  449. // RepositoryPayload payload for repository webhooks
  450. type RepositoryPayload struct {
  451. Secret string `json:"secret"`
  452. Action HookRepoAction `json:"action"`
  453. Repository *Repository `json:"repository"`
  454. Organization *User `json:"organization"`
  455. Sender *User `json:"sender"`
  456. }
  457. // SetSecret modifies the secret of the RepositoryPayload
  458. func (p *RepositoryPayload) SetSecret(secret string) {
  459. p.Secret = secret
  460. }
  461. // JSONPayload JSON representation of the payload
  462. func (p *RepositoryPayload) JSONPayload() ([]byte, error) {
  463. return json.MarshalIndent(p, "", " ")
  464. }