2016-11-07 19:23:13 +05:30
// Copyright 2014 The Gogs Authors. All rights reserved.
2017-02-23 05:23:33 +05:30
// Copyright 2017 The Gitea Authors. All rights reserved.
2016-11-07 19:23:13 +05:30
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package gitea
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
)
var (
2016-11-29 13:39:17 +05:30
// ErrInvalidReceiveHook FIXME
2016-11-07 19:23:13 +05:30
ErrInvalidReceiveHook = errors . New ( "Invalid JSON payload received over webhook" )
)
2016-11-29 13:39:17 +05:30
// Hook a hook is a web hook when one repository changed
2016-11-07 19:23:13 +05:30
type Hook struct {
ID int64 ` json:"id" `
Type string ` json:"type" `
URL string ` json:"-" `
Config map [ string ] string ` json:"config" `
Events [ ] string ` json:"events" `
Active bool ` json:"active" `
Updated time . Time ` json:"updated_at" `
Created time . Time ` json:"created_at" `
}
2016-12-25 01:17:32 +05:30
// ListOrgHooks list all the hooks of one organization
func ( c * Client ) ListOrgHooks ( org string ) ( [ ] * Hook , error ) {
hooks := make ( [ ] * Hook , 0 , 10 )
return hooks , c . getParsedResponse ( "GET" , fmt . Sprintf ( "/orgs/%s/hooks" , org ) , nil , nil , & hooks )
}
2016-11-29 13:39:17 +05:30
// ListRepoHooks list all the hooks of one repository
2016-11-07 19:23:13 +05:30
func ( c * Client ) ListRepoHooks ( user , repo string ) ( [ ] * Hook , error ) {
hooks := make ( [ ] * Hook , 0 , 10 )
return hooks , c . getParsedResponse ( "GET" , fmt . Sprintf ( "/repos/%s/%s/hooks" , user , repo ) , nil , nil , & hooks )
}
2016-12-25 01:17:32 +05:30
// GetOrgHook get a hook of an organization
func ( c * Client ) GetOrgHook ( org string , id int64 ) ( * Hook , error ) {
h := new ( Hook )
return h , c . getParsedResponse ( "GET" , fmt . Sprintf ( "/orgs/%s/hooks/%d" , org , id ) , nil , nil , h )
}
// GetRepoHook get a hook of a repository
func ( c * Client ) GetRepoHook ( user , repo string , id int64 ) ( * Hook , error ) {
h := new ( Hook )
return h , c . getParsedResponse ( "GET" , fmt . Sprintf ( "/repos/%s/%s/hooks/%d" , user , repo , id ) , nil , nil , h )
}
2016-11-29 13:39:17 +05:30
// CreateHookOption options when create a hook
2016-11-07 19:23:13 +05:30
type CreateHookOption struct {
Type string ` json:"type" binding:"Required" `
Config map [ string ] string ` json:"config" binding:"Required" `
Events [ ] string ` json:"events" `
Active bool ` json:"active" `
}
2016-12-25 01:17:32 +05:30
// CreateOrgHook create one hook for an organization, with options
func ( c * Client ) CreateOrgHook ( org string , opt CreateHookOption ) ( * Hook , error ) {
body , err := json . Marshal ( & opt )
if err != nil {
return nil , err
}
h := new ( Hook )
return h , c . getParsedResponse ( "POST" , fmt . Sprintf ( "/orgs/%s/hooks" , org ) , jsonHeader , bytes . NewReader ( body ) , h )
}
// CreateRepoHook create one hook for a repository, with options
2016-11-07 19:23:13 +05:30
func ( c * Client ) CreateRepoHook ( user , repo string , opt CreateHookOption ) ( * Hook , error ) {
body , err := json . Marshal ( & opt )
if err != nil {
return nil , err
}
h := new ( Hook )
return h , c . getParsedResponse ( "POST" , fmt . Sprintf ( "/repos/%s/%s/hooks" , user , repo ) , jsonHeader , bytes . NewReader ( body ) , h )
}
2016-11-29 13:39:17 +05:30
// EditHookOption options when modify one hook
2016-11-07 19:23:13 +05:30
type EditHookOption struct {
Config map [ string ] string ` json:"config" `
Events [ ] string ` json:"events" `
Active * bool ` json:"active" `
}
2016-12-25 01:17:32 +05:30
// EditOrgHook modify one hook of an organization, with hook id and options
func ( c * Client ) EditOrgHook ( org string , id int64 , opt EditHookOption ) error {
body , err := json . Marshal ( & opt )
if err != nil {
return err
}
_ , err = c . getResponse ( "PATCH" , fmt . Sprintf ( "/orgs/%s/hooks/%d" , org , id ) , jsonHeader , bytes . NewReader ( body ) )
return err
}
// EditRepoHook modify one hook of a repository, with hook id and options
2016-11-07 19:23:13 +05:30
func ( c * Client ) EditRepoHook ( user , repo string , id int64 , opt EditHookOption ) error {
body , err := json . Marshal ( & opt )
if err != nil {
return err
}
_ , err = c . getResponse ( "PATCH" , fmt . Sprintf ( "/repos/%s/%s/hooks/%d" , user , repo , id ) , jsonHeader , bytes . NewReader ( body ) )
return err
}
2016-12-25 01:17:32 +05:30
// DeleteOrgHook delete one hook from an organization, with hook id
func ( c * Client ) DeleteOrgHook ( org string , id int64 ) error {
_ , err := c . getResponse ( "DELETE" , fmt . Sprintf ( "/org/%s/hooks/%d" , org , id ) , nil , nil )
return err
}
// DeleteRepoHook delete one hook from a repository, with hook id
2016-11-07 19:23:13 +05:30
func ( c * Client ) DeleteRepoHook ( user , repo string , id int64 ) error {
_ , err := c . getResponse ( "DELETE" , fmt . Sprintf ( "/repos/%s/%s/hooks/%d" , user , repo , id ) , nil , nil )
return err
}
2016-11-29 13:39:17 +05:30
// Payloader payload is some part of one hook
2016-11-07 19:23:13 +05:30
type Payloader interface {
SetSecret ( string )
JSONPayload ( ) ( [ ] byte , error )
}
2016-11-29 13:39:17 +05:30
// PayloadUser FIXME
2016-11-07 19:23:13 +05:30
type PayloadUser struct {
Name string ` json:"name" `
Email string ` json:"email" `
UserName string ` json:"username" `
}
2016-11-29 13:39:17 +05:30
// PayloadCommit FIXME: consider use same format as API when commits API are added.
2016-11-07 19:23:13 +05:30
type PayloadCommit struct {
2017-03-22 16:13:54 +05:30
ID string ` json:"id" `
Message string ` json:"message" `
URL string ` json:"url" `
Author * PayloadUser ` json:"author" `
Committer * PayloadUser ` json:"committer" `
Verification * PayloadCommitVerification ` json:"verification" `
Timestamp time . Time ` json:"timestamp" `
}
// PayloadCommitVerification represent the GPG verification part of a commit. FIXME: like PayloadCommit consider use same format as API when commits API are added.
type PayloadCommitVerification struct {
Verified bool ` json:"verified" `
Reason string ` json:"reason" `
Signature string ` json:"signature" `
Payload string ` json:"payload" `
2016-11-07 19:23:13 +05:30
}
var (
_ Payloader = & CreatePayload { }
_ Payloader = & PushPayload { }
2017-02-23 05:23:33 +05:30
_ Payloader = & IssuePayload { }
2016-11-07 19:23:13 +05:30
_ Payloader = & PullRequestPayload { }
)
// _________ __
// \_ ___ \_______ ____ _____ _/ |_ ____
// / \ \/\_ __ \_/ __ \\__ \\ __\/ __ \
// \ \____| | \/\ ___/ / __ \| | \ ___/
// \______ /|__| \___ >____ /__| \___ >
// \/ \/ \/ \/
2016-11-29 13:39:17 +05:30
// CreatePayload FIXME
2016-11-07 19:23:13 +05:30
type CreatePayload struct {
Secret string ` json:"secret" `
2016-11-29 13:39:17 +05:30
Sha string ` json:"sha" `
2016-11-07 19:23:13 +05:30
Ref string ` json:"ref" `
RefType string ` json:"ref_type" `
Repo * Repository ` json:"repository" `
Sender * User ` json:"sender" `
}
2016-11-29 13:39:17 +05:30
// SetSecret FIXME
2016-11-07 19:23:13 +05:30
func ( p * CreatePayload ) SetSecret ( secret string ) {
p . Secret = secret
}
2016-11-29 13:39:17 +05:30
// JSONPayload return payload information
2016-11-07 19:23:13 +05:30
func ( p * CreatePayload ) JSONPayload ( ) ( [ ] byte , error ) {
return json . MarshalIndent ( p , "" , " " )
}
// ParseCreateHook parses create event hook content.
func ParseCreateHook ( raw [ ] byte ) ( * CreatePayload , error ) {
hook := new ( CreatePayload )
if err := json . Unmarshal ( raw , hook ) ; err != nil {
return nil , err
}
// it is possible the JSON was parsed, however,
// was not from Gogs (maybe was from Bitbucket)
// So we'll check to be sure certain key fields
// were populated
switch {
case hook . Repo == nil :
return nil , ErrInvalidReceiveHook
case len ( hook . Ref ) == 0 :
return nil , ErrInvalidReceiveHook
}
return hook , nil
}
// __________ .__
// \______ \__ __ _____| |__
// | ___/ | \/ ___/ | \
// | | | | /\___ \| Y \
// |____| |____//____ >___| /
// \/ \/
// PushPayload represents a payload information of push event.
type PushPayload struct {
Secret string ` json:"secret" `
Ref string ` json:"ref" `
Before string ` json:"before" `
After string ` json:"after" `
CompareURL string ` json:"compare_url" `
Commits [ ] * PayloadCommit ` json:"commits" `
Repo * Repository ` json:"repository" `
Pusher * User ` json:"pusher" `
Sender * User ` json:"sender" `
}
2016-11-29 13:39:17 +05:30
// SetSecret FIXME
2016-11-07 19:23:13 +05:30
func ( p * PushPayload ) SetSecret ( secret string ) {
p . Secret = secret
}
2016-11-29 13:39:17 +05:30
// JSONPayload FIXME
2016-11-07 19:23:13 +05:30
func ( p * PushPayload ) JSONPayload ( ) ( [ ] byte , error ) {
return json . MarshalIndent ( p , "" , " " )
}
// ParsePushHook parses push event hook content.
func ParsePushHook ( raw [ ] byte ) ( * PushPayload , error ) {
hook := new ( PushPayload )
if err := json . Unmarshal ( raw , hook ) ; err != nil {
return nil , err
}
switch {
case hook . Repo == nil :
return nil , ErrInvalidReceiveHook
case len ( hook . Ref ) == 0 :
return nil , ErrInvalidReceiveHook
}
return hook , nil
}
// Branch returns branch name from a payload
func ( p * PushPayload ) Branch ( ) string {
return strings . Replace ( p . Ref , "refs/heads/" , "" , - 1 )
}
// .___
// | | ______ ________ __ ____
// | |/ ___// ___/ | \_/ __ \
// | |\___ \ \___ \| | /\ ___/
// |___/____ >____ >____/ \___ >
// \/ \/ \/
2016-11-29 13:39:17 +05:30
// HookIssueAction FIXME
2016-11-07 19:23:13 +05:30
type HookIssueAction string
const (
2016-11-29 13:39:17 +05:30
// HookIssueOpened opened
HookIssueOpened HookIssueAction = "opened"
// HookIssueClosed closed
HookIssueClosed HookIssueAction = "closed"
// HookIssueReOpened reopened
HookIssueReOpened HookIssueAction = "reopened"
// HookIssueEdited edited
HookIssueEdited HookIssueAction = "edited"
// HookIssueAssigned assigned
HookIssueAssigned HookIssueAction = "assigned"
// HookIssueUnassigned unassigned
HookIssueUnassigned HookIssueAction = "unassigned"
// HookIssueLabelUpdated label_updated
2016-11-07 21:07:32 +05:30
HookIssueLabelUpdated HookIssueAction = "label_updated"
2016-11-29 13:39:17 +05:30
// HookIssueLabelCleared label_cleared
2016-11-07 21:07:32 +05:30
HookIssueLabelCleared HookIssueAction = "label_cleared"
2016-11-29 13:39:17 +05:30
// HookIssueSynchronized synchronized
HookIssueSynchronized HookIssueAction = "synchronized"
2017-02-23 05:23:33 +05:30
// HookIssueMilestoned is an issue action for when a milestone is set on an issue.
HookIssueMilestoned HookIssueAction = "milestoned"
// HookIssueDemilestoned is an issue action for when a milestone is cleared on an issue.
HookIssueDemilestoned HookIssueAction = "demilestoned"
2016-11-07 19:23:13 +05:30
)
2017-02-23 05:23:33 +05:30
// IssuePayload represents the payload information that is sent along with an issue event.
type IssuePayload struct {
Secret string ` json:"secret" `
Action HookIssueAction ` json:"action" `
Index int64 ` json:"number" `
Changes * ChangesPayload ` json:"changes,omitempty" `
Issue * Issue ` json:"issue" `
Repository * Repository ` json:"repository" `
Sender * User ` json:"sender" `
}
// SetSecret modifies the secret of the IssuePayload.
func ( p * IssuePayload ) SetSecret ( secret string ) {
p . Secret = secret
}
// JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces.
func ( p * IssuePayload ) JSONPayload ( ) ( [ ] byte , error ) {
return json . MarshalIndent ( p , "" , " " )
}
2016-11-29 13:39:17 +05:30
// ChangesFromPayload FIXME
2016-11-07 19:23:13 +05:30
type ChangesFromPayload struct {
From string ` json:"from" `
}
2016-11-29 13:39:17 +05:30
// ChangesPayload FIXME
2016-11-07 19:23:13 +05:30
type ChangesPayload struct {
Title * ChangesFromPayload ` json:"title,omitempty" `
Body * ChangesFromPayload ` json:"body,omitempty" `
}
// __________ .__ .__ __________ __
// \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
// | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | |
// |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__|
// \/ \/ |__| \/ \/
// PullRequestPayload represents a payload information of pull request event.
type PullRequestPayload struct {
Secret string ` json:"secret" `
Action HookIssueAction ` json:"action" `
Index int64 ` json:"number" `
Changes * ChangesPayload ` json:"changes,omitempty" `
PullRequest * PullRequest ` json:"pull_request" `
Repository * Repository ` json:"repository" `
Sender * User ` json:"sender" `
}
2017-02-23 05:23:33 +05:30
// SetSecret modifies the secret of the PullRequestPayload.
2016-11-07 19:23:13 +05:30
func ( p * PullRequestPayload ) SetSecret ( secret string ) {
p . Secret = secret
}
2016-11-29 13:39:17 +05:30
// JSONPayload FIXME
2016-11-07 19:23:13 +05:30
func ( p * PullRequestPayload ) JSONPayload ( ) ( [ ] byte , error ) {
return json . MarshalIndent ( p , "" , " " )
}