github.com/go-playground/webhooks/v6@v6.3.0/bitbucket/bitbucket.go (about)

     1  package bitbucket
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"net/http"
    10  )
    11  
    12  // parse errors
    13  var (
    14  	ErrEventNotSpecifiedToParse = errors.New("no Event specified to parse")
    15  	ErrInvalidHTTPMethod        = errors.New("invalid HTTP Method")
    16  	ErrMissingHookUUIDHeader    = errors.New("missing X-Hook-UUID Header")
    17  	ErrMissingEventKeyHeader    = errors.New("missing X-Event-Key Header")
    18  	ErrEventNotFound            = errors.New("event not defined to be parsed")
    19  	ErrParsingPayload           = errors.New("error parsing payload")
    20  	ErrUUIDVerificationFailed   = errors.New("UUID verification failed")
    21  )
    22  
    23  // Webhook instance contains all methods needed to process events
    24  type Webhook struct {
    25  	uuid string
    26  }
    27  
    28  // Event defines a Bitbucket hook event type
    29  type Event string
    30  
    31  // Bitbucket hook types
    32  const (
    33  	RepoPushEvent                  Event = "repo:push"
    34  	RepoForkEvent                  Event = "repo:fork"
    35  	RepoUpdatedEvent               Event = "repo:updated"
    36  	RepoCommitCommentCreatedEvent  Event = "repo:commit_comment_created"
    37  	RepoCommitStatusCreatedEvent   Event = "repo:commit_status_created"
    38  	RepoCommitStatusUpdatedEvent   Event = "repo:commit_status_updated"
    39  	IssueCreatedEvent              Event = "issue:created"
    40  	IssueUpdatedEvent              Event = "issue:updated"
    41  	IssueCommentCreatedEvent       Event = "issue:comment_created"
    42  	PullRequestCreatedEvent        Event = "pullrequest:created"
    43  	PullRequestUpdatedEvent        Event = "pullrequest:updated"
    44  	PullRequestApprovedEvent       Event = "pullrequest:approved"
    45  	PullRequestUnapprovedEvent     Event = "pullrequest:unapproved"
    46  	PullRequestMergedEvent         Event = "pullrequest:fulfilled"
    47  	PullRequestDeclinedEvent       Event = "pullrequest:rejected"
    48  	PullRequestCommentCreatedEvent Event = "pullrequest:comment_created"
    49  	PullRequestCommentUpdatedEvent Event = "pullrequest:comment_updated"
    50  	PullRequestCommentDeletedEvent Event = "pullrequest:comment_deleted"
    51  )
    52  
    53  // Option is a configuration option for the webhook
    54  type Option func(*Webhook) error
    55  
    56  // Options is a namespace var for configuration options
    57  var Options = WebhookOptions{}
    58  
    59  // WebhookOptions is a namespace for configuration option methods
    60  type WebhookOptions struct{}
    61  
    62  // UUID registers the BitBucket secret
    63  func (WebhookOptions) UUID(uuid string) Option {
    64  	return func(hook *Webhook) error {
    65  		hook.uuid = uuid
    66  		return nil
    67  	}
    68  }
    69  
    70  // New creates and returns a WebHook instance denoted by the Provider type
    71  func New(options ...Option) (*Webhook, error) {
    72  	hook := new(Webhook)
    73  	for _, opt := range options {
    74  		if err := opt(hook); err != nil {
    75  			return nil, errors.New("Error applying Option")
    76  		}
    77  	}
    78  	return hook, nil
    79  }
    80  
    81  // Parse verifies and parses the events specified and returns the payload object or an error
    82  func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) {
    83  	defer func() {
    84  		_, _ = io.Copy(ioutil.Discard, r.Body)
    85  		_ = r.Body.Close()
    86  	}()
    87  
    88  	if len(events) == 0 {
    89  		return nil, ErrEventNotSpecifiedToParse
    90  	}
    91  	if r.Method != http.MethodPost {
    92  		return nil, ErrInvalidHTTPMethod
    93  	}
    94  
    95  	uuid := r.Header.Get("X-Hook-UUID")
    96  	if hook.uuid != "" && uuid == "" {
    97  		return nil, ErrMissingHookUUIDHeader
    98  	}
    99  
   100  	event := r.Header.Get("X-Event-Key")
   101  	if event == "" {
   102  		return nil, ErrMissingEventKeyHeader
   103  	}
   104  
   105  	if len(hook.uuid) > 0 && uuid != hook.uuid {
   106  		return nil, ErrUUIDVerificationFailed
   107  	}
   108  
   109  	bitbucketEvent := Event(event)
   110  
   111  	var found bool
   112  	for _, evt := range events {
   113  		if evt == bitbucketEvent {
   114  			found = true
   115  			break
   116  		}
   117  	}
   118  	// event not defined to be parsed
   119  	if !found {
   120  		return nil, ErrEventNotFound
   121  	}
   122  
   123  	payload, err := ioutil.ReadAll(r.Body)
   124  	if err != nil || len(payload) == 0 {
   125  		return nil, ErrParsingPayload
   126  	}
   127  
   128  	switch bitbucketEvent {
   129  	case RepoPushEvent:
   130  		var pl RepoPushPayload
   131  		err = json.Unmarshal([]byte(payload), &pl)
   132  		return pl, err
   133  	case RepoForkEvent:
   134  		var pl RepoForkPayload
   135  		err = json.Unmarshal([]byte(payload), &pl)
   136  		return pl, err
   137  	case RepoUpdatedEvent:
   138  		var pl RepoUpdatedPayload
   139  		err = json.Unmarshal([]byte(payload), &pl)
   140  		return pl, err
   141  	case RepoCommitCommentCreatedEvent:
   142  		var pl RepoCommitCommentCreatedPayload
   143  		err = json.Unmarshal([]byte(payload), &pl)
   144  		return pl, err
   145  	case RepoCommitStatusCreatedEvent:
   146  		var pl RepoCommitStatusCreatedPayload
   147  		err = json.Unmarshal([]byte(payload), &pl)
   148  		return pl, err
   149  	case RepoCommitStatusUpdatedEvent:
   150  		var pl RepoCommitStatusUpdatedPayload
   151  		err = json.Unmarshal([]byte(payload), &pl)
   152  		return pl, err
   153  	case IssueCreatedEvent:
   154  		var pl IssueCreatedPayload
   155  		err = json.Unmarshal([]byte(payload), &pl)
   156  		return pl, err
   157  	case IssueUpdatedEvent:
   158  		var pl IssueUpdatedPayload
   159  		err = json.Unmarshal([]byte(payload), &pl)
   160  		return pl, err
   161  	case IssueCommentCreatedEvent:
   162  		var pl IssueCommentCreatedPayload
   163  		err = json.Unmarshal([]byte(payload), &pl)
   164  		return pl, err
   165  	case PullRequestCreatedEvent:
   166  		var pl PullRequestCreatedPayload
   167  		err = json.Unmarshal([]byte(payload), &pl)
   168  		return pl, err
   169  	case PullRequestUpdatedEvent:
   170  		var pl PullRequestUpdatedPayload
   171  		err = json.Unmarshal([]byte(payload), &pl)
   172  		return pl, err
   173  	case PullRequestApprovedEvent:
   174  		var pl PullRequestApprovedPayload
   175  		err = json.Unmarshal([]byte(payload), &pl)
   176  		return pl, err
   177  	case PullRequestUnapprovedEvent:
   178  		var pl PullRequestUnapprovedPayload
   179  		err = json.Unmarshal([]byte(payload), &pl)
   180  		return pl, err
   181  	case PullRequestMergedEvent:
   182  		var pl PullRequestMergedPayload
   183  		err = json.Unmarshal([]byte(payload), &pl)
   184  		return pl, err
   185  	case PullRequestDeclinedEvent:
   186  		var pl PullRequestDeclinedPayload
   187  		err = json.Unmarshal([]byte(payload), &pl)
   188  		return pl, err
   189  	case PullRequestCommentCreatedEvent:
   190  		var pl PullRequestCommentCreatedPayload
   191  		err = json.Unmarshal([]byte(payload), &pl)
   192  		return pl, err
   193  	case PullRequestCommentUpdatedEvent:
   194  		var pl PullRequestCommentUpdatedPayload
   195  		err = json.Unmarshal([]byte(payload), &pl)
   196  		return pl, err
   197  	case PullRequestCommentDeletedEvent:
   198  		var pl PullRequestCommentDeletedPayload
   199  		err = json.Unmarshal([]byte(payload), &pl)
   200  		return pl, err
   201  	default:
   202  		return nil, fmt.Errorf("unknown event %s", bitbucketEvent)
   203  	}
   204  }