Compare commits

...

66 Commits

Author SHA1 Message Date
Dean Karn 8ffb2ffc32 Update README.md 2018-06-28 12:32:45 -07:00
Dean Karn 84dc839b94 Merge pull request #33 from kishorenc/fix_deployment_payload
Deployment Payload fields should be of type string.
2018-06-28 12:32:17 -07:00
Kishore Nallan 2c541a737f Deployment Payload fields should be string. 2018-06-28 16:33:41 +05:30
Dean Karn be944ed461 update REAME + travis.yml 2018-05-08 07:55:49 -07:00
Dean Karn 16896cdb6b Merge pull request #29 from naiba/v3
Add gogs support
2018-05-08 07:51:34 -07:00
奶爸 3e1bb69b7d fix merge issue 2018-05-08 22:09:43 +08:00
奶爸 c9c9d981d7 godmt 2018-05-07 18:42:23 +08:00
奶爸 22713e3054 add gogs support 2018-05-07 18:41:12 +08:00
奶爸 0ebe5231e2 merge 2018-04-11 16:13:03 +08:00
奶爸 b26a00f48c remove space 2018-04-11 16:11:21 +08:00
Dean Karn 5580947e3e Update README.md 2018-04-08 09:15:57 -07:00
Dean Karn 8db8abb389 Merge pull request #28 from rtnpro/parse-github-pull-request-labels
Parse Github pull request labels from pull request payload.
2018-04-08 09:15:30 -07:00
Ratnadeep Debnath 9e4b7fa61b Parse Github pull request labels from pull request payload. 2018-04-02 12:14:20 +05:30
奶爸 a831111e26 Merge remote-tracking branch 'upstream/v3' into v3 2018-03-23 11:19:22 +08:00
Dean Karn f2acbcde40 Update README.md 2018-03-21 08:13:12 -07:00
Dean Karn 3ad83a882d Update README.md 2018-03-21 08:12:58 -07:00
Dean Karn 32331e68eb Merge pull request #27 from lukepatrick/v3
fix(bitbucket) typo in Event
2018-03-21 08:12:28 -07:00
奶爸 6d731433c9 Merge remote-tracking branch 'upstream/v3' into v3 2018-03-21 16:25:13 +08:00
lukepatrick 1253715fd8 fix(bitbucket) typo in Event 2018-03-20 11:20:36 -06:00
奶爸 d4d9692af0 [fix]Gogs sign verify 2018-03-20 11:27:21 +08:00
Dean Karn 1b6492ce45 Merge pull request #26 from kuiro5/add-requested-reviewers
Add RequestedReviewers to PullRequestPayload
2018-03-19 08:41:56 -07:00
奶爸 493e94de50 [fix] Gogs signature calc 2018-03-19 16:16:01 +08:00
奶爸 fc20b2a250 ignore IDEA 2018-03-19 14:26:32 +08:00
奶爸 1c3914ef16 edit import 2018-03-19 14:25:52 +08:00
奶爸 2aa5fdc243 add gogs support 2018-03-19 14:03:56 +08:00
kuiros ea44f6921c Add RequestedReviewers to PullRequestPayload 2018-03-10 15:33:16 -08:00
Dean Karn b6e930d373 Update README.md 2018-02-23 05:13:07 -08:00
Dean Karn c271ec3e32 Merge pull request #25 from lukepatrick/v3
Update bitbucket uuid check to allow a non-specified uuid, similar to…
2018-02-23 05:10:58 -08:00
lukepatrick 0c4911f7f5 Update bitbucket uuid check to allow a non-specified uuid, similar to gitlab empty secret. 2018-02-22 15:27:54 -07:00
Dean Karn 3667088d60 Merge pull request #24 from lukepatrick/v3
update MergeRequestEvent payload with Project, Repo objects from the API
2018-02-15 07:22:55 -08:00
lukepatrick 9cafa895ff update MergeRequestEvent payload with Project, Repo objects from the API 2018-02-14 12:45:52 -07:00
Dean Karn 9494e434fc Update README.md 2018-01-19 08:54:08 -08:00
Dean Karn 97dd8f3564 Merge pull request #23 from PombeirP/add-installation-and-ping
Add installation and ping
2018-01-19 08:46:12 -08:00
Pedro Pombeiro 8f6fada23d Add support for ping events 2018-01-16 10:15:54 +01:00
Pedro Pombeiro 94f9d6694d Add support for installation and integration_installation events 2018-01-16 10:15:29 +01:00
Dean Karn ad5392160c Update README.md 2017-12-17 22:05:38 -08:00
Dean Karn 19cab958b6 Merge pull request #21 from Mingan/master
[GitLab] Parse label changes on issue and MR events
2017-12-17 22:05:13 -08:00
Štěpán Pilař 78ce03b046 [GitLab] Parse label changes on issue and MR events 2017-12-17 17:50:34 +01:00
Dean Karn ced2e979bc Merge pull request #19 from kairen/add-author-association
Add parse author association for GitHub comment
2017-10-22 09:17:54 -07:00
kairen d60a03e52a Add parse author association for GitHub comment 2017-10-20 16:14:26 +08:00
Dean Karn f553bfaa59 Update README.md 2017-10-01 19:29:18 -07:00
Dean Karn 903279e458 add test for confidential issues gitlab 2017-10-01 19:24:09 -07:00
Dean Karn 5462959f1e Merge pull request #18 from tulir/patch-2
[GitLab] Add support for confidential issues
2017-10-01 19:17:33 -07:00
Dean Karn 4964805803 Merge pull request #17 from tulir/patch-1
[GitLab] Fix type of SourceProjectID in MergeRequest struct
2017-10-01 19:16:55 -07:00
Tulir Asokan 13e6611c00 Add separate payload type for confidential issues 2017-10-01 23:13:19 +03:00
Tulir Asokan b9424ab72e Add support for confidential GitLab issues 2017-10-01 13:56:19 +03:00
Tulir Asokan 203bf4218b Fix type of SourceProjectID in MergeRequest struct
It should be an int64, but was a string.
https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-merge-request

The incorrect type caused the MergeRequest field in comment event payloads to be empty.
2017-09-29 19:54:03 +00:00
Dean Karn 5e4be82c0b Update README.md 2017-08-17 08:39:34 -07:00
Dean Karn cd89a10b64 Merge pull request #16 from samuelkarp/pr-label
payload: add Label to PullRequestPayload
2017-08-17 08:34:59 -07:00
Samuel Karp e120e3b3ba payload: add Label to PullRequestPayload 2017-08-12 17:24:29 -07:00
Dean Karn a5141d656b Add customizable Logger interface + info,error and debugs (#14)
* Add customizable Logger interface + info,error and debugs
* update travis.yml to atest golang versions
2017-07-15 12:12:11 -07:00
Dean Karn 9a8b92d028 Update README 2017-05-04 15:04:26 -04:00
Dean Karn 248dae5b83 Merge branch 'rakeshbala-fix/githubPushPayload' into v3 2017-05-04 15:02:51 -04:00
Rakesh Balasubramanian cc075dfe29 fix(github): adds sha to commits in push payload 2017-05-02 11:25:35 -04:00
Dean Karn c93876b3e9 Merge pull request #10 from go-playground/add-handler-support
Add handler support
2017-04-27 19:24:15 -04:00
Dean Karn 0926003ddf .travis.yml tweak for gopkg.in 2017-04-27 19:19:51 -04:00
Dean Karn 58dd13d367 Add Handler function
Handler(...) return an http.Handler of the webhook for use within your own Mux
2017-04-27 17:57:51 -04:00
Dean Karn 4fa39fdfab Add .travis.yml config 2017-04-27 17:40:55 -04:00
Dean Karn fccbba5986 Update README example typo 2017-04-22 12:47:22 -04:00
Dean Karn 0d7e42cf96 correct some spelling 2017-04-21 22:13:16 -04:00
Dean Karn c9ac93f3b3 Update README 2017-04-21 22:06:42 -04:00
Dean Karn 2d256610b0 Update BitBucket + GitLab Payloads 2017-04-21 22:03:45 -04:00
Dean Karn 05a2f7cd8d refine payload interface{} to types 2017-04-21 20:40:02 -04:00
Dean Karn 5ed22cdd66 Initial GitHub Webhook revamp 2017-04-21 19:45:07 -04:00
Dean Karn 2e471dc89c Update MergerRequestEvents to MergeRequestEvents 2017-04-21 16:11:04 -04:00
Dean Karn 64819086ff Update README.md 2017-04-08 11:48:29 -04:00
19 changed files with 8962 additions and 1899 deletions
+1
View File
@@ -6,6 +6,7 @@
# Folders # Folders
_obj _obj
_test _test
.idea
# Architecture specific extensions/prefixes # Architecture specific extensions/prefixes
*.[568vq] *.[568vq]
+38
View File
@@ -0,0 +1,38 @@
language: go
go:
- 1.10.2
- tip
matrix:
allow_failures:
- go: tip
notifications:
email:
recipients: dean.karn@gmail.com
on_success: change
on_failure: always
before_install:
- go get -u github.com/go-playground/overalls
- go get -u github.com/mattn/goveralls
- go get -u golang.org/x/tools/cmd/cover
- go get -u github.com/golang/lint/golint
- go get -u github.com/gordonklaus/ineffassign
- mkdir -p $GOPATH/src/gopkg.in
- ln -s $GOPATH/src/github.com/$TRAVIS_REPO_SLUG $GOPATH/src/gopkg.in/webhooks.v2
- ln -s $GOPATH/src/github.com/$TRAVIS_REPO_SLUG $GOPATH/src/gopkg.in/webhooks.v3
before_script:
- go vet ./...
script:
- gofmt -d -s .
- golint ./...
- ineffassign ./
- go test -v ./...
- go test -race
after_success: |
[ $TRAVIS_GO_VERSION = 1.10.2 ] &&
overalls -project="github.com/go-playground/webhooks" -covermode=count -ignore=.git,examples -debug &&
goveralls -coverprofile=overalls.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN
+13 -14
View File
@@ -1,13 +1,13 @@
Library webhooks Library webhooks
================ ================
<img align="right" src="https://raw.githubusercontent.com/go-playground/webhooks/v2/logo.png">![Project status](https://img.shields.io/badge/version-2.0.0-green.svg) <img align="right" src="https://raw.githubusercontent.com/go-playground/webhooks/v3/logo.png">![Project status](https://img.shields.io/badge/version-3.13.0-green.svg)
[![Build Status](https://semaphoreci.com/api/v1/projects/5b9e2eda-8f8d-40aa-8cb4-e3f6120171fe/587820/badge.svg)](https://semaphoreci.com/joeybloggs/webhooks) [![Build Status](https://travis-ci.org/go-playground/webhooks.svg?branch=v3)](https://travis-ci.org/go-playground/webhooks)
[![Coverage Status](https://coveralls.io/repos/go-playground/webhooks/badge.svg?branch=v2&service=github)](https://coveralls.io/github/go-playground/webhooks?branch=v2) [![Coverage Status](https://coveralls.io/repos/go-playground/webhooks/badge.svg?branch=v3&service=github)](https://coveralls.io/github/go-playground/webhooks?branch=v3)
[![Go Report Card](https://goreportcard.com/badge/go-playground/webhooks)](https://goreportcard.com/report/go-playground/webhooks) [![Go Report Card](https://goreportcard.com/badge/go-playground/webhooks)](https://goreportcard.com/report/go-playground/webhooks)
[![GoDoc](https://godoc.org/gopkg.in/go-playground/webhooks.v2?status.svg)](https://godoc.org/gopkg.in/go-playground/webhooks.v2) [![GoDoc](https://godoc.org/gopkg.in/go-playground/webhooks.v3?status.svg)](https://godoc.org/gopkg.in/go-playground/webhooks.v3)
![License](https://img.shields.io/dub/l/vibe-d.svg) ![License](https://img.shields.io/dub/l/vibe-d.svg)
Library webhooks allows for easy recieving and parsing of GitHub, Bitbucket and GitLab Webhook Events Library webhooks allows for easy receiving and parsing of GitHub, Bitbucket and GitLab Webhook Events
Features: Features:
@@ -24,17 +24,17 @@ Installation
Use go get. Use go get.
```shell ```shell
go get -u gopkg.in/go-playground/webhooks.v2 go get -u gopkg.in/go-playground/webhooks.v3
``` ```
Then import the package into your own code. Then import the package into your own code.
import "gopkg.in/go-playground/webhooks.v2" import "gopkg.in/go-playground/webhooks.v3"
Usage and Documentation Usage and Documentation
------ ------
Please see http://godoc.org/gopkg.in/go-playground/webhooks.v2 for detailed usage docs. Please see http://godoc.org/gopkg.in/go-playground/webhooks.v3 for detailed usage docs.
##### Examples: ##### Examples:
@@ -46,8 +46,8 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"gopkg.in/go-playground/webhooks.v2" "gopkg.in/go-playground/webhooks.v3"
"gopkg.in/go-playground/webhooks.v2/github" "gopkg.in/go-playground/webhooks.v3/github"
) )
const ( const (
@@ -75,7 +75,7 @@ func HandleRelease(payload interface{}, header webhooks.Header) {
pl := payload.(github.ReleasePayload) pl := payload.(github.ReleasePayload)
// only want to compile on full releases // only want to compile on full releases
if pl.Release.Draft || pl.Release.Prelelease || pl.Release.TargetCommitish != "master" { if pl.Release.Draft || pl.Release.Prerelease || pl.Release.TargetCommitish != "master" {
return return
} }
@@ -93,7 +93,6 @@ func HandlePullRequest(payload interface{}, header webhooks.Header) {
// Do whatever you want from here... // Do whatever you want from here...
fmt.Printf("%+v", pl) fmt.Printf("%+v", pl)
} }
``` ```
Single receiver for events you subscribe to Single receiver for events you subscribe to
@@ -104,8 +103,8 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"gopkg.in/go-playground/webhooks.v2" "gopkg.in/go-playground/webhooks.v3"
"gopkg.in/go-playground/webhooks.v2/github" "gopkg.in/go-playground/webhooks.v3/github"
) )
const ( const (
+43 -25
View File
@@ -2,10 +2,11 @@ package bitbucket
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"gopkg.in/go-playground/webhooks.v2" "gopkg.in/go-playground/webhooks.v3"
) )
// Webhook instance contains all methods needed to process events // Webhook instance contains all methods needed to process events
@@ -25,23 +26,24 @@ type Event string
// Bitbucket hook types // Bitbucket hook types
const ( const (
RepoPushEvent Event = "repo:push" RepoPushEvent Event = "repo:push"
RepoForkEvent Event = "repo:fork" RepoForkEvent Event = "repo:fork"
RepoCommitCommentCreatedEvent Event = "repo:commit_comment_created" RepoUpdatedEvent Event = "repo:updated"
RepoCommitStatusCreatedEvent Event = "repo:commit_status_created" RepoCommitCommentCreatedEvent Event = "repo:commit_comment_created"
RepoCommitStatusUpdatedEvent Event = "repo:commit_status_updated" RepoCommitStatusCreatedEvent Event = "repo:commit_status_created"
IssueCreatedEvent Event = "issue:created" RepoCommitStatusUpdatedEvent Event = "repo:commit_status_updated"
IssueUpdatedEvent Event = "issue:updated" IssueCreatedEvent Event = "issue:created"
IssueCommentCreatedEvent Event = "issue:comment_created" IssueUpdatedEvent Event = "issue:updated"
PullRequestCreatedEvent Event = "pullrequest:created" IssueCommentCreatedEvent Event = "issue:comment_created"
PullRequestUpdatedEvent Event = "pullrequest:updated" PullRequestCreatedEvent Event = "pullrequest:created"
PullRequestApprovedEvent Event = "pullrequest:approved" PullRequestUpdatedEvent Event = "pullrequest:updated"
PullRequestApprovalRemovedEvent Event = "pullrequest:unapproved" PullRequestApprovedEvent Event = "pullrequest:approved"
PullRequestMergedEvent Event = "pullrequest:fulfilled" PullRequestUnapprovedEvent Event = "pullrequest:unapproved"
PullRequestDeclinedEvent Event = "pullrequest:rejected" PullRequestMergedEvent Event = "pullrequest:fulfilled"
PullRequestCommentCreatedEvent Event = "pullrequest:comment_created" PullRequestDeclinedEvent Event = "pullrequest:rejected"
PullRequestCommentUpdatedEvent Event = "pullrequest:comment_updated" PullRequestCommentCreatedEvent Event = "pullrequest:comment_created"
PullRequestCommentDeletedEvent Event = "pull_request:comment_deleted" PullRequestCommentUpdatedEvent Event = "pullrequest:comment_updated"
PullRequestCommentDeletedEvent Event = "pullrequest:comment_deleted"
) )
// New creates and returns a WebHook instance denoted by the Provider type // New creates and returns a WebHook instance denoted by the Provider type
@@ -68,38 +70,50 @@ func (hook Webhook) RegisterEvents(fn webhooks.ProcessPayloadFunc, events ...Eve
// ParsePayload parses and verifies the payload and fires off the mapped function, if it exists. // ParsePayload parses and verifies the payload and fires off the mapped function, if it exists.
func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) { func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
webhooks.DefaultLog.Info("Parsing Payload...")
uuid := r.Header.Get("X-Hook-UUID") uuid := r.Header.Get("X-Hook-UUID")
if uuid == "" { if uuid == "" {
webhooks.DefaultLog.Error("Missing X-Hook-UUID Header")
http.Error(w, "400 Bad Request - Missing X-Hook-UUID Header", http.StatusBadRequest) http.Error(w, "400 Bad Request - Missing X-Hook-UUID Header", http.StatusBadRequest)
return return
} }
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Hook-UUID:%s", uuid))
if uuid != hook.uuid { if len(hook.uuid) > 0 {
http.Error(w, "403 Forbidden - Missing X-Hook-UUID does not match", http.StatusForbidden) if uuid != hook.uuid {
return webhooks.DefaultLog.Error(fmt.Sprintf("X-Hook-UUID %s does not match configured uuid of %s", uuid, hook.uuid))
http.Error(w, "403 Forbidden - X-Hook-UUID does not match", http.StatusForbidden)
return
}
} else {
webhooks.DefaultLog.Debug("hook uuid not defined - recommend setting for improved security")
} }
event := r.Header.Get("X-Event-Key") event := r.Header.Get("X-Event-Key")
if event == "" { if event == "" {
webhooks.DefaultLog.Error("Missing X-Event-Key Header")
http.Error(w, "400 Bad Request - Missing X-Event-Key Header", http.StatusBadRequest) http.Error(w, "400 Bad Request - Missing X-Event-Key Header", http.StatusBadRequest)
return return
} }
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Event-Key:%s", event))
bitbucketEvent := Event(event) bitbucketEvent := Event(event)
fn, ok := hook.eventFuncs[bitbucketEvent] fn, ok := hook.eventFuncs[bitbucketEvent]
// if no event registered // if no event registered
if !ok { if !ok {
webhooks.DefaultLog.Info(fmt.Sprintf("Webhook Event %s not registered, it is recommended to setup only events in bitbucket that will be registered in the webhook to avoid unnecessary traffic and reduce potential attack vectors.", event))
return return
} }
payload, err := ioutil.ReadAll(r.Body) payload, err := ioutil.ReadAll(r.Body)
if err != nil || len(payload) == 0 { if err != nil || len(payload) == 0 {
http.Error(w, "Error reading Body", http.StatusInternalServerError) webhooks.DefaultLog.Error("Issue reading Payload")
http.Error(w, "Issue reading Payload", http.StatusInternalServerError)
return return
} }
webhooks.DefaultLog.Debug(fmt.Sprintf("Payload:%s", string(payload)))
hd := webhooks.Header(r.Header) hd := webhooks.Header(r.Header)
switch bitbucketEvent { switch bitbucketEvent {
@@ -111,6 +125,10 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
var pl RepoForkPayload var pl RepoForkPayload
json.Unmarshal([]byte(payload), &pl) json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd) hook.runProcessPayloadFunc(fn, pl, hd)
case RepoUpdatedEvent:
var pl RepoUpdatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case RepoCommitCommentCreatedEvent: case RepoCommitCommentCreatedEvent:
var pl RepoCommitCommentCreatedPayload var pl RepoCommitCommentCreatedPayload
json.Unmarshal([]byte(payload), &pl) json.Unmarshal([]byte(payload), &pl)
@@ -147,8 +165,8 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
var pl PullRequestApprovedPayload var pl PullRequestApprovedPayload
json.Unmarshal([]byte(payload), &pl) json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd) hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestApprovalRemovedEvent: case PullRequestUnapprovedEvent:
var pl PullRequestApprovalRemovedPayload var pl PullRequestUnapprovedPayload
json.Unmarshal([]byte(payload), &pl) json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd) hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestMergedEvent: case PullRequestMergedEvent:
+182 -26
View File
@@ -9,7 +9,7 @@ import (
"time" "time"
. "gopkg.in/go-playground/assert.v1" . "gopkg.in/go-playground/assert.v1"
"gopkg.in/go-playground/webhooks.v2" "gopkg.in/go-playground/webhooks.v3"
) )
// NOTES: // NOTES:
@@ -24,7 +24,7 @@ import (
// //
// //
const ( const (
port = 3010 port = 3009
path = "/webhooks" path = "/webhooks"
) )
@@ -39,10 +39,30 @@ func TestMain(m *testing.M) {
// setup // setup
hook = New(&Config{UUID: "MY_UUID"}) hook = New(&Config{UUID: "MY_UUID"})
hook.RegisterEvents(HandlePayload, RepoPushEvent, RepoForkEvent, RepoCommitCommentCreatedEvent, RepoCommitStatusCreatedEvent, RepoCommitStatusUpdatedEvent, IssueCreatedEvent, IssueUpdatedEvent, IssueCommentCreatedEvent, PullRequestCreatedEvent, PullRequestUpdatedEvent, PullRequestApprovedEvent, PullRequestApprovalRemovedEvent, PullRequestMergedEvent, PullRequestDeclinedEvent, PullRequestCommentCreatedEvent, PullRequestCommentUpdatedEvent, PullRequestCommentDeletedEvent) hook.RegisterEvents(
HandlePayload,
RepoPushEvent,
RepoForkEvent,
RepoUpdatedEvent,
RepoCommitCommentCreatedEvent,
RepoCommitStatusCreatedEvent,
RepoCommitStatusUpdatedEvent,
IssueCreatedEvent,
IssueUpdatedEvent,
IssueCommentCreatedEvent,
PullRequestCreatedEvent,
PullRequestUpdatedEvent,
PullRequestApprovedEvent,
PullRequestUnapprovedEvent,
PullRequestMergedEvent,
PullRequestDeclinedEvent,
PullRequestCommentCreatedEvent,
PullRequestCommentUpdatedEvent,
PullRequestCommentDeletedEvent,
)
go webhooks.Run(hook, "127.0.0.1:"+strconv.Itoa(port), path) go webhooks.Run(hook, "127.0.0.1:"+strconv.Itoa(port), path)
time.Sleep(5000) time.Sleep(time.Millisecond * 500)
os.Exit(m.Run()) os.Exit(m.Run())
@@ -56,7 +76,7 @@ func TestProvider(t *testing.T) {
func TestUUIDMissingEvent(t *testing.T) { func TestUUIDMissingEvent(t *testing.T) {
payload := "{}" payload := "{}"
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Event-Key", "noneexistant_event") req.Header.Set("X-Event-Key", "noneexistant_event")
@@ -74,7 +94,7 @@ func TestUUIDMissingEvent(t *testing.T) {
func TestUUIDDoesNotMatchEvent(t *testing.T) { func TestUUIDDoesNotMatchEvent(t *testing.T) {
payload := "{}" payload := "{}"
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "THIS_DOES_NOT_MATCH") req.Header.Set("X-Hook-UUID", "THIS_DOES_NOT_MATCH")
@@ -92,7 +112,7 @@ func TestUUIDDoesNotMatchEvent(t *testing.T) {
func TestBadNoEventHeader(t *testing.T) { func TestBadNoEventHeader(t *testing.T) {
payload := "{}" payload := "{}"
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
@@ -110,7 +130,7 @@ func TestBadNoEventHeader(t *testing.T) {
func TestUnsubscribedEvent(t *testing.T) { func TestUnsubscribedEvent(t *testing.T) {
payload := "{}" payload := "{}"
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "noneexistant_event") req.Header.Set("X-Event-Key", "noneexistant_event")
@@ -129,7 +149,7 @@ func TestUnsubscribedEvent(t *testing.T) {
func TestBadBody(t *testing.T) { func TestBadBody(t *testing.T) {
payload := "" payload := ""
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "repo:push") req.Header.Set("X-Event-Key", "repo:push")
@@ -355,7 +375,7 @@ func TestRepoPush(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "repo:push") req.Header.Set("X-Event-Key", "repo:push")
@@ -429,7 +449,7 @@ func TestRepoFork(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "repo:fork") req.Header.Set("X-Event-Key", "repo:fork")
@@ -445,6 +465,142 @@ func TestRepoFork(t *testing.T) {
Equal(t, resp.StatusCode, http.StatusOK) Equal(t, resp.StatusCode, http.StatusOK)
} }
func TestRepoUpdated(t *testing.T) {
payload := `{
"actor": {
"type": "user",
"username": "emmap1",
"display_name": "Emma",
"uuid": "{a54f16da-24e9-4d7f-a3a7-b1ba2cd98aa3}",
"links": {
"self": {
"href": "https://api.bitbucket.org/api/2.0/users/emmap1"
},
"html": {
"href": "https://api.bitbucket.org/emmap1"
},
"avatar": {
"href": "https://bitbucket-api-assetroot.s3.amazonaws.com/c/photos/2015/Feb/26/3613917261-0-emmap1-avatar_avatar.png"
}
}
},
"repository": {
"type": "repository",
"links": {
"self": {
"href": "https://api.bitbucket.org/api/2.0/repositories/bitbucket/bitbucket"
},
"html": {
"href": "https://api.bitbucket.org/bitbucket/bitbucket"
},
"avatar": {
"href": "https://api-staging-assetroot.s3.amazonaws.com/c/photos/2014/Aug/01/bitbucket-logo-2629490769-3_avatar.png"
}
},
"uuid": "{673a6070-3421-46c9-9d48-90745f7bfe8e}",
"project": {
"type": "project",
"project": "Untitled project",
"uuid": "{3b7898dc-6891-4225-ae60-24613bb83080}",
"links": {
"html": {
"href": "https://bitbucket.org/account/user/teamawesome/projects/proj"
},
"avatar": {
"href": "https://bitbucket.org/account/user/teamawesome/projects/proj/avatar/32"
}
},
"key": "proj"
},
"full_name": "team_name/repo_name",
"name": "repo_name",
"website": "https://mywebsite.com/",
"owner": {
"type": "user",
"username": "emmap1",
"display_name": "Emma",
"uuid": "{a54f16da-24e9-4d7f-a3a7-b1ba2cd98aa3}",
"links": {
"self": {
"href": "https://api.bitbucket.org/api/2.0/users/emmap1"
},
"html": {
"href": "https://api.bitbucket.org/emmap1"
},
"avatar": {
"href": "https://bitbucket-api-assetroot.s3.amazonaws.com/c/photos/2015/Feb/26/3613917261-0-emmap1-avatar_avatar.png"
}
}
},
"scm": "git",
"is_private": true
},
"changes": {
"name": {
"new": "repository",
"old": "repository_name"
},
"website": {
"new": "http://www.example.com/",
"old": ""
},
"language": {
"new": "java",
"old": ""
},
"links": {
"new": {
"avatar": {
"href": "https://bitbucket.org/teamawesome/repository/avatar/32/"
},
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/teamawesome/repository"
},
"html": {
"href": "https://bitbucket.org/teamawesome/repository"
}
},
"old": {
"avatar": {
"href": "https://bitbucket.org/teamawesome/repository_name/avatar/32/"
},
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/teamawesome/repository_name"
},
"html": {
"href": "https://bitbucket.org/teamawesome/repository_name"
}
}
},
"description": {
"new": "This is a better description.",
"old": "This is a description."
},
"full_name": {
"new": "teamawesome/repository",
"old": "teamawesome/repository_name"
}
}
}
`
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "repo:updated")
Equal(t, err, nil)
client := &http.Client{}
resp, err := client.Do(req)
Equal(t, err, nil)
defer resp.Body.Close()
Equal(t, resp.StatusCode, http.StatusOK)
}
func TestRepoCommitCommentCreated(t *testing.T) { func TestRepoCommitCommentCreated(t *testing.T) {
payload := `{ payload := `{
@@ -514,7 +670,7 @@ func TestRepoCommitCommentCreated(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "repo:commit_comment_created") req.Header.Set("X-Event-Key", "repo:commit_comment_created")
@@ -588,7 +744,7 @@ func TestRepoCommitStatusCreated(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "repo:commit_status_created") req.Header.Set("X-Event-Key", "repo:commit_status_created")
@@ -662,7 +818,7 @@ func TestRepoCommitStatusUpdated(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "repo:commit_status_updated") req.Header.Set("X-Event-Key", "repo:commit_status_updated")
@@ -747,7 +903,7 @@ func TestIssueCreated(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "issue:created") req.Header.Set("X-Event-Key", "issue:created")
@@ -864,7 +1020,7 @@ func TestIssueUpdated(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "issue:updated") req.Header.Set("X-Event-Key", "issue:updated")
@@ -975,7 +1131,7 @@ func TestIssueCommentCreated(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "issue:comment_created") req.Header.Set("X-Event-Key", "issue:comment_created")
@@ -1172,7 +1328,7 @@ func TestPullRequestCreated(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "pullrequest:created") req.Header.Set("X-Event-Key", "pullrequest:created")
@@ -1369,7 +1525,7 @@ func TestPullRequestUpdated(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "pullrequest:updated") req.Header.Set("X-Event-Key", "pullrequest:updated")
@@ -1585,7 +1741,7 @@ func TestPullRequestApproved(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "pullrequest:approved") req.Header.Set("X-Event-Key", "pullrequest:approved")
@@ -1801,7 +1957,7 @@ func TestPullRequestApprovalRemoved(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "pullrequest:unapproved") req.Header.Set("X-Event-Key", "pullrequest:unapproved")
@@ -1998,7 +2154,7 @@ func TestPullRequestMerged(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "pullrequest:fulfilled") req.Header.Set("X-Event-Key", "pullrequest:fulfilled")
@@ -2195,7 +2351,7 @@ func TestPullRequestDeclined(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "pullrequest:rejected") req.Header.Set("X-Event-Key", "pullrequest:rejected")
@@ -2418,7 +2574,7 @@ func TestPullRequestCommentCreated(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "pullrequest:comment_created") req.Header.Set("X-Event-Key", "pullrequest:comment_created")
@@ -2641,7 +2797,7 @@ func TestPullRequestCommentUpdated(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "pullrequest:comment_updated") req.Header.Set("X-Event-Key", "pullrequest:comment_updated")
@@ -2864,7 +3020,7 @@ func TestPullRequestCommentDeleted(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3010/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Hook-UUID", "MY_UUID") req.Header.Set("X-Hook-UUID", "MY_UUID")
req.Header.Set("X-Event-Key", "pull_request:comment_deleted") req.Header.Set("X-Event-Key", "pull_request:comment_deleted")
+457 -337
View File
@@ -2,388 +2,508 @@ package bitbucket
import "time" import "time"
// PullRequestCommentDeletedPayload is the Bitbucket pull_request:comment_deleted payload // RepoPushPayload is the Bitbucket repo:push payload
type PullRequestCommentDeletedPayload struct { type RepoPushPayload struct {
Actor User `json:"actor"` Actor Owner `json:"actor"`
Repository Repository `json:"repository"`
PullRequest PullRequest `json:"pullrequest"`
Comment Comment `json:"comment"`
}
// PullRequestCommentUpdatedPayload is the Bitbucket pullrequest:comment_updated payload
type PullRequestCommentUpdatedPayload struct {
Actor User `json:"actor"`
Repository Repository `json:"repository"`
PullRequest PullRequest `json:"pullrequest"`
Comment Comment `json:"comment"`
}
// PullRequestCommentCreatedPayload is the Bitbucket pullrequest:comment_created payload
type PullRequestCommentCreatedPayload struct {
Actor User `json:"actor"`
Repository Repository `json:"repository"`
PullRequest PullRequest `json:"pullrequest"`
Comment Comment `json:"comment"`
}
// PullRequestDeclinedPayload is the Bitbucket pullrequest:rejected payload
type PullRequestDeclinedPayload struct {
Actor User `json:"actor"`
PullRequest PullRequest `json:"pullrequest"`
Repository Repository `json:"repository"`
}
// PullRequestMergedPayload is the Bitbucket pullrequest:fulfilled payload
type PullRequestMergedPayload struct {
Actor User `json:"actor"`
PullRequest PullRequest `json:"pullrequest"`
Repository Repository `json:"repository"`
}
// PullRequestApprovalRemovedPayload is the Bitbucket pullrequest:unapproved payload
type PullRequestApprovalRemovedPayload struct {
Actor User `json:"actor"`
PullRequest PullRequest `json:"pullrequest"`
Repository Repository `json:"repository"`
Approval Approval `json:"approval"`
}
// PullRequestApprovedPayload is the Bitbucket pullrequest:approved payload
type PullRequestApprovedPayload struct {
Actor User `json:"actor"`
PullRequest PullRequest `json:"pullrequest"`
Repository Repository `json:"repository"`
Approval Approval `json:"approval"`
}
// PullRequestUpdatedPayload is the Bitbucket pullrequest:updated payload
type PullRequestUpdatedPayload struct {
Actor User `json:"actor"`
PullRequest PullRequest `json:"pullrequest"`
Repository Repository `json:"repository"`
}
// PullRequestCreatedPayload is the Bitbucket pullrequest:created payload
type PullRequestCreatedPayload struct {
Actor User `json:"actor"`
PullRequest PullRequest `json:"pullrequest"`
Repository Repository `json:"repository"`
}
// IssueCommentCreatedPayload is the Bitbucket issue:comment_created payload
type IssueCommentCreatedPayload struct {
Actor User `json:"actor"`
Repository Repository `json:"repository"` Repository Repository `json:"repository"`
Issue Issue `json:"issue"` Push struct {
Comment Comment `json:"comment"` Changes []struct {
} New struct {
Type string `json:"type"`
// IssueUpdatedPayload is the Bitbucket issue:updated payload Name string `json:"name"`
type IssueUpdatedPayload struct { Target struct {
Actor User `json:"actor"` Type string `json:"type"`
Issue Issue `json:"issue"` Hash string `json:"hash"`
Repository Repository `json:"repository"` Author Owner `json:"author"`
Comment Comment `json:"comment"` Message string `json:"message"`
Changes IssueChanges `json:"changes"` Date time.Time `json:"date"`
} Parents []struct {
Type string `json:"type"`
// IssueCreatedPayload is the Bitbucket issue:created payload Hash string `json:"hash"`
type IssueCreatedPayload struct { Links struct {
Actor User `json:"actor"` Self struct {
Issue Issue `json:"issue"` Href string `json:"href"`
Repository Repository `json:"repository"` } `json:"self"`
} HTML struct {
Href string `json:"href"`
// RepoCommitStatusUpdatedPayload is the Bitbucket repo:commit_status_updated payload } `json:"html"`
type RepoCommitStatusUpdatedPayload struct { } `json:"links"`
Actor User `json:"actor"` } `json:"parents"`
Repository Repository `json:"repository"` Links struct {
CommitStatus CommitStatus `json:"commit_status"` Self struct {
} Href string `json:"href"`
} `json:"self"`
// RepoCommitStatusCreatedPayload is the Bitbucket repo:commit_status_created payload HTML struct {
type RepoCommitStatusCreatedPayload struct { Href string `json:"href"`
Actor User `json:"actor"` } `json:"html"`
Repository Repository `json:"repository"` } `json:"links"`
CommitStatus CommitStatus `json:"commit_status"` } `json:"target"`
} Links struct {
Self struct {
// RepoCommitCommentCreatedPayload is the Bitbucket repo:commit_comment_created payload Href string `json:"href"`
type RepoCommitCommentCreatedPayload struct { } `json:"self"`
Actor User `json:"actor"` Commits struct {
Comment Comment `json:"comment"` Href string `json:"href"`
Repository Repository `json:"repository"` } `json:"commits"`
Commit CommitHash `json:"commit"` HTML struct {
Href string `json:"href"`
} `json:"html"`
} `json:"links"`
} `json:"new"`
Old struct {
Type string `json:"type"`
Name string `json:"name"`
Target struct {
Type string `json:"type"`
Hash string `json:"hash"`
Author Owner `json:"author"`
Message string `json:"message"`
Date time.Time `json:"date"`
Parents []struct {
Type string `json:"type"`
Hash string `json:"hash"`
Links struct {
Self struct {
Href string `json:"href"`
} `json:"self"`
HTML struct {
Href string `json:"href"`
} `json:"html"`
} `json:"links"`
} `json:"parents"`
Links struct {
Self struct {
Href string `json:"href"`
} `json:"self"`
HTML struct {
Href string `json:"href"`
} `json:"html"`
} `json:"links"`
} `json:"target"`
Links struct {
Self struct {
Href string `json:"href"`
} `json:"self"`
Commits struct {
Href string `json:"href"`
} `json:"commits"`
HTML struct {
Href string `json:"href"`
} `json:"html"`
} `json:"links"`
} `json:"old"`
Links struct {
HTML struct {
Href string `json:"href"`
} `json:"html"`
Diff struct {
Href string `json:"href"`
} `json:"diff"`
Commits struct {
Href string `json:"href"`
} `json:"commits"`
} `json:"links"`
Created bool `json:"created"`
Forced bool `json:"forced"`
Closed bool `json:"closed"`
Commits []struct {
Hash string `json:"hash"`
Type string `json:"type"`
Message string `json:"message"`
Author Owner `json:"author"`
Links struct {
Self struct {
Href string `json:"href"`
} `json:"self"`
HTML struct {
Href string `json:"href"`
} `json:"html"`
} `json:"links"`
} `json:"commits"`
Truncated bool `json:"truncated"`
} `json:"changes"`
} `json:"push"`
} }
// RepoForkPayload is the Bitbucket repo:fork payload // RepoForkPayload is the Bitbucket repo:fork payload
type RepoForkPayload struct { type RepoForkPayload struct {
Actor User `json:"actor"` Actor Owner `json:"actor"`
Repository Repository `json:"repository"` Repository Repository `json:"repository"`
Fork Repository `json:"fork"` Fork Repository `json:"fork"`
} }
// RepoPushPayload is the Bitbucket repo:push payload // RepoUpdatedPayload is the Bitbucket repo:updated payload
type RepoPushPayload struct { type RepoUpdatedPayload struct {
Actor User `json:"actor"` Actor Owner `json:"actor"`
Repository Repository `json:"repository"` Repository Repository `json:"repository"`
Push Push `json:"push"` Changes struct {
Name struct {
New string `json:"new"`
Old string `json:"old"`
} `json:"name"`
Website struct {
New string `json:"new"`
Old string `json:"old"`
} `json:"website"`
Language struct {
New string `json:"new"`
Old string `json:"old"`
} `json:"language"`
Links struct {
New struct {
Avatar struct {
Href string `json:"href"`
} `json:"avatar"`
Self struct {
Href string `json:"href"`
} `json:"self"`
HTML struct {
Href string `json:"href"`
} `json:"html"`
} `json:"new"`
Old struct {
Avatar struct {
Href string `json:"href"`
} `json:"avatar"`
Self struct {
Href string `json:"href"`
} `json:"self"`
HTML struct {
Href string `json:"href"`
} `json:"html"`
} `json:"old"`
} `json:"links"`
Description struct {
New string `json:"new"`
Old string `json:"old"`
} `json:"description"`
FullName struct {
New string `json:"new"`
Old string `json:"old"`
} `json:"full_name"`
} `json:"changes"`
} }
// Approval is the common Bitbucket Issue Approval Sub Entity // RepoCommitCommentCreatedPayload is the Bitbucket repo:commit_comment_created payload
type Approval struct { type RepoCommitCommentCreatedPayload struct {
Date time.Time `json:"date"` Actor Owner `json:"actor"`
User User `json:"user"` Comment Comment `json:"comment"`
Repository Repository `json:"repository"`
Commit struct {
Hash string `json:"hash"`
} `json:"commit"`
} }
// IssueChanges is the common Bitbucket Issue Changes Sub Entity // RepoCommitStatusCreatedPayload is the Bitbucket repo:commit_status_created payload
type IssueChanges struct { type RepoCommitStatusCreatedPayload struct {
Status IssueChangeStatus `json:"status"` Actor Owner `json:"actor"`
Repository Repository `json:"repository"`
CommitStatus struct {
Name string `json:"name"`
Description string `json:"description"`
State string `json:"state"`
Key string `json:"key"`
URL string `json:"url"`
Type string `json:"type"`
CreatedOn time.Time `json:"created_on"`
UpdatedOn time.Time `json:"updated_on"`
Links struct {
Commit struct {
Href string `json:"href"`
} `json:"commit"`
Self struct {
Href string `json:"href"`
} `json:"self"`
} `json:"links"`
} `json:"commit_status"`
} }
// IssueChangeStatus is the common Bitbucket Issue Change Status Sub Entity // RepoCommitStatusUpdatedPayload is the Bitbucket repo:commit_status_updated payload
type IssueChangeStatus struct { type RepoCommitStatusUpdatedPayload struct {
Old string `json:"old"` Actor Owner `json:"actor"`
New string `json:"new"` Repository Repository `json:"repository"`
CommitStatus struct {
Name string `json:"name"`
Description string `json:"description"`
State string `json:"state"`
Key string `json:"key"`
URL string `json:"url"`
Type string `json:"type"`
CreatedOn time.Time `json:"created_on"`
UpdatedOn time.Time `json:"updated_on"`
Links struct {
Commit struct {
Href string `json:"href"`
} `json:"commit"`
Self struct {
Href string `json:"href"`
} `json:"self"`
} `json:"links"`
} `json:"commit_status"`
} }
// CommitStatus is the common Bitbucket CommitStatus Sub Entity // IssueCreatedPayload is the Bitbucket issue:created payload
type CommitStatus struct { type IssueCreatedPayload struct {
Name string `json:"name"` Actor Owner `json:"actor"`
Description string `json:"description"` Issue Issue `json:"issue"`
State string `json:"state"` Repository Repository `json:"repository"`
Key string `json:"key"`
URL string `json:"url"`
Type string `json:"type"`
CreatedOn time.Time `json:"created_on"`
UpdatedOn time.Time `json:"updated_on"`
Links LinksSelfCommit `json:"links"`
} }
// Push is the common Bitbucket Push Sub Entity // IssueUpdatedPayload is the Bitbucket issue:updated payload
type Push struct { type IssueUpdatedPayload struct {
Changes []Change `json:"changes"` Actor Owner `json:"actor"`
Issue Issue `json:"issue"`
Repository Repository `json:"repository"`
Comment Comment `json:"comment"`
Changes struct {
Status struct {
Old string `json:"old"`
New string `json:"new"`
} `json:"status"`
} `json:"changes"`
} }
// Change is the common Bitbucket Change Sub Entity // IssueCommentCreatedPayload is the Bitbucket pullrequest:created payload
type Change struct { type IssueCommentCreatedPayload struct {
New ChangeData `json:"new"` Actor Owner `json:"actor"`
Old ChangeData `json:"old"` Repository Repository `json:"repository"`
Links LinksHTMLDiffCommits `json:"links"` Issue Issue `json:"issue"`
Created bool `json:"created"` Comment Comment `json:"comment"`
Forced bool `json:"forced"`
Closed bool `json:"closed"`
Commits []Commit `json:"commits"`
Truncated bool `json:"truncated"`
} }
// ChangeData is the common Bitbucket ChangeData Sub Entity // PullRequestCreatedPayload is the Bitbucket pullrequest:created payload
type ChangeData struct { type PullRequestCreatedPayload struct {
Type string `json:"type"` Actor Owner `json:"actor"`
Name string `json:"name"` PullRequest PullRequest `json:"pullrequest"`
Target Target `json:"target"` Repository Repository `json:"repository"`
Links LinksHTMLSelfCommits `json:"links"`
} }
// Target is the common Bitbucket Target Sub Entity // PullRequestUpdatedPayload is the Bitbucket pullrequest:updated payload
type Target struct { type PullRequestUpdatedPayload struct {
Type string `json:"type"` Actor Owner `json:"actor"`
Hash string `json:"hash"` PullRequest PullRequest `json:"pullrequest"`
Author User `json:"author"` Repository Repository `json:"repository"`
Message string `json:"message"`
Date time.Time `json:"date"`
Parents []Parent `json:"parents"`
Links LinksHTMLSelf `json:"links"`
} }
// Parent is the common Bitbucket Parent Sub Entity // PullRequestApprovedPayload is the Bitbucket pullrequest:approved payload
type Parent struct { type PullRequestApprovedPayload struct {
Type string `json:"type"` Actor Owner `json:"actor"`
Hash string `json:"hash"` PullRequest PullRequest `json:"pullrequest"`
Links LinksHTMLSelf `json:"links"` Repository Repository `json:"repository"`
Approval struct {
Date time.Time `json:"date"`
User Owner `json:"user"`
} `json:"approval"`
} }
// Commit is the common Bitbucket Commit Sub Entity // PullRequestUnapprovedPayload is the Bitbucket pullrequest:unapproved payload
type Commit struct { type PullRequestUnapprovedPayload struct {
Hash string `json:"hash"` Actor Owner `json:"actor"`
Type string `json:"type"` PullRequest PullRequest `json:"pullrequest"`
Message string `json:"message"` Repository Repository `json:"repository"`
Author User `json:"author"` Approval struct {
Links LinksHTMLSelf `json:"links"` Date time.Time `json:"date"`
User Owner `json:"user"`
} `json:"approval"`
} }
// User is the common Bitbucket User Entity // PullRequestMergedPayload is the Bitbucket pullrequest:fulfilled payload
type User struct { type PullRequestMergedPayload struct {
Actor Owner `json:"actor"`
PullRequest PullRequest `json:"pullrequest"`
Repository Repository `json:"repository"`
}
// PullRequestDeclinedPayload is the Bitbucket pullrequest:rejected payload
type PullRequestDeclinedPayload struct {
Actor Owner `json:"actor"`
PullRequest PullRequest `json:"pullrequest"`
Repository Repository `json:"repository"`
}
// PullRequestCommentCreatedPayload is the Bitbucket pullrequest:comment_updated payload
type PullRequestCommentCreatedPayload struct {
Actor Owner `json:"actor"`
Repository Repository `json:"repository"`
PullRequest PullRequest `json:"pullrequest"`
Comment Comment `json:"comment"`
}
// PullRequestCommentUpdatedPayload is the Bitbucket pullrequest:comment_created payload
type PullRequestCommentUpdatedPayload struct {
Actor Owner `json:"actor"`
Repository Repository `json:"repository"`
PullRequest PullRequest `json:"pullrequest"`
Comment Comment `json:"comment"`
}
// PullRequestCommentDeletedPayload is the Bitbucket pullrequest:comment_deleted payload
type PullRequestCommentDeletedPayload struct {
Actor Owner `json:"actor"`
Repository Repository `json:"repository"`
PullRequest PullRequest `json:"pullrequest"`
Comment Comment `json:"comment"`
}
// Owner is the common Bitbucket Owner Sub Entity
type Owner struct {
Type string `json:"type"`
Username string `json:"username"` Username string `json:"username"`
DisplayName string `json:"display_name"` DisplayName string `json:"display_name"`
UUID string `json:"uuid"` UUID string `json:"uuid"`
Links Links `json:"links"` Links struct {
Self struct {
Href string `json:"href"`
} `json:"self"`
HTML struct {
Href string `json:"href"`
} `json:"html"`
Avatar struct {
Href string `json:"href"`
} `json:"avatar"`
} `json:"links"`
} }
// Repository is the common Bitbucket Repository Entity // Repository is the common Bitbucket Repository Sub Entity
type Repository struct { type Repository struct {
Links Links `json:"links"` Type string `json:"type"`
UUID string `json:"uuid"` Links struct {
FullName string `json:"full_name"` Self struct {
Name string `json:"name"` Href string `json:"href"`
Scm string `json:"scm"` } `json:"self"`
IsPrivate bool `json:"is_private"` HTML struct {
Href string `json:"href"`
} `json:"html"`
Avatar struct {
Href string `json:"href"`
} `json:"avatar"`
} `json:"links"`
UUID string `json:"uuid"`
Project Project `json:"project"`
FullName string `json:"full_name"`
Name string `json:"name"`
Website string `json:"website"`
Owner Owner `json:"owner"`
Scm string `json:"scm"`
IsPrivate bool `json:"is_private"`
} }
// Issue is the common Bitbucket Issue Entity // Project is the common Bitbucket Project Sub Entity
type Project struct {
Type string `json:"type"`
Project string `json:"project"`
UUID string `json:"uuid"`
Links struct {
HTML struct {
Href string `json:"href"`
} `json:"html"`
Avatar struct {
Href string `json:"href"`
} `json:"avatar"`
} `json:"links"`
Key string `json:"key"`
}
// Issue is the common Bitbucket Issue Sub Entity
type Issue struct { type Issue struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Component string `json:"component"` Component string `json:"component"`
Title string `json:"title"` Title string `json:"title"`
Content Content `json:"content"` Content struct {
Priority string `json:"priority"` Raw string `json:"raw"`
State string `json:"state"` HTML string `json:"html"`
Type string `json:"type"` Markup string `json:"markup"`
Milestone Milestone `json:"milestone"` } `json:"content"`
Version Version `json:"version"` Priority string `json:"priority"`
CreatedOn time.Time `json:"created_on"` State string `json:"state"`
UpdatedOn time.Time `json:"updated_on"` Type string `json:"type"`
Links LinksHTMLSelf `json:"links"` Milestone struct {
Name string `json:"name"`
} `json:"milestone"`
Version struct {
Name string `json:"name"`
} `json:"version"`
CreatedOn time.Time `json:"created_on"`
UpdatedOn time.Time `json:"updated_on"`
Links struct {
Self struct {
Href string `json:"href"`
} `json:"self"`
HTML struct {
Href string `json:"href"`
} `json:"html"`
} `json:"links"`
} }
// Comment is the common Bitbucket Comment Entity // Comment is the common Bitbucket Comment Sub Entity
type Comment struct { type Comment struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Parent ParentID `json:"parent"` Parent struct {
Content Content `json:"content"` ID int64 `json:"id"`
Inline Inline `json:"inline"` } `json:"parent"`
CreatedOn time.Time `json:"created_on"` Content struct {
UpdatedOn time.Time `json:"updated_on"` Raw string `json:"raw"`
Links LinksHTMLSelf `json:"links"` HTML string `json:"html"`
Markup string `json:"markup"`
} `json:"content"`
Inline struct {
Path string `json:"path"`
From *int64 `json:"from"`
To int64 `json:"to"`
} `json:"inline"`
CreatedOn time.Time `json:"created_on"`
UpdatedOn time.Time `json:"updated_on"`
Links struct {
Self struct {
Href string `json:"href"`
} `json:"self"`
HTML struct {
Href string `json:"href"`
} `json:"html"`
} `json:"links"`
} }
// PullRequest is the common Bitbucket PullRequest Entity // PullRequest is the common Bitbucket Pull Request Sub Entity
type PullRequest struct { type PullRequest struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
State string `json:"state"` State string `json:"state"`
Author User `json:"author"` Author Owner `json:"author"`
Source Source `json:"source"` Source struct {
Destination Destination `json:"destination"` Branch struct {
MergeCommit CommitHash `json:"merge_commit"` Name string `json:"name"`
Participants []User `json:"participants"` } `json:"branch"`
Reviewers []User `json:"reviewers"` Commit struct {
CloseSourceBranch bool `json:"close_source_branch"` Hash string `json:"hash"`
ClosedBy User `json:"closed_by"` } `json:"commit"`
Reason string `json:"reason"` Repository Repository `json:"repository"`
CreatedOn time.Time `json:"created_on"` } `json:"source"`
UpdatedOn time.Time `json:"updated_on"` Destination struct {
Links LinksHTMLSelf `json:"links"` Branch struct {
} Name string `json:"name"`
} `json:"branch"`
// Destination is the common Bitbucket Destination Sub Entity Commit struct {
type Destination struct { Hash string `json:"hash"`
Branch Branch `json:"branch"` } `json:"commit"`
Commit CommitHash `json:"commit"` Repository Repository `json:"repository"`
Repository Repository `json:"repository"` } `json:"destination"`
} MergeCommit struct {
Hash string `json:"hash"`
// Source is the common Bitbucket Source Sub Entity } `json:"merge_commit"`
type Source struct { Participants []Owner `json:"participants"`
Branch Branch `json:"branch"` Reviewers []Owner `json:"reviewers"`
Commit CommitHash `json:"commit"` CloseSourceBranch bool `json:"close_source_branch"`
Repository Repository `json:"repository"` ClosedBy Owner `json:"closed_by"`
} Reason string `json:"reason"`
CreatedOn time.Time `json:"created_on"`
// Branch is the common Bitbucket Branch Sub Entity UpdatedOn time.Time `json:"updated_on"`
type Branch struct { Links struct {
Name string `json:"name"` Self struct {
} Href string `json:"href"`
} `json:"self"`
// CommitHash is the common Bitbucket CommitHash Sub Entity HTML struct {
type CommitHash struct { Href string `json:"href"`
Hash string `json:"hash"` } `json:"html"`
} } `json:"links"`
// Inline is the common Bitbucket Inline Sub Entity
type Inline struct {
Path string `json:"path"`
From *int64 `json:"from"`
To int64 `json:"to"`
}
// ParentID is the common Bitbucket ParentID Sub Entity
type ParentID struct {
ID int64 `json:"id"`
}
// Avatar is the common Bitbucket Avatar Sub Entity
type Avatar struct {
HREF string `json:"href"`
}
// HTML is the common Bitbucket HTML Sub Entity
type HTML struct {
HREF string `json:"href"`
}
// Self is the common Bitbucket Self Sub Entity
type Self struct {
HREF string `json:"href"`
}
// Diff is the common Bitbucket Diff Sub Entity
type Diff struct {
HREF string `json:"href"`
}
// Commits is the common Bitbucket Commits Sub Entity
type Commits struct {
HREF string `json:"href"`
}
// LinksSelfCommit is the common Bitbucket LinksSelfCommit Sub Entity
type LinksSelfCommit struct {
Self Self `json:"self"`
Commit Commits `json:"commit"`
}
// LinksHTMLSelfCommits is the common Bitbucket LinksHTMLSelfCommits Sub Entity
type LinksHTMLSelfCommits struct {
Self Self `json:"self"`
Commits Commits `json:"commits"`
HTML HTML `json:"html"`
}
// LinksHTMLDiffCommits is the common Bitbucket LinksHTMLDiffCommits Sub Entity
type LinksHTMLDiffCommits struct {
HTML HTML `json:"html"`
Diff Diff `json:"diff"`
Commits Commits `json:"commits"`
}
// Links is the common Bitbucket Links Sub Entity
type Links struct {
Avatar Avatar `json:"avatar"`
HTML HTML `json:"html"`
Self Self `json:"self"`
}
// LinksHTMLSelf is the common Bitbucket LinksHTMLSelf Sub Entity
type LinksHTMLSelf struct {
HTML HTML `json:"html"`
Self Self `json:"self"`
}
// Content is the common Bitbucket Content Sub Entity
type Content struct {
HTML string `json:"html"`
Markup string `json:"markup"`
Raw string `json:"raw"`
}
// Milestone is the common Bitbucket Milestone Sub Entity
type Milestone struct {
Name string `json:"name"`
}
// Version is the common Bitbucket Version Sub Entity
type Version struct {
Name string `json:"name"`
} }
+67
View File
@@ -0,0 +1,67 @@
package main
import (
"fmt"
"log"
"strconv"
"gopkg.in/go-playground/webhooks.v3"
"gopkg.in/go-playground/webhooks.v3/github"
)
const (
path = "/webhooks"
port = 3016
)
type myLogger struct {
PrintDebugs bool
}
func (l *myLogger) Info(msg string) {
log.Println(msg)
}
func (l *myLogger) Error(msg string) {
log.Println(msg)
}
func (l *myLogger) Debug(msg string) {
if !l.PrintDebugs {
return
}
log.Println(msg)
}
func main() {
// webhooks.DefaultLog=webhooks.NewLogger(true)
//
// or override with your own
webhooks.DefaultLog = &myLogger{PrintDebugs: true}
hook := github.New(&github.Config{Secret: "MyGitHubSuperSecretSecrect...?"})
hook.RegisterEvents(HandleMultiple, github.ReleaseEvent, github.PullRequestEvent) // Add as many as you want
err := webhooks.Run(hook, ":"+strconv.Itoa(port), path)
if err != nil {
fmt.Println(err)
}
}
// HandleMultiple handles multiple GitHub events
func HandleMultiple(payload interface{}, header webhooks.Header) {
fmt.Println("Handling Payload..")
switch payload.(type) {
case github.ReleasePayload:
release := payload.(github.ReleasePayload)
// Do whatever you want from here...
fmt.Printf("%+v", release)
case github.PullRequestPayload:
pullRequest := payload.(github.PullRequestPayload)
// Do whatever you want from here...
fmt.Printf("%+v", pullRequest)
}
}
+3 -5
View File
@@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"gopkg.in/go-playground/webhooks.v2" "gopkg.in/go-playground/webhooks.v3"
"gopkg.in/go-playground/webhooks.v2/github" "gopkg.in/go-playground/webhooks.v3/github"
) )
const ( const (
@@ -14,7 +14,6 @@ const (
) )
func main() { func main() {
hook := github.New(&github.Config{Secret: "MyGitHubSuperSecretSecrect...?"}) hook := github.New(&github.Config{Secret: "MyGitHubSuperSecretSecrect...?"})
hook.RegisterEvents(HandleRelease, github.ReleaseEvent) hook.RegisterEvents(HandleRelease, github.ReleaseEvent)
hook.RegisterEvents(HandlePullRequest, github.PullRequestEvent) hook.RegisterEvents(HandlePullRequest, github.PullRequestEvent)
@@ -27,13 +26,12 @@ func main() {
// HandleRelease handles GitHub release events // HandleRelease handles GitHub release events
func HandleRelease(payload interface{}, header webhooks.Header) { func HandleRelease(payload interface{}, header webhooks.Header) {
fmt.Println("Handling Release") fmt.Println("Handling Release")
pl := payload.(github.ReleasePayload) pl := payload.(github.ReleasePayload)
// only want to compile on full releases // only want to compile on full releases
if pl.Release.Draft || pl.Release.Prelelease || pl.Release.TargetCommitish != "master" { if pl.Release.Draft || pl.Release.Prerelease || pl.Release.TargetCommitish != "master" {
return return
} }
+2 -4
View File
@@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"gopkg.in/go-playground/webhooks.v2" "gopkg.in/go-playground/webhooks.v3"
"gopkg.in/go-playground/webhooks.v2/github" "gopkg.in/go-playground/webhooks.v3/github"
) )
const ( const (
@@ -14,7 +14,6 @@ const (
) )
func main() { func main() {
hook := github.New(&github.Config{Secret: "MyGitHubSuperSecretSecrect...?"}) hook := github.New(&github.Config{Secret: "MyGitHubSuperSecretSecrect...?"})
hook.RegisterEvents(HandleMultiple, github.ReleaseEvent, github.PullRequestEvent) // Add as many as you want hook.RegisterEvents(HandleMultiple, github.ReleaseEvent, github.PullRequestEvent) // Add as many as you want
@@ -26,7 +25,6 @@ func main() {
// HandleMultiple handles multiple GitHub events // HandleMultiple handles multiple GitHub events
func HandleMultiple(payload interface{}, header webhooks.Header) { func HandleMultiple(payload interface{}, header webhooks.Header) {
fmt.Println("Handling Payload..") fmt.Println("Handling Payload..")
switch payload.(type) { switch payload.(type) {
+79 -14
View File
@@ -5,10 +5,11 @@ import (
"crypto/sha1" "crypto/sha1"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"gopkg.in/go-playground/webhooks.v2" "gopkg.in/go-playground/webhooks.v3"
) )
// Webhook instance contains all methods needed to process events // Webhook instance contains all methods needed to process events
@@ -35,18 +36,30 @@ const (
DeploymentStatusEvent Event = "deployment_status" DeploymentStatusEvent Event = "deployment_status"
ForkEvent Event = "fork" ForkEvent Event = "fork"
GollumEvent Event = "gollum" GollumEvent Event = "gollum"
InstallationEvent Event = "installation"
IntegrationInstallationEvent Event = "integration_installation"
IssueCommentEvent Event = "issue_comment" IssueCommentEvent Event = "issue_comment"
IssuesEvent Event = "issues" IssuesEvent Event = "issues"
LabelEvent Event = "label"
MemberEvent Event = "member" MemberEvent Event = "member"
MembershipEvent Event = "membership" MembershipEvent Event = "membership"
MilestoneEvent Event = "milestone"
OrganizationEvent Event = "organization"
OrgBlockEvent Event = "org_block"
PageBuildEvent Event = "page_build" PageBuildEvent Event = "page_build"
PingEvent Event = "ping"
ProjectCardEvent Event = "project_card"
ProjectColumnEvent Event = "project_column"
ProjectEvent Event = "project"
PublicEvent Event = "public" PublicEvent Event = "public"
PullRequestReviewCommentEvent Event = "pull_request_review_comment"
PullRequestEvent Event = "pull_request" PullRequestEvent Event = "pull_request"
PullRequestReviewEvent Event = "pull_request_review"
PullRequestReviewCommentEvent Event = "pull_request_review_comment"
PushEvent Event = "push" PushEvent Event = "push"
RepositoryEvent Event = "repository"
ReleaseEvent Event = "release" ReleaseEvent Event = "release"
RepositoryEvent Event = "repository"
StatusEvent Event = "status" StatusEvent Event = "status"
TeamEvent Event = "team"
TeamAddEvent Event = "team_add" TeamAddEvent Event = "team_add"
WatchEvent Event = "watch" WatchEvent Event = "watch"
) )
@@ -87,36 +100,43 @@ func (hook Webhook) RegisterEvents(fn webhooks.ProcessPayloadFunc, events ...Eve
// ParsePayload parses and verifies the payload and fires off the mapped function, if it exists. // ParsePayload parses and verifies the payload and fires off the mapped function, if it exists.
func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) { func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
webhooks.DefaultLog.Info("Parsing Payload...")
event := r.Header.Get("X-GitHub-Event") event := r.Header.Get("X-GitHub-Event")
if len(event) == 0 { if len(event) == 0 {
webhooks.DefaultLog.Error("Missing X-GitHub-Event Header")
http.Error(w, "400 Bad Request - Missing X-GitHub-Event Header", http.StatusBadRequest) http.Error(w, "400 Bad Request - Missing X-GitHub-Event Header", http.StatusBadRequest)
return return
} }
webhooks.DefaultLog.Debug(fmt.Sprintf("X-GitHub-Event:%s", event))
gitHubEvent := Event(event) gitHubEvent := Event(event)
fn, ok := hook.eventFuncs[gitHubEvent] fn, ok := hook.eventFuncs[gitHubEvent]
// if no event registered // if no event registered
if !ok { if !ok {
webhooks.DefaultLog.Info(fmt.Sprintf("Webhook Event %s not registered, it is recommended to setup only events in github that will be registered in the webhook to avoid unnecessary traffic and reduce potential attack vectors.", event))
return return
} }
payload, err := ioutil.ReadAll(r.Body) payload, err := ioutil.ReadAll(r.Body)
if err != nil || len(payload) == 0 { if err != nil || len(payload) == 0 {
http.Error(w, "Error reading Body", http.StatusInternalServerError) webhooks.DefaultLog.Error("Issue reading Payload")
http.Error(w, "Issue reading Payload", http.StatusInternalServerError)
return return
} }
webhooks.DefaultLog.Debug(fmt.Sprintf("Payload:%s", string(payload)))
// If we have a Secret set, we should check the MAC // If we have a Secret set, we should check the MAC
if len(hook.secret) > 0 { if len(hook.secret) > 0 {
webhooks.DefaultLog.Info("Checking secret")
signature := r.Header.Get("X-Hub-Signature") signature := r.Header.Get("X-Hub-Signature")
if len(signature) == 0 { if len(signature) == 0 {
webhooks.DefaultLog.Error("Missing X-Hub-Signature required for HMAC verification")
http.Error(w, "403 Forbidden - Missing X-Hub-Signature required for HMAC verification", http.StatusForbidden) http.Error(w, "403 Forbidden - Missing X-Hub-Signature required for HMAC verification", http.StatusForbidden)
return return
} }
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Hub-Signature:%s", signature))
mac := hmac.New(sha1.New, []byte(hook.secret)) mac := hmac.New(sha1.New, []byte(hook.secret))
mac.Write(payload) mac.Write(payload)
@@ -124,6 +144,7 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
expectedMAC := hex.EncodeToString(mac.Sum(nil)) expectedMAC := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(signature[5:]), []byte(expectedMAC)) { if !hmac.Equal([]byte(signature[5:]), []byte(expectedMAC)) {
webhooks.DefaultLog.Error("HMAC verification failed")
http.Error(w, "403 Forbidden - HMAC verification failed", http.StatusForbidden) http.Error(w, "403 Forbidden - HMAC verification failed", http.StatusForbidden)
return return
} }
@@ -161,6 +182,10 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
var g GollumPayload var g GollumPayload
json.Unmarshal([]byte(payload), &g) json.Unmarshal([]byte(payload), &g)
hook.runProcessPayloadFunc(fn, g, hd) hook.runProcessPayloadFunc(fn, g, hd)
case InstallationEvent, IntegrationInstallationEvent:
var i InstallationPayload
json.Unmarshal([]byte(payload), &i)
hook.runProcessPayloadFunc(fn, i, hd)
case IssueCommentEvent: case IssueCommentEvent:
var i IssueCommentPayload var i IssueCommentPayload
json.Unmarshal([]byte(payload), &i) json.Unmarshal([]byte(payload), &i)
@@ -169,6 +194,10 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
var i IssuesPayload var i IssuesPayload
json.Unmarshal([]byte(payload), &i) json.Unmarshal([]byte(payload), &i)
hook.runProcessPayloadFunc(fn, i, hd) hook.runProcessPayloadFunc(fn, i, hd)
case LabelEvent:
var l LabelPayload
json.Unmarshal([]byte(payload), &l)
hook.runProcessPayloadFunc(fn, l, hd)
case MemberEvent: case MemberEvent:
var m MemberPayload var m MemberPayload
json.Unmarshal([]byte(payload), &m) json.Unmarshal([]byte(payload), &m)
@@ -177,38 +206,74 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
var m MembershipPayload var m MembershipPayload
json.Unmarshal([]byte(payload), &m) json.Unmarshal([]byte(payload), &m)
hook.runProcessPayloadFunc(fn, m, hd) hook.runProcessPayloadFunc(fn, m, hd)
case MilestoneEvent:
var m MilestonePayload
json.Unmarshal([]byte(payload), &m)
hook.runProcessPayloadFunc(fn, m, hd)
case OrganizationEvent:
var o OrganizationPayload
json.Unmarshal([]byte(payload), &o)
hook.runProcessPayloadFunc(fn, o, hd)
case OrgBlockEvent:
var o OrgBlockPayload
json.Unmarshal([]byte(payload), &o)
hook.runProcessPayloadFunc(fn, o, hd)
case PageBuildEvent: case PageBuildEvent:
var p PageBuildPayload var p PageBuildPayload
json.Unmarshal([]byte(payload), &p) json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd) hook.runProcessPayloadFunc(fn, p, hd)
case PingEvent:
var p PingPayload
json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd)
case ProjectCardEvent:
var p ProjectCardPayload
json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd)
case ProjectColumnEvent:
var p ProjectColumnPayload
json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd)
case ProjectEvent:
var p ProjectPayload
json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd)
case PublicEvent: case PublicEvent:
var p PublicPayload var p PublicPayload
json.Unmarshal([]byte(payload), &p) json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd) hook.runProcessPayloadFunc(fn, p, hd)
case PullRequestReviewCommentEvent:
var p PullRequestReviewCommentPayload
json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd)
case PullRequestEvent: case PullRequestEvent:
var p PullRequestPayload var p PullRequestPayload
json.Unmarshal([]byte(payload), &p) json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd) hook.runProcessPayloadFunc(fn, p, hd)
case PullRequestReviewEvent:
var p PullRequestReviewPayload
json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd)
case PullRequestReviewCommentEvent:
var p PullRequestReviewCommentPayload
json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd)
case PushEvent: case PushEvent:
var p PushPayload var p PushPayload
json.Unmarshal([]byte(payload), &p) json.Unmarshal([]byte(payload), &p)
hook.runProcessPayloadFunc(fn, p, hd) hook.runProcessPayloadFunc(fn, p, hd)
case RepositoryEvent:
var r RepositoryPayload
json.Unmarshal([]byte(payload), &r)
hook.runProcessPayloadFunc(fn, r, hd)
case ReleaseEvent: case ReleaseEvent:
var r ReleasePayload var r ReleasePayload
json.Unmarshal([]byte(payload), &r) json.Unmarshal([]byte(payload), &r)
hook.runProcessPayloadFunc(fn, r, hd) hook.runProcessPayloadFunc(fn, r, hd)
case RepositoryEvent:
var r RepositoryPayload
json.Unmarshal([]byte(payload), &r)
hook.runProcessPayloadFunc(fn, r, hd)
case StatusEvent: case StatusEvent:
var s StatusPayload var s StatusPayload
json.Unmarshal([]byte(payload), &s) json.Unmarshal([]byte(payload), &s)
hook.runProcessPayloadFunc(fn, s, hd) hook.runProcessPayloadFunc(fn, s, hd)
case TeamEvent:
var t TeamPayload
json.Unmarshal([]byte(payload), &t)
hook.runProcessPayloadFunc(fn, t, hd)
case TeamAddEvent: case TeamAddEvent:
var t TeamAddPayload var t TeamAddPayload
json.Unmarshal([]byte(payload), &t) json.Unmarshal([]byte(payload), &t)
+2394 -633
View File
File diff suppressed because it is too large Load Diff
+5044 -661
View File
File diff suppressed because it is too large Load Diff
+26 -13
View File
@@ -2,10 +2,11 @@ package gitlab
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"gopkg.in/go-playground/webhooks.v2" "gopkg.in/go-playground/webhooks.v3"
) )
// Webhook instance contains all methods needed to process events // Webhook instance contains all methods needed to process events
@@ -25,14 +26,15 @@ type Event string
// GitLab hook types // GitLab hook types
const ( const (
PushEvents Event = "Push Hook" PushEvents Event = "Push Hook"
TagEvents Event = "Tag Push Hook" TagEvents Event = "Tag Push Hook"
IssuesEvents Event = "Issue Hook" IssuesEvents Event = "Issue Hook"
CommentEvents Event = "Note Hook" ConfidentialIssuesEvents Event = "Confidential Issue Hook"
MergerRequestEvents Event = "Merge Request Hook" CommentEvents Event = "Note Hook"
WikiPageEvents Event = "Wiki Page Hook" MergeRequestEvents Event = "Merge Request Hook"
PipelineEvents Event = "Pipeline Hook" WikiPageEvents Event = "Wiki Page Hook"
BuildEvents Event = "Build Hook" PipelineEvents Event = "Pipeline Hook"
BuildEvents Event = "Build Hook"
) )
// New creates and returns a WebHook instance denoted by the Provider type // New creates and returns a WebHook instance denoted by the Provider type
@@ -59,33 +61,39 @@ func (hook Webhook) RegisterEvents(fn webhooks.ProcessPayloadFunc, events ...Eve
// ParsePayload parses and verifies the payload and fires off the mapped function, if it exists. // ParsePayload parses and verifies the payload and fires off the mapped function, if it exists.
func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) { func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
webhooks.DefaultLog.Info("Parsing Payload...")
event := r.Header.Get("X-Gitlab-Event") event := r.Header.Get("X-Gitlab-Event")
if len(event) == 0 { if len(event) == 0 {
webhooks.DefaultLog.Error("Missing X-Gitlab-Event Header")
http.Error(w, "400 Bad Request - Missing X-Gitlab-Event Header", http.StatusBadRequest) http.Error(w, "400 Bad Request - Missing X-Gitlab-Event Header", http.StatusBadRequest)
return return
} }
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Gitlab-Event:%s", event))
gitLabEvent := Event(event) gitLabEvent := Event(event)
fn, ok := hook.eventFuncs[gitLabEvent] fn, ok := hook.eventFuncs[gitLabEvent]
// if no event registered // if no event registered
if !ok { if !ok {
webhooks.DefaultLog.Info(fmt.Sprintf("Webhook Event %s not registered, it is recommended to setup only events in gitlab that will be registered in the webhook to avoid unnecessary traffic and reduce potential attack vectors.", event))
return return
} }
payload, err := ioutil.ReadAll(r.Body) payload, err := ioutil.ReadAll(r.Body)
if err != nil || len(payload) == 0 { if err != nil || len(payload) == 0 {
http.Error(w, "Error reading Body", http.StatusInternalServerError) webhooks.DefaultLog.Error("Issue reading Payload")
http.Error(w, "Error reading Payload", http.StatusInternalServerError)
return return
} }
webhooks.DefaultLog.Debug(fmt.Sprintf("Payload:%s", string(payload)))
// If we have a Secret set, we should check the MAC // If we have a Secret set, we should check the MAC
if len(hook.secret) > 0 { if len(hook.secret) > 0 {
webhooks.DefaultLog.Info("Checking secret")
signature := r.Header.Get("X-Gitlab-Token") signature := r.Header.Get("X-Gitlab-Token")
if signature != hook.secret { if signature != hook.secret {
webhooks.DefaultLog.Error(fmt.Sprintf("Invalid X-Gitlab-Token of '%s'", signature))
http.Error(w, "403 Forbidden - Token missmatch", http.StatusForbidden) http.Error(w, "403 Forbidden - Token missmatch", http.StatusForbidden)
return return
} }
@@ -105,6 +113,11 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
json.Unmarshal([]byte(payload), &te) json.Unmarshal([]byte(payload), &te)
hook.runProcessPayloadFunc(fn, te, hd) hook.runProcessPayloadFunc(fn, te, hd)
case ConfidentialIssuesEvents:
var cie ConfidentialIssueEventPayload
json.Unmarshal([]byte(payload), &cie)
hook.runProcessPayloadFunc(fn, cie, hd)
case IssuesEvents: case IssuesEvents:
var ie IssueEventPayload var ie IssueEventPayload
json.Unmarshal([]byte(payload), &ie) json.Unmarshal([]byte(payload), &ie)
@@ -115,7 +128,7 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
json.Unmarshal([]byte(payload), &ce) json.Unmarshal([]byte(payload), &ce)
hook.runProcessPayloadFunc(fn, ce, hd) hook.runProcessPayloadFunc(fn, ce, hd)
case MergerRequestEvents: case MergeRequestEvents:
var mre MergeRequestEventPayload var mre MergeRequestEventPayload
json.Unmarshal([]byte(payload), &mre) json.Unmarshal([]byte(payload), &mre)
hook.runProcessPayloadFunc(fn, mre, hd) hook.runProcessPayloadFunc(fn, mre, hd)
+222 -86
View File
@@ -9,7 +9,7 @@ import (
"time" "time"
. "gopkg.in/go-playground/assert.v1" . "gopkg.in/go-playground/assert.v1"
"gopkg.in/go-playground/webhooks.v2" "gopkg.in/go-playground/webhooks.v3"
) )
// NOTES: // NOTES:
@@ -24,7 +24,7 @@ import (
// //
const ( const (
port = 3009 port = 3011
path = "/webhooks" path = "/webhooks"
) )
@@ -43,14 +43,15 @@ func TestMain(m *testing.M) {
PushEvents, PushEvents,
TagEvents, TagEvents,
IssuesEvents, IssuesEvents,
ConfidentialIssuesEvents,
CommentEvents, CommentEvents,
MergerRequestEvents, MergeRequestEvents,
WikiPageEvents, WikiPageEvents,
PipelineEvents, PipelineEvents,
BuildEvents, BuildEvents,
) )
go webhooks.Run(hook, "127.0.0.1:"+strconv.Itoa(port), path) go webhooks.Run(hook, "127.0.0.1:"+strconv.Itoa(port), path)
time.Sleep(5000) time.Sleep(time.Millisecond * 500)
os.Exit(m.Run()) os.Exit(m.Run())
@@ -64,7 +65,7 @@ func TestProvider(t *testing.T) {
func TestBadNoEventHeader(t *testing.T) { func TestBadNoEventHeader(t *testing.T) {
payload := "{}" payload := "{}"
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
Equal(t, err, nil) Equal(t, err, nil)
@@ -81,7 +82,7 @@ func TestBadNoEventHeader(t *testing.T) {
func TestUnsubscribedEvent(t *testing.T) { func TestUnsubscribedEvent(t *testing.T) {
payload := "{}" payload := "{}"
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "noneexistant_event") req.Header.Set("X-Gitlab-Event", "noneexistant_event")
@@ -99,7 +100,7 @@ func TestUnsubscribedEvent(t *testing.T) {
func TestBadBody(t *testing.T) { func TestBadBody(t *testing.T) {
payload := "" payload := ""
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Note Hook") req.Header.Set("X-Gitlab-Event", "Note Hook")
@@ -117,7 +118,7 @@ func TestBadBody(t *testing.T) {
func TestTokenMissmatch(t *testing.T) { func TestTokenMissmatch(t *testing.T) {
payload := "{}" payload := "{}"
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Note Hook") req.Header.Set("X-Gitlab-Event", "Note Hook")
req.Header.Set("X-Gitlab-Token", "itsnotasampleToken!") req.Header.Set("X-Gitlab-Token", "itsnotasampleToken!")
@@ -203,7 +204,7 @@ func TestPushEvent(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Push Hook") req.Header.Set("X-Gitlab-Event", "Push Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
@@ -261,7 +262,7 @@ func TestTagEvent(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Tag Push Hook") req.Header.Set("X-Gitlab-Event", "Tag Push Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
@@ -333,7 +334,7 @@ func TestIssueEvent(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Issue Hook") req.Header.Set("X-Gitlab-Event", "Issue Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
@@ -349,6 +350,78 @@ func TestIssueEvent(t *testing.T) {
Equal(t, resp.StatusCode, http.StatusOK) Equal(t, resp.StatusCode, http.StatusOK)
} }
func TestConfidentialIssueEvent(t *testing.T) {
payload := `{
"object_kind": "issue",
"user": {
"name": "Administrator",
"username": "root",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"project":{
"name":"Gitlab Test",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/gitlabhq/gitlab-test",
"avatar_url":null,
"git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
"git_http_url":"http://example.com/gitlabhq/gitlab-test.git",
"namespace":"GitlabHQ",
"visibility_level":20,
"path_with_namespace":"gitlabhq/gitlab-test",
"default_branch":"master",
"homepage":"http://example.com/gitlabhq/gitlab-test",
"url":"http://example.com/gitlabhq/gitlab-test.git",
"ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
"http_url":"http://example.com/gitlabhq/gitlab-test.git"
},
"repository":{
"name": "Gitlab Test",
"url": "http://example.com/gitlabhq/gitlab-test.git",
"description": "Aut reprehenderit ut est.",
"homepage": "http://example.com/gitlabhq/gitlab-test"
},
"object_attributes": {
"id": 301,
"title": "New API: create/update/delete file",
"assignee_id": 51,
"author_id": 51,
"project_id": 14,
"created_at": "2013-12-03T17:15:43Z",
"updated_at": "2013-12-03T17:15:43Z",
"position": 0,
"branch_name": null,
"description": "Create new API for manipulations with repository",
"milestone_id": null,
"state": "opened",
"iid": 23,
"url": "http://example.com/diaspora/issues/23",
"action": "open"
},
"assignee": {
"name": "User1",
"username": "user1",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
}
}
`
req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Confidential Issue Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!")
Equal(t, err, nil)
client := &http.Client{}
resp, err := client.Do(req)
Equal(t, err, nil)
defer resp.Body.Close()
Equal(t, resp.StatusCode, http.StatusOK)
}
func TestCommentCommitEvent(t *testing.T) { func TestCommentCommitEvent(t *testing.T) {
payload := `{ payload := `{
@@ -419,7 +492,7 @@ func TestCommentCommitEvent(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Note Hook") req.Header.Set("X-Gitlab-Event", "Note Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
@@ -553,7 +626,7 @@ func TestCommentMergeRequestEvent(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Note Hook") req.Header.Set("X-Gitlab-Event", "Note Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
@@ -635,7 +708,7 @@ func TestCommentIssueEvent(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Note Hook") req.Header.Set("X-Gitlab-Event", "Note Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
@@ -715,7 +788,7 @@ func TestCommentSunippetEvent(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Note Hook") req.Header.Set("X-Gitlab-Event", "Note Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
@@ -734,85 +807,148 @@ func TestCommentSunippetEvent(t *testing.T) {
func TestMergeRequestEvent(t *testing.T) { func TestMergeRequestEvent(t *testing.T) {
payload := `{ payload := `{
"object_kind": "merge_request", "object_kind": "merge_request",
"user": { "user": {
"name": "Administrator", "name": "Administrator",
"username": "root", "username": "root",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"object_attributes": {
"id": 99,
"target_branch": "master",
"source_branch": "ms-viewport",
"source_project_id": 14,
"author_id": 51,
"assignee_id": 6,
"title": "MS-Viewport",
"created_at": "2013-12-03T17:23:34Z",
"updated_at": "2013-12-03T17:23:34Z",
"st_commits": null,
"st_diffs": null,
"milestone_id": null,
"state": "opened",
"merge_status": "unchecked",
"target_project_id": 14,
"iid": 1,
"description": "",
"source":{
"name":"Awesome Project",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/awesome_space/awesome_project",
"avatar_url":null,
"git_ssh_url":"git@example.com:awesome_space/awesome_project.git",
"git_http_url":"http://example.com/awesome_space/awesome_project.git",
"namespace":"Awesome Space",
"visibility_level":20,
"path_with_namespace":"awesome_space/awesome_project",
"default_branch":"master",
"homepage":"http://example.com/awesome_space/awesome_project",
"url":"http://example.com/awesome_space/awesome_project.git",
"ssh_url":"git@example.com:awesome_space/awesome_project.git",
"http_url":"http://example.com/awesome_space/awesome_project.git"
}, },
"target": { "project": {
"name":"Awesome Project", "id": 1,
"name":"Gitlab Test",
"description":"Aut reprehenderit ut est.", "description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/awesome_space/awesome_project", "web_url":"http://example.com/gitlabhq/gitlab-test",
"avatar_url":null, "avatar_url":null,
"git_ssh_url":"git@example.com:awesome_space/awesome_project.git", "git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
"git_http_url":"http://example.com/awesome_space/awesome_project.git", "git_http_url":"http://example.com/gitlabhq/gitlab-test.git",
"namespace":"Awesome Space", "namespace":"GitlabHQ",
"visibility_level":20, "visibility_level":20,
"path_with_namespace":"awesome_space/awesome_project", "path_with_namespace":"gitlabhq/gitlab-test",
"default_branch":"master", "default_branch":"master",
"homepage":"http://example.com/awesome_space/awesome_project", "homepage":"http://example.com/gitlabhq/gitlab-test",
"url":"http://example.com/awesome_space/awesome_project.git", "url":"http://example.com/gitlabhq/gitlab-test.git",
"ssh_url":"git@example.com:awesome_space/awesome_project.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
"http_url":"http://example.com/awesome_space/awesome_project.git" "http_url":"http://example.com/gitlabhq/gitlab-test.git"
}, },
"last_commit": { "repository": {
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "name": "Gitlab Test",
"message": "fixed readme", "url": "http://example.com/gitlabhq/gitlab-test.git",
"timestamp": "2012-01-03T23:36:29+02:00", "description": "Aut reprehenderit ut est.",
"url": "http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "homepage": "http://example.com/gitlabhq/gitlab-test"
"author": { },
"name": "GitLab dev user", "object_attributes": {
"email": "gitlabdev@dv6700.(none)" "id": 99,
"target_branch": "master",
"source_branch": "ms-viewport",
"source_project_id": 14,
"author_id": 51,
"assignee_id": 6,
"title": "MS-Viewport",
"created_at": "2013-12-03T17:23:34Z",
"updated_at": "2013-12-03T17:23:34Z",
"milestone_id": null,
"state": "opened",
"merge_status": "unchecked",
"target_project_id": 14,
"iid": 1,
"description": "",
"source": {
"name":"Awesome Project",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/awesome_space/awesome_project",
"avatar_url":null,
"git_ssh_url":"git@example.com:awesome_space/awesome_project.git",
"git_http_url":"http://example.com/awesome_space/awesome_project.git",
"namespace":"Awesome Space",
"visibility_level":20,
"path_with_namespace":"awesome_space/awesome_project",
"default_branch":"master",
"homepage":"http://example.com/awesome_space/awesome_project",
"url":"http://example.com/awesome_space/awesome_project.git",
"ssh_url":"git@example.com:awesome_space/awesome_project.git",
"http_url":"http://example.com/awesome_space/awesome_project.git"
},
"target": {
"name":"Awesome Project",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/awesome_space/awesome_project",
"avatar_url":null,
"git_ssh_url":"git@example.com:awesome_space/awesome_project.git",
"git_http_url":"http://example.com/awesome_space/awesome_project.git",
"namespace":"Awesome Space",
"visibility_level":20,
"path_with_namespace":"awesome_space/awesome_project",
"default_branch":"master",
"homepage":"http://example.com/awesome_space/awesome_project",
"url":"http://example.com/awesome_space/awesome_project.git",
"ssh_url":"git@example.com:awesome_space/awesome_project.git",
"http_url":"http://example.com/awesome_space/awesome_project.git"
},
"last_commit": {
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"message": "fixed readme",
"timestamp": "2012-01-03T23:36:29+02:00",
"url": "http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"author": {
"name": "GitLab dev user",
"email": "gitlabdev@dv6700.(none)"
}
},
"work_in_progress": false,
"url": "http://example.com/diaspora/merge_requests/1",
"action": "open",
"assignee": {
"name": "User1",
"username": "user1",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
} }
}, },
"work_in_progress": false, "labels": [{
"url": "http://example.com/diaspora/merge_requests/1", "id": 206,
"action": "open", "title": "API",
"assignee": { "color": "#ffffff",
"name": "User1", "project_id": 14,
"username": "user1", "created_at": "2013-12-03T17:15:43Z",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" "updated_at": "2013-12-03T17:15:43Z",
"template": false,
"description": "API related issues",
"type": "ProjectLabel",
"group_id": 41
}],
"changes": {
"updated_by_id": [null, 1],
"updated_at": ["2017-09-15 16:50:55 UTC", "2017-09-15 16:52:00 UTC"],
"labels": {
"previous": [{
"id": 206,
"title": "API",
"color": "#ffffff",
"project_id": 14,
"created_at": "2013-12-03T17:15:43Z",
"updated_at": "2013-12-03T17:15:43Z",
"template": false,
"description": "API related issues",
"type": "ProjectLabel",
"group_id": 41
}],
"current": [{
"id": 205,
"title": "Platform",
"color": "#123123",
"project_id": 14,
"created_at": "2013-12-03T17:15:43Z",
"updated_at": "2013-12-03T17:15:43Z",
"template": false,
"description": "Platform related issues",
"type": "ProjectLabel",
"group_id": 41
}]
}
} }
} }
}
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Merge Request Hook") req.Header.Set("X-Gitlab-Event", "Merge Request Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
@@ -872,7 +1008,7 @@ func TestWikipageEvent(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Wiki Page Hook") req.Header.Set("X-Gitlab-Event", "Wiki Page Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
@@ -1045,7 +1181,7 @@ func TestPipelineEvent(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Pipeline Hook") req.Header.Set("X-Gitlab-Event", "Pipeline Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
@@ -1107,7 +1243,7 @@ func TestBuildEvent(t *testing.T) {
} }
` `
req, err := http.NewRequest("POST", "http://127.0.0.1:3009/webhooks", bytes.NewBuffer([]byte(payload))) req, err := http.NewRequest("POST", "http://127.0.0.1:3011/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitlab-Event", "Build Hook") req.Header.Set("X-Gitlab-Event", "Build Hook")
req.Header.Set("X-Gitlab-Token", "sampleToken!") req.Header.Set("X-Gitlab-Token", "sampleToken!")
+100 -64
View File
@@ -38,6 +38,14 @@ type IssueEventPayload struct {
Repository Repository `json:"repository"` Repository Repository `json:"repository"`
ObjectAttributes ObjectAttributes `json:"object_attributes"` ObjectAttributes ObjectAttributes `json:"object_attributes"`
Assignee Assignee `json:"assignee"` Assignee Assignee `json:"assignee"`
Changes Changes `json:"changes"`
}
// ConfidentialIssueEventPayload contains the information for GitLab's confidential issue event
type ConfidentialIssueEventPayload struct {
// The data for confidential issues is currently the same as normal issues,
// so we can just embed the normal issue payload type here.
IssueEventPayload
} }
// MergeRequestEventPayload contains the information for GitLab's merge request event // MergeRequestEventPayload contains the information for GitLab's merge request event
@@ -45,6 +53,9 @@ type MergeRequestEventPayload struct {
ObjectKind string `json:"object_kind"` ObjectKind string `json:"object_kind"`
User User `json:"user"` User User `json:"user"`
ObjectAttributes ObjectAttributes `json:"object_attributes"` ObjectAttributes ObjectAttributes `json:"object_attributes"`
Changes Changes `json:"changes"`
Project Project `json:"project"`
Repository Repository `json:"repository"`
} }
// PushEventPayload contains the information for GitLab's push event // PushEventPayload contains the information for GitLab's push event
@@ -54,15 +65,15 @@ type PushEventPayload struct {
After string `json:"after"` After string `json:"after"`
Ref string `json:"ref"` Ref string `json:"ref"`
CheckoutSHA string `json:"checkout_sha"` CheckoutSHA string `json:"checkout_sha"`
UserID int `json:"user_id"` UserID int64 `json:"user_id"`
UserName string `json:"user_name"` UserName string `json:"user_name"`
UserEmail string `json:"user_email"` UserEmail string `json:"user_email"`
UserAvatar string `json:"user_avatar"` UserAvatar string `json:"user_avatar"`
ProjectID int `json:"project_id"` ProjectID int64 `json:"project_id"`
Project Project `json:"Project"` Project Project `json:"Project"`
Repository Repository `json:"repository"` Repository Repository `json:"repository"`
Commits []Commit `json:"commits"` Commits []Commit `json:"commits"`
TotalCommitsCount int `json:"total_commits_count"` TotalCommitsCount int64 `json:"total_commits_count"`
} }
// TagEventPayload contains the information for GitLab's tag push event // TagEventPayload contains the information for GitLab's tag push event
@@ -72,14 +83,14 @@ type TagEventPayload struct {
After string `json:"after"` After string `json:"after"`
Ref string `json:"ref"` Ref string `json:"ref"`
CheckoutSHA string `json:"checkout_sha"` CheckoutSHA string `json:"checkout_sha"`
UserID int `json:"user_id"` UserID int64 `json:"user_id"`
UserName string `json:"user_name"` UserName string `json:"user_name"`
UserAvatar string `json:"user_avatar"` UserAvatar string `json:"user_avatar"`
ProjectID int `json:"project_id"` ProjectID int64 `json:"project_id"`
Project Project `json:"Project"` Project Project `json:"Project"`
Repository Repository `json:"repository"` Repository Repository `json:"repository"`
Commits []Commit `json:"commits"` Commits []Commit `json:"commits"`
TotalCommitsCount int `json:"total_commits_count"` TotalCommitsCount int64 `json:"total_commits_count"`
} }
// WikiPageEventPayload contains the information for GitLab's wiki created/updated event // WikiPageEventPayload contains the information for GitLab's wiki created/updated event
@@ -105,7 +116,7 @@ type PipelineEventPayload struct {
type CommentEventPayload struct { type CommentEventPayload struct {
ObjectKind string `json:"object_kind"` ObjectKind string `json:"object_kind"`
User User `json:"user"` User User `json:"user"`
ProjectID int `json:"project_id"` ProjectID int64 `json:"project_id"`
Project Project `json:"project"` Project Project `json:"project"`
Repository Repository `json:"repository"` Repository Repository `json:"repository"`
ObjectAttributes ObjectAttributes `json:"object_attributes"` ObjectAttributes ObjectAttributes `json:"object_attributes"`
@@ -122,41 +133,41 @@ type BuildEventPayload struct {
Tag bool `json:"tag"` Tag bool `json:"tag"`
BeforeSHA string `json:"before_sha"` BeforeSHA string `json:"before_sha"`
SHA string `json:"sha"` SHA string `json:"sha"`
BuildID int `json:"build_id"` BuildID int64 `json:"build_id"`
BuildName string `json:"build_name"` BuildName string `json:"build_name"`
BuildStage string `json:"build_stage"` BuildStage string `json:"build_stage"`
BuildStatus string `json:"build_status"` BuildStatus string `json:"build_status"`
BuildStartedAt customTime `json:"build_started_at"` BuildStartedAt customTime `json:"build_started_at"`
BuildFinishedAt customTime `json:"build_finished_at"` BuildFinishedAt customTime `json:"build_finished_at"`
BuildDuration int `json:"build_duration"` BuildDuration int64 `json:"build_duration"`
BuildAllowFailure bool `json:"build_allow_failure"` BuildAllowFailure bool `json:"build_allow_failure"`
ProjectID int `json:"project_id"` ProjectID int64 `json:"project_id"`
ProjectName string `json:"project_name"` ProjectName string `json:"project_name"`
User User `json:"user"` User User `json:"user"`
Commit BuildCommit `json:"commit"` Commit BuildCommit `json:"commit"`
Repository Repository `json:"repository"` Repository Repository `json:"repository"`
} }
// Issue contais all of the GitLab issue information // Issue contains all of the GitLab issue information
type Issue struct { type Issue struct {
ID int `json:"id"` ID int64 `json:"id"`
Title string `json:"title"` Title string `json:"title"`
AssigneeID int `json:"assignee_id"` AssigneeID int64 `json:"assignee_id"`
AuthorID int `json:"author_id"` AuthorID int64 `json:"author_id"`
ProjectID int `json:"project_id"` ProjectID int64 `json:"project_id"`
CreatedAt customTime `json:"created_at"` CreatedAt customTime `json:"created_at"`
UpdatedAt customTime `json:"updated_at"` UpdatedAt customTime `json:"updated_at"`
Position int `json:"position"` Position int64 `json:"position"`
BranchName string `json:"branch_name"` BranchName string `json:"branch_name"`
Description string `json:"description"` Description string `json:"description"`
MilestoneID int `json:"milestone_id"` MilestoneID int64 `json:"milestone_id"`
State string `json:"state"` State string `json:"state"`
IID int `json:"iid"` IID int64 `json:"iid"`
} }
// Build contais all of the GitLab build information // Build contains all of the GitLab build information
type Build struct { type Build struct {
ID int `json:"id"` ID int64 `json:"id"`
Stage string `json:"stage"` Stage string `json:"stage"`
Name string `json:"name"` Name string `json:"name"`
Status string `json:"status"` Status string `json:"status"`
@@ -170,13 +181,13 @@ type Build struct {
ArtifactsFile ArtifactsFile `json:"artifactsfile"` ArtifactsFile ArtifactsFile `json:"artifactsfile"`
} }
// ArtifactsFile contais all of the GitLab artifact information // ArtifactsFile contains all of the GitLab artifact information
type ArtifactsFile struct { type ArtifactsFile struct {
Filename string `json:"filename"` Filename string `json:"filename"`
Size string `json:"size"` Size string `json:"size"`
} }
// Wiki contais all of the GitLab wiki information // Wiki contains all of the GitLab wiki information
type Wiki struct { type Wiki struct {
WebURL string `json:"web_url"` WebURL string `json:"web_url"`
GitSSHURL string `json:"git_ssh_url"` GitSSHURL string `json:"git_ssh_url"`
@@ -185,7 +196,7 @@ type Wiki struct {
DefaultBranch string `json:"default_branch"` DefaultBranch string `json:"default_branch"`
} }
// Commit contais all of the GitLab commit information // Commit contains all of the GitLab commit information
type Commit struct { type Commit struct {
ID string `json:"id"` ID string `json:"id"`
Message string `json:"message"` Message string `json:"message"`
@@ -197,42 +208,42 @@ type Commit struct {
Removed []string `json:"removed"` Removed []string `json:"removed"`
} }
// BuildCommit contais all of the GitLab build commit information // BuildCommit contains all of the GitLab build commit information
type BuildCommit struct { type BuildCommit struct {
ID int `json:"id"` ID int64 `json:"id"`
SHA string `json:"sha"` SHA string `json:"sha"`
Message string `json:"message"` Message string `json:"message"`
AuthorName string `json:"auuthor_name"` AuthorName string `json:"auuthor_name"`
AuthorEmail string `json:"author_email"` AuthorEmail string `json:"author_email"`
Status string `json:"status"` Status string `json:"status"`
Duration int `json:"duration"` Duration int64 `json:"duration"`
StartedAt customTime `json:"started_at"` StartedAt customTime `json:"started_at"`
FinishedAt customTime `json:"finished_at"` FinishedAt customTime `json:"finished_at"`
} }
// Snippet contais all of the GitLab snippet information // Snippet contains all of the GitLab snippet information
type Snippet struct { type Snippet struct {
ID int `json:"id"` ID int64 `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Content string `json:"content"` Content string `json:"content"`
AuthorID int `json:"author_id"` AuthorID int64 `json:"author_id"`
ProjectID int `json:"project_id"` ProjectID int64 `json:"project_id"`
CreatedAt customTime `json:"created_at"` CreatedAt customTime `json:"created_at"`
UpdatedAt customTime `json:"updated_at"` UpdatedAt customTime `json:"updated_at"`
FileName string `json:"file_name"` FileName string `json:"file_name"`
ExpiresAt customTime `json:"expires_at"` ExpiresAt customTime `json:"expires_at"`
Type string `json:"type"` Type string `json:"type"`
VisibilityLevel int `json:"visibility_level"` VisibilityLevel int64 `json:"visibility_level"`
} }
// User contais all of the GitLab user information // User contains all of the GitLab user information
type User struct { type User struct {
Name string `json:"name"` Name string `json:"name"`
UserName string `json:"username"` UserName string `json:"username"`
AvatarURL string `json:"avatar_url"` AvatarURL string `json:"avatar_url"`
} }
// Project contais all of the GitLab project information // Project contains all of the GitLab project information
type Project struct { type Project struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
@@ -241,7 +252,7 @@ type Project struct {
GitSSSHURL string `json:"git_ssh_url"` GitSSSHURL string `json:"git_ssh_url"`
GitHTTPURL string `json:"git_http_url"` GitHTTPURL string `json:"git_http_url"`
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
VisibilityLevel int `json:"visibility_level"` VisibilityLevel int64 `json:"visibility_level"`
PathWithNamespace string `json:"path_with_namespace"` PathWithNamespace string `json:"path_with_namespace"`
DefaultBranch string `json:"default_branch"` DefaultBranch string `json:"default_branch"`
Homepage string `json:"homepage"` Homepage string `json:"homepage"`
@@ -250,7 +261,7 @@ type Project struct {
HTTPURL string `json:"http_url"` HTTPURL string `json:"http_url"`
} }
// Repository contais all of the GitLab repository information // Repository contains all of the GitLab repository information
type Repository struct { type Repository struct {
Name string `json:"name"` Name string `json:"name"`
URL string `json:"url"` URL string `json:"url"`
@@ -258,27 +269,27 @@ type Repository struct {
Homepage string `json:"homepage"` Homepage string `json:"homepage"`
} }
// ObjectAttributes contais all of the GitLab object attributes information // ObjectAttributes contains all of the GitLab object attributes information
type ObjectAttributes struct { type ObjectAttributes struct {
ID int `json:"id"` ID int64 `json:"id"`
Title string `json:"title"` Title string `json:"title"`
AssigneeID int `json:"assignee_id"` AssigneeID int64 `json:"assignee_id"`
AuthorID int `json:"author_id"` AuthorID int64 `json:"author_id"`
ProjectID int `json:"project_id"` ProjectID int64 `json:"project_id"`
CreatedAt customTime `json:"created_at"` CreatedAt customTime `json:"created_at"`
UpdatedAt customTime `json:"updated_at"` UpdatedAt customTime `json:"updated_at"`
Position int `json:"position"` Position int64 `json:"position"`
BranchName string `json:"branch_name"` BranchName string `json:"branch_name"`
Description string `json:"description"` Description string `json:"description"`
MilestoneID int `json:"milestone_id"` MilestoneID int64 `json:"milestone_id"`
State string `json:"state"` State string `json:"state"`
IID int `json:"iid"` IID int64 `json:"iid"`
URL string `json:"url"` URL string `json:"url"`
Action string `json:"action"` Action string `json:"action"`
TargetBranch string `json:"target_branch"` TargetBranch string `json:"target_branch"`
SourceBranch string `json:"source_branch"` SourceBranch string `json:"source_branch"`
SourceProjectID int `json:"source_project_id"` SourceProjectID int64 `json:"source_project_id"`
TargetProjectID int `json:"target_project_id"` TargetProjectID int64 `json:"target_project_id"`
StCommits string `json:"st_commits"` StCommits string `json:"st_commits"`
MergeStatus string `json:"merge_status"` MergeStatus string `json:"merge_status"`
Content string `json:"content"` Content string `json:"content"`
@@ -291,13 +302,13 @@ type ObjectAttributes struct {
BeforeSHA string `json:"before_sha"` BeforeSHA string `json:"before_sha"`
Status string `json:"status"` Status string `json:"status"`
Stages []string `json:"stages"` Stages []string `json:"stages"`
Duration int `json:"duration"` Duration int64 `json:"duration"`
Note string `json:"note"` Note string `json:"note"`
NotebookType string `json:"noteable_type"` NotebookType string `json:"noteable_type"`
At customTime `json:"attachment"` At customTime `json:"attachment"`
LineCode string `json:"line_code"` LineCode string `json:"line_code"`
CommitID string `json:"commit_id"` CommitID string `json:"commit_id"`
NoteableID int `json:"noteable_id"` NoteableID int64 `json:"noteable_id"`
System bool `json:"system"` System bool `json:"system"`
WorkInProgress bool `json:"work_in_progress"` WorkInProgress bool `json:"work_in_progress"`
StDiffs []StDiff `json:"st_diffs"` StDiffs []StDiff `json:"st_diffs"`
@@ -307,24 +318,24 @@ type ObjectAttributes struct {
Assignee Assignee `json:"assignee"` Assignee Assignee `json:"assignee"`
} }
// MergeRequest contais all of the GitLab merge request information // MergeRequest contains all of the GitLab merge request information
type MergeRequest struct { type MergeRequest struct {
ID int `json:"id"` ID int64 `json:"id"`
TargetBranch string `json:"target_branch"` TargetBranch string `json:"target_branch"`
SourceBranch string `json:"source_branch"` SourceBranch string `json:"source_branch"`
SourceProjectID string `json:"source_project_id"` SourceProjectID int64 `json:"source_project_id"`
AssigneeID int `json:"assignee_id"` AssigneeID int64 `json:"assignee_id"`
AuthorID int `json:"author_id"` AuthorID int64 `json:"author_id"`
Title string `json:"title"` Title string `json:"title"`
CreatedAt customTime `json:"created_at"` CreatedAt customTime `json:"created_at"`
UpdatedAt customTime `json:"updated_at"` UpdatedAt customTime `json:"updated_at"`
MilestoneID int `json:"milestone_id"` MilestoneID int64 `json:"milestone_id"`
State string `json:"state"` State string `json:"state"`
MergeStatus string `json:"merge_status"` MergeStatus string `json:"merge_status"`
TargetProjectID int `json:"target_project_id"` TargetProjectID int64 `json:"target_project_id"`
IID int `json:"iid"` IID int64 `json:"iid"`
Description string `json:"description"` Description string `json:"description"`
Position int `json:"position"` Position int64 `json:"position"`
LockedAt customTime `json:"locked_at"` LockedAt customTime `json:"locked_at"`
Source Source `json:"source"` Source Source `json:"source"`
Target Target `json:"target"` Target Target `json:"target"`
@@ -333,14 +344,14 @@ type MergeRequest struct {
Assignee Assignee `json:"assignee"` Assignee Assignee `json:"assignee"`
} }
// Assignee contais all of the GitLab assignee information // Assignee contains all of the GitLab assignee information
type Assignee struct { type Assignee struct {
Name string `json:"name"` Name string `json:"name"`
Username string `json:"username"` Username string `json:"username"`
AvatarURL string `json:"avatar_url"` AvatarURL string `json:"avatar_url"`
} }
// StDiff contais all of the GitLab diff information // StDiff contains all of the GitLab diff information
type StDiff struct { type StDiff struct {
Diff string `json:"diff"` Diff string `json:"diff"`
NewPath string `json:"new_path"` NewPath string `json:"new_path"`
@@ -352,7 +363,7 @@ type StDiff struct {
DeletedFile bool `json:"deleted_file"` DeletedFile bool `json:"deleted_file"`
} }
// Source contais all of the GitLab source information // Source contains all of the GitLab source information
type Source struct { type Source struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
@@ -361,7 +372,7 @@ type Source struct {
GitSSHURL string `json:"git_ssh_url"` GitSSHURL string `json:"git_ssh_url"`
GitHTTPURL string `json:"git_http_url"` GitHTTPURL string `json:"git_http_url"`
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
VisibilityLevel int `json:"visibility_level"` VisibilityLevel int64 `json:"visibility_level"`
PathWithNamespace string `json:"path_with_namespace"` PathWithNamespace string `json:"path_with_namespace"`
DefaultBranch string `json:"default_branch"` DefaultBranch string `json:"default_branch"`
Homepage string `json:"homepage"` Homepage string `json:"homepage"`
@@ -370,7 +381,7 @@ type Source struct {
HTTPURL string `json:"http_url"` HTTPURL string `json:"http_url"`
} }
// Target contais all of the GitLab target information // Target contains all of the GitLab target information
type Target struct { type Target struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
@@ -379,7 +390,7 @@ type Target struct {
GitSSHURL string `json:"git_ssh_url"` GitSSHURL string `json:"git_ssh_url"`
GitHTTPURL string `json:"git_http_url"` GitHTTPURL string `json:"git_http_url"`
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
VisibilityLevel int `json:"visibility_level"` VisibilityLevel int64 `json:"visibility_level"`
PathWithNamespace string `json:"path_with_namespace"` PathWithNamespace string `json:"path_with_namespace"`
DefaultBranch string `json:"default_branch"` DefaultBranch string `json:"default_branch"`
Homepage string `json:"homepage"` Homepage string `json:"homepage"`
@@ -388,7 +399,7 @@ type Target struct {
HTTPURL string `json:"http_url"` HTTPURL string `json:"http_url"`
} }
// LastCommit contais all of the GitLab last commit information // LastCommit contains all of the GitLab last commit information
type LastCommit struct { type LastCommit struct {
ID string `json:"id"` ID string `json:"id"`
Message string `json:"message"` Message string `json:"message"`
@@ -397,8 +408,33 @@ type LastCommit struct {
Author Author `json:"author"` Author Author `json:"author"`
} }
// Author contais all of the GitLab author information // Author contains all of the GitLab author information
type Author struct { type Author struct {
Name string `json:"name"` Name string `json:"name"`
Email string `json:"email"` Email string `json:"email"`
} }
// Changes contains all changes associated with a GitLab issue or MR
type Changes struct {
LabelChanges LabelChanges `json:"labels"`
}
// LabelChanges contains changes in labels assocatiated with a GitLab issue or MR
type LabelChanges struct {
Previous []Label `json:"previous"`
Current []Label `json:"current"`
}
// Label contains all of the GitLab label information
type Label struct {
Id int64 `json:"id"`
Title string `json:"title"`
Color string `json:"color"`
ProjectId int64 `json:"project_id"`
CreatedAt customTime `json:"created_at"`
UpdatedAt customTime `json:"updated_at"`
Template bool `json:"template"`
Description string `json:"description"`
Type string `json:"type"`
GroupId int64 `json:"group_id"`
}
+167
View File
@@ -0,0 +1,167 @@
package gogs
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
client "github.com/gogits/go-gogs-client"
"gopkg.in/go-playground/webhooks.v3"
)
// Webhook instance contains all methods needed to process events
type Webhook struct {
provider webhooks.Provider
secret string
eventFuncs map[Event]webhooks.ProcessPayloadFunc
}
// Config defines the configuration to create a new Gogs Webhook instance
type Config struct {
Secret string
}
// Event defines a Gogs hook event type
type Event string
// Gogs hook types
const (
CreateEvent Event = "create"
DeleteEvent Event = "delete"
ForkEvent Event = "fork"
PushEvent Event = "push"
IssuesEvent Event = "issues"
IssueCommentEvent Event = "issue_comment"
PullRequestEvent Event = "pull_request"
ReleaseEvent Event = "release"
)
// New creates and returns a WebHook instance denoted by the Provider type
func New(config *Config) *Webhook {
return &Webhook{
provider: webhooks.Gogs,
secret: config.Secret,
eventFuncs: map[Event]webhooks.ProcessPayloadFunc{},
}
}
// Provider returns the current hooks provider ID
func (hook Webhook) Provider() webhooks.Provider {
return hook.provider
}
// RegisterEvents registers the function to call when the specified event(s) are encountered
func (hook Webhook) RegisterEvents(fn webhooks.ProcessPayloadFunc, events ...Event) {
for _, event := range events {
hook.eventFuncs[event] = fn
}
}
// ParsePayload parses and verifies the payload and fires off the mapped function, if it exists.
func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
webhooks.DefaultLog.Info("Parsing Payload...")
event := r.Header.Get("X-Gogs-Event")
if len(event) == 0 {
webhooks.DefaultLog.Error("Missing X-Gogs-Event Header")
http.Error(w, "400 Bad Request - Missing X-Gogs-Event Header", http.StatusBadRequest)
return
}
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Gogs-Event:%s", event))
gogsEvent := Event(event)
fn, ok := hook.eventFuncs[gogsEvent]
// if no event registered
if !ok {
webhooks.DefaultLog.Info(fmt.Sprintf("Webhook Event %s not registered, it is recommended to setup only events in gogs that will be registered in the webhook to avoid unnecessary traffic and reduce potential attack vectors.", event))
return
}
payload, err := ioutil.ReadAll(r.Body)
if err != nil || len(payload) == 0 {
webhooks.DefaultLog.Error("Issue reading Payload")
http.Error(w, "Issue reading Payload", http.StatusInternalServerError)
return
}
webhooks.DefaultLog.Debug(fmt.Sprintf("Payload:%s", string(payload)))
// If we have a Secret set, we should check the MAC
if len(hook.secret) > 0 {
webhooks.DefaultLog.Info("Checking secret")
signature := r.Header.Get("X-Gogs-Signature")
if len(signature) == 0 {
webhooks.DefaultLog.Error("Missing X-Gogs-Signature required for HMAC verification")
http.Error(w, "403 Forbidden - Missing X-Gogs-Signature required for HMAC verification", http.StatusForbidden)
return
}
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Gogs-Signature:%s", signature))
mac := hmac.New(sha256.New, []byte(hook.secret))
mac.Write(payload)
expectedMAC := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(signature), []byte(expectedMAC)) {
webhooks.DefaultLog.Debug(string(payload))
http.Error(w, "403 Forbidden - HMAC verification failed", http.StatusForbidden)
return
}
}
// Make headers available to ProcessPayloadFunc as a webhooks type
hd := webhooks.Header(r.Header)
switch gogsEvent {
case CreateEvent:
var pe client.CreatePayload
json.Unmarshal([]byte(payload), &pe)
hook.runProcessPayloadFunc(fn, pe, hd)
case ReleaseEvent:
var re client.ReleasePayload
json.Unmarshal([]byte(payload), &re)
hook.runProcessPayloadFunc(fn, re, hd)
case PushEvent:
var pe client.PushPayload
json.Unmarshal([]byte(payload), &pe)
hook.runProcessPayloadFunc(fn, pe, hd)
case DeleteEvent:
var de client.DeletePayload
json.Unmarshal([]byte(payload), &de)
hook.runProcessPayloadFunc(fn, de, hd)
case ForkEvent:
var fe client.ForkPayload
json.Unmarshal([]byte(payload), &fe)
hook.runProcessPayloadFunc(fn, fe, hd)
case IssuesEvent:
var ie client.IssuesPayload
json.Unmarshal([]byte(payload), &ie)
hook.runProcessPayloadFunc(fn, ie, hd)
case IssueCommentEvent:
var ice client.IssueCommentPayload
json.Unmarshal([]byte(payload), &ice)
hook.runProcessPayloadFunc(fn, ice, hd)
case PullRequestEvent:
var pre client.PullRequestPayload
json.Unmarshal([]byte(payload), &pre)
hook.runProcessPayloadFunc(fn, pre, hd)
}
}
func (hook Webhook) runProcessPayloadFunc(fn webhooks.ProcessPayloadFunc, results interface{}, header webhooks.Header) {
go func(fn webhooks.ProcessPayloadFunc, results interface{}, header webhooks.Header) {
fn(results, header)
}(fn, results, header)
}
+44
View File
@@ -0,0 +1,44 @@
package webhooks
import "log"
// DefaultLog contains the default logger for webhooks, and prints only info and error messages by default
// for debugs override DefaultLog or see NewLogger for creating one without debugs.
var DefaultLog Logger = new(logger)
// Logger allows for customizable logging
type Logger interface {
// Info prints basic information.
Info(string)
// Error prints error information.
Error(string)
// Debug prints information usefull for debugging.
Debug(string)
}
// NewLogger returns a new logger for use.
func NewLogger(debug bool) Logger {
return &logger{PrintDebugs: debug}
}
type logger struct {
PrintDebugs bool
}
// Info prints basic information.
func (l *logger) Info(msg string) {
log.Println("INFO:", msg)
}
// v prints error information.
func (l *logger) Error(msg string) {
log.Println("ERROR:", msg)
}
// Debug prints information usefull for debugging.
func (l *logger) Debug(msg string) {
if !l.PrintDebugs {
return
}
log.Println("DEBUG:", msg)
}
+40 -16
View File
@@ -1,6 +1,9 @@
package webhooks package webhooks
import "net/http" import (
"fmt"
"net/http"
)
// Header provides http.Header to minimize imports // Header provides http.Header to minimize imports
type Header http.Header type Header http.Header
@@ -16,6 +19,8 @@ func (p Provider) String() string {
return "Bitbucket" return "Bitbucket"
case GitLab: case GitLab:
return "GitLab" return "GitLab"
case Gogs:
return "Gogs"
default: default:
return "Unknown" return "Unknown"
} }
@@ -26,31 +31,41 @@ const (
GitHub Provider = iota GitHub Provider = iota
Bitbucket Bitbucket
GitLab GitLab
Gogs
) )
// Webhook interface defines a webhook to recieve events // Webhook interface defines a webhook to receive events
type Webhook interface { type Webhook interface {
Provider() Provider Provider() Provider
ParsePayload(w http.ResponseWriter, r *http.Request) ParsePayload(w http.ResponseWriter, r *http.Request)
} }
type server struct { type server struct {
hook Webhook hook Webhook
path string path string
includePathCheck bool
} }
// ProcessPayloadFunc is a common function for payload return values // ProcessPayloadFunc is a common function for payload return values
type ProcessPayloadFunc func(payload interface{}, header Header) type ProcessPayloadFunc func(payload interface{}, header Header)
// Handler returns the webhook http.Handler for use in your own Mux implementation
func Handler(hook Webhook) http.Handler {
return &server{
hook: hook,
}
}
// Run runs a server // Run runs a server
func Run(hook Webhook, addr string, path string) error { func Run(hook Webhook, addr string, path string) error {
srv := &server{ srv := &server{
hook: hook, hook: hook,
path: path, path: path,
includePathCheck: true,
} }
s := &http.Server{Addr: addr, Handler: srv} s := &http.Server{Addr: addr, Handler: srv}
DefaultLog.Info(fmt.Sprintf("Listening on addr: %s path: %s", addr, path))
return s.ListenAndServe() return s.ListenAndServe()
} }
@@ -58,12 +73,13 @@ func Run(hook Webhook, addr string, path string) error {
func RunServer(s *http.Server, hook Webhook, path string) error { func RunServer(s *http.Server, hook Webhook, path string) error {
srv := &server{ srv := &server{
hook: hook, hook: hook,
path: path, path: path,
includePathCheck: true,
} }
s.Handler = srv s.Handler = srv
DefaultLog.Info(fmt.Sprintf("Listening on addr: %s path: %s", s.Addr, path))
return s.ListenAndServe() return s.ListenAndServe()
} }
@@ -74,26 +90,34 @@ func RunServer(s *http.Server, hook Webhook, path string) error {
func RunTLSServer(s *http.Server, hook Webhook, path string) error { func RunTLSServer(s *http.Server, hook Webhook, path string) error {
srv := &server{ srv := &server{
hook: hook, hook: hook,
path: path, path: path,
includePathCheck: true,
} }
s.Handler = srv s.Handler = srv
DefaultLog.Info(fmt.Sprintf("Listening on addr: %s path: %s", s.Addr, path))
return s.ListenAndServeTLS("", "") return s.ListenAndServeTLS("", "")
} }
// ServeHTTP is the Handler for every posted WebHook Event // ServeHTTP is the Handler for every posted WebHook Event
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close() defer r.Body.Close()
DefaultLog.Info("Webhook received")
if r.Method != "POST" { if r.Method != "POST" {
DefaultLog.Error(fmt.Sprintf("405 Method not allowed, attempt made using Method: %s", r.Method))
http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed) http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed)
return return
} }
if r.URL.Path != s.path {
http.Error(w, "404 Not found", http.StatusNotFound) DefaultLog.Debug(fmt.Sprintf("Include path check: %t", s.includePathCheck))
return if s.includePathCheck {
if r.URL.Path != s.path {
DefaultLog.Error(fmt.Sprintf("404 Not found, POST made using path: %s, but expected %s", r.URL.Path, s.path))
http.Error(w, "404 Not found", http.StatusNotFound)
return
}
} }
s.hook.ParsePayload(w, r) s.hook.ParsePayload(w, r)
+40 -1
View File
@@ -8,6 +8,8 @@ import (
"testing" "testing"
"time" "time"
"net/http/httptest"
. "gopkg.in/go-playground/assert.v1" . "gopkg.in/go-playground/assert.v1"
) )
@@ -47,6 +49,43 @@ func TestMain(m *testing.M) {
// teardown // teardown
} }
func TestHandler(t *testing.T) {
mux := http.NewServeMux()
mux.Handle("/webhooks", Handler(fakeHook))
s := httptest.NewServer(Handler(fakeHook))
defer s.Close()
payload := "{}"
req, err := http.NewRequest("POST", s.URL+"/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json")
Equal(t, err, nil)
client := &http.Client{}
resp, err := client.Do(req)
Equal(t, err, nil)
defer resp.Body.Close()
Equal(t, resp.StatusCode, http.StatusOK)
// Test BAD METHOD
req, err = http.NewRequest("GET", s.URL+"/webhooks", bytes.NewBuffer([]byte(payload)))
req.Header.Set("Content-Type", "application/json")
Equal(t, err, nil)
resp, err = client.Do(req)
Equal(t, err, nil)
defer resp.Body.Close()
Equal(t, resp.StatusCode, http.StatusMethodNotAllowed)
}
func TestRun(t *testing.T) { func TestRun(t *testing.T) {
go Run(fakeHook, "127.0.0.1:3006", "/webhooks") go Run(fakeHook, "127.0.0.1:3006", "/webhooks")
@@ -97,7 +136,7 @@ func TestRun(t *testing.T) {
} }
func TestRunServer(t *testing.T) { func TestRunServer(t *testing.T) {
DefaultLog = NewLogger(true)
server := &http.Server{Addr: "127.0.0.1:3007", Handler: nil} server := &http.Server{Addr: "127.0.0.1:3007", Handler: nil}
go RunServer(server, fakeHook, "/webhooks") go RunServer(server, fakeHook, "/webhooks")
time.Sleep(5000) time.Sleep(5000)