205 lines
6.0 KiB
Go
205 lines
6.0 KiB
Go
package bitbucket
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
)
|
|
|
|
// parse errors
|
|
var (
|
|
ErrEventNotSpecifiedToParse = errors.New("no Event specified to parse")
|
|
ErrInvalidHTTPMethod = errors.New("invalid HTTP Method")
|
|
ErrMissingHookUUIDHeader = errors.New("missing X-Hook-UUID Header")
|
|
ErrMissingEventKeyHeader = errors.New("missing X-Event-Key Header")
|
|
ErrEventNotFound = errors.New("event not defined to be parsed")
|
|
ErrParsingPayload = errors.New("error parsing payload")
|
|
ErrUUIDVerificationFailed = errors.New("UUID verification failed")
|
|
)
|
|
|
|
// Webhook instance contains all methods needed to process events
|
|
type Webhook struct {
|
|
uuid string
|
|
}
|
|
|
|
// Event defines a Bitbucket hook event type
|
|
type Event string
|
|
|
|
// Bitbucket hook types
|
|
const (
|
|
RepoPushEvent Event = "repo:push"
|
|
RepoForkEvent Event = "repo:fork"
|
|
RepoUpdatedEvent Event = "repo:updated"
|
|
RepoCommitCommentCreatedEvent Event = "repo:commit_comment_created"
|
|
RepoCommitStatusCreatedEvent Event = "repo:commit_status_created"
|
|
RepoCommitStatusUpdatedEvent Event = "repo:commit_status_updated"
|
|
IssueCreatedEvent Event = "issue:created"
|
|
IssueUpdatedEvent Event = "issue:updated"
|
|
IssueCommentCreatedEvent Event = "issue:comment_created"
|
|
PullRequestCreatedEvent Event = "pullrequest:created"
|
|
PullRequestUpdatedEvent Event = "pullrequest:updated"
|
|
PullRequestApprovedEvent Event = "pullrequest:approved"
|
|
PullRequestUnapprovedEvent Event = "pullrequest:unapproved"
|
|
PullRequestMergedEvent Event = "pullrequest:fulfilled"
|
|
PullRequestDeclinedEvent Event = "pullrequest:rejected"
|
|
PullRequestCommentCreatedEvent Event = "pullrequest:comment_created"
|
|
PullRequestCommentUpdatedEvent Event = "pullrequest:comment_updated"
|
|
PullRequestCommentDeletedEvent Event = "pullrequest:comment_deleted"
|
|
)
|
|
|
|
// Option is a configuration option for the webhook
|
|
type Option func(*Webhook) error
|
|
|
|
// Options is a namespace var for configuration options
|
|
var Options = WebhookOptions{}
|
|
|
|
// WebhookOptions is a namespace for configuration option methods
|
|
type WebhookOptions struct{}
|
|
|
|
// UUID registers the BitBucket secret
|
|
func (WebhookOptions) UUID(uuid string) Option {
|
|
return func(hook *Webhook) error {
|
|
hook.uuid = uuid
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// New creates and returns a WebHook instance denoted by the Provider type
|
|
func New(options ...Option) (*Webhook, error) {
|
|
hook := new(Webhook)
|
|
for _, opt := range options {
|
|
if err := opt(hook); err != nil {
|
|
return nil, errors.New("Error applying Option")
|
|
}
|
|
}
|
|
return hook, nil
|
|
}
|
|
|
|
// Parse verifies and parses the events specified and returns the payload object or an error
|
|
func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) {
|
|
defer func() {
|
|
_, _ = io.Copy(ioutil.Discard, r.Body)
|
|
_ = r.Body.Close()
|
|
}()
|
|
|
|
if len(events) == 0 {
|
|
return nil, ErrEventNotSpecifiedToParse
|
|
}
|
|
if r.Method != http.MethodPost {
|
|
return nil, ErrInvalidHTTPMethod
|
|
}
|
|
|
|
uuid := r.Header.Get("X-Hook-UUID")
|
|
if hook.uuid != "" && uuid == "" {
|
|
return nil, ErrMissingHookUUIDHeader
|
|
}
|
|
|
|
event := r.Header.Get("X-Event-Key")
|
|
if event == "" {
|
|
return nil, ErrMissingEventKeyHeader
|
|
}
|
|
|
|
if len(hook.uuid) > 0 && uuid != hook.uuid {
|
|
return nil, ErrUUIDVerificationFailed
|
|
}
|
|
|
|
bitbucketEvent := Event(event)
|
|
|
|
var found bool
|
|
for _, evt := range events {
|
|
if evt == bitbucketEvent {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
// event not defined to be parsed
|
|
if !found {
|
|
return nil, ErrEventNotFound
|
|
}
|
|
|
|
payload, err := ioutil.ReadAll(r.Body)
|
|
if err != nil || len(payload) == 0 {
|
|
return nil, ErrParsingPayload
|
|
}
|
|
|
|
switch bitbucketEvent {
|
|
case RepoPushEvent:
|
|
var pl RepoPushPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case RepoForkEvent:
|
|
var pl RepoForkPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case RepoUpdatedEvent:
|
|
var pl RepoUpdatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case RepoCommitCommentCreatedEvent:
|
|
var pl RepoCommitCommentCreatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case RepoCommitStatusCreatedEvent:
|
|
var pl RepoCommitStatusCreatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case RepoCommitStatusUpdatedEvent:
|
|
var pl RepoCommitStatusUpdatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case IssueCreatedEvent:
|
|
var pl IssueCreatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case IssueUpdatedEvent:
|
|
var pl IssueUpdatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case IssueCommentCreatedEvent:
|
|
var pl IssueCommentCreatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case PullRequestCreatedEvent:
|
|
var pl PullRequestCreatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case PullRequestUpdatedEvent:
|
|
var pl PullRequestUpdatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case PullRequestApprovedEvent:
|
|
var pl PullRequestApprovedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case PullRequestUnapprovedEvent:
|
|
var pl PullRequestUnapprovedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case PullRequestMergedEvent:
|
|
var pl PullRequestMergedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case PullRequestDeclinedEvent:
|
|
var pl PullRequestDeclinedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case PullRequestCommentCreatedEvent:
|
|
var pl PullRequestCommentCreatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case PullRequestCommentUpdatedEvent:
|
|
var pl PullRequestCommentUpdatedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
case PullRequestCommentDeletedEvent:
|
|
var pl PullRequestCommentDeletedPayload
|
|
err = json.Unmarshal([]byte(payload), &pl)
|
|
return pl, err
|
|
default:
|
|
return nil, fmt.Errorf("unknown event %s", bitbucketEvent)
|
|
}
|
|
}
|