Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ffb2ffc32 | |||
| 84dc839b94 | |||
| 2c541a737f | |||
| be944ed461 | |||
| 16896cdb6b | |||
| 3e1bb69b7d | |||
| c9c9d981d7 | |||
| 22713e3054 | |||
| 0ebe5231e2 | |||
| b26a00f48c | |||
| 5580947e3e | |||
| 8db8abb389 | |||
| 9e4b7fa61b | |||
| a831111e26 | |||
| f2acbcde40 | |||
| 3ad83a882d | |||
| 32331e68eb | |||
| 6d731433c9 | |||
| 1253715fd8 | |||
| d4d9692af0 | |||
| 1b6492ce45 | |||
| 493e94de50 | |||
| fc20b2a250 | |||
| 1c3914ef16 | |||
| 2aa5fdc243 | |||
| ea44f6921c | |||
| b6e930d373 | |||
| c271ec3e32 | |||
| 0c4911f7f5 | |||
| 3667088d60 | |||
| 9cafa895ff | |||
| 9494e434fc | |||
| 97dd8f3564 | |||
| 8f6fada23d | |||
| 94f9d6694d | |||
| ad5392160c | |||
| 19cab958b6 | |||
| 78ce03b046 | |||
| ced2e979bc | |||
| d60a03e52a | |||
| f553bfaa59 | |||
| 903279e458 | |||
| 5462959f1e | |||
| 4964805803 | |||
| 13e6611c00 | |||
| b9424ab72e | |||
| 203bf4218b | |||
| 5e4be82c0b | |||
| cd89a10b64 | |||
| e120e3b3ba | |||
| a5141d656b | |||
| 9a8b92d028 | |||
| 248dae5b83 | |||
| cc075dfe29 | |||
| c93876b3e9 | |||
| 0926003ddf | |||
| 58dd13d367 | |||
| 4fa39fdfab | |||
| fccbba5986 | |||
| 0d7e42cf96 | |||
| c9ac93f3b3 | |||
| 2d256610b0 | |||
| 05a2f7cd8d | |||
| 5ed22cdd66 | |||
| 2e471dc89c |
@@ -6,6 +6,7 @@
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
.idea
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
|
||||
+38
@@ -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
|
||||
@@ -1,13 +1,13 @@
|
||||
Library webhooks
|
||||
================
|
||||
<img align="right" src="https://raw.githubusercontent.com/go-playground/webhooks/v2/logo.png">
|
||||
[](https://semaphoreci.com/joeybloggs/webhooks)
|
||||
[](https://coveralls.io/github/go-playground/webhooks?branch=v2)
|
||||
<img align="right" src="https://raw.githubusercontent.com/go-playground/webhooks/v3/logo.png">
|
||||
[](https://travis-ci.org/go-playground/webhooks)
|
||||
[](https://coveralls.io/github/go-playground/webhooks?branch=v3)
|
||||
[](https://goreportcard.com/report/go-playground/webhooks)
|
||||
[](https://godoc.org/gopkg.in/go-playground/webhooks.v2)
|
||||
[](https://godoc.org/gopkg.in/go-playground/webhooks.v3)
|
||||

|
||||
|
||||
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:
|
||||
|
||||
@@ -24,17 +24,17 @@ Installation
|
||||
Use go get.
|
||||
|
||||
```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.
|
||||
|
||||
import "gopkg.in/go-playground/webhooks.v2"
|
||||
import "gopkg.in/go-playground/webhooks.v3"
|
||||
|
||||
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:
|
||||
|
||||
@@ -46,8 +46,8 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/go-playground/webhooks.v2"
|
||||
"gopkg.in/go-playground/webhooks.v2/github"
|
||||
"gopkg.in/go-playground/webhooks.v3"
|
||||
"gopkg.in/go-playground/webhooks.v3/github"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -75,7 +75,7 @@ func HandleRelease(payload interface{}, header webhooks.Header) {
|
||||
pl := payload.(github.ReleasePayload)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -93,7 +93,6 @@ func HandlePullRequest(payload interface{}, header webhooks.Header) {
|
||||
// Do whatever you want from here...
|
||||
fmt.Printf("%+v", pl)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Single receiver for events you subscribe to
|
||||
@@ -104,8 +103,8 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/go-playground/webhooks.v2"
|
||||
"gopkg.in/go-playground/webhooks.v2/github"
|
||||
"gopkg.in/go-playground/webhooks.v3"
|
||||
"gopkg.in/go-playground/webhooks.v3/github"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
+43
-25
@@ -2,10 +2,11 @@ package bitbucket
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"gopkg.in/go-playground/webhooks.v2"
|
||||
"gopkg.in/go-playground/webhooks.v3"
|
||||
)
|
||||
|
||||
// Webhook instance contains all methods needed to process events
|
||||
@@ -25,23 +26,24 @@ type Event string
|
||||
|
||||
// Bitbucket hook types
|
||||
const (
|
||||
RepoPushEvent Event = "repo:push"
|
||||
RepoForkEvent Event = "repo:fork"
|
||||
RepoCommitCommentCreatedEvent Event = "repo:commit_comment_created"
|
||||
RepoCommitStatusCreatedEvent Event = "repo:commit_status_created"
|
||||
RepoCommitStatusUpdatedEvent Event = "repo:commit_status_updated"
|
||||
IssueCreatedEvent Event = "issue:created"
|
||||
IssueUpdatedEvent Event = "issue:updated"
|
||||
IssueCommentCreatedEvent Event = "issue:comment_created"
|
||||
PullRequestCreatedEvent Event = "pullrequest:created"
|
||||
PullRequestUpdatedEvent Event = "pullrequest:updated"
|
||||
PullRequestApprovedEvent Event = "pullrequest:approved"
|
||||
PullRequestApprovalRemovedEvent Event = "pullrequest:unapproved"
|
||||
PullRequestMergedEvent Event = "pullrequest:fulfilled"
|
||||
PullRequestDeclinedEvent Event = "pullrequest:rejected"
|
||||
PullRequestCommentCreatedEvent Event = "pullrequest:comment_created"
|
||||
PullRequestCommentUpdatedEvent Event = "pullrequest:comment_updated"
|
||||
PullRequestCommentDeletedEvent Event = "pull_request:comment_deleted"
|
||||
RepoPushEvent Event = "repo:push"
|
||||
RepoForkEvent Event = "repo:fork"
|
||||
RepoUpdatedEvent Event = "repo:updated"
|
||||
RepoCommitCommentCreatedEvent Event = "repo:commit_comment_created"
|
||||
RepoCommitStatusCreatedEvent Event = "repo:commit_status_created"
|
||||
RepoCommitStatusUpdatedEvent Event = "repo:commit_status_updated"
|
||||
IssueCreatedEvent Event = "issue:created"
|
||||
IssueUpdatedEvent Event = "issue:updated"
|
||||
IssueCommentCreatedEvent Event = "issue:comment_created"
|
||||
PullRequestCreatedEvent Event = "pullrequest:created"
|
||||
PullRequestUpdatedEvent Event = "pullrequest:updated"
|
||||
PullRequestApprovedEvent Event = "pullrequest:approved"
|
||||
PullRequestUnapprovedEvent Event = "pullrequest:unapproved"
|
||||
PullRequestMergedEvent Event = "pullrequest:fulfilled"
|
||||
PullRequestDeclinedEvent Event = "pullrequest:rejected"
|
||||
PullRequestCommentCreatedEvent Event = "pullrequest:comment_created"
|
||||
PullRequestCommentUpdatedEvent Event = "pullrequest:comment_updated"
|
||||
PullRequestCommentDeletedEvent Event = "pullrequest:comment_deleted"
|
||||
)
|
||||
|
||||
// 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.
|
||||
func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
webhooks.DefaultLog.Info("Parsing Payload...")
|
||||
|
||||
uuid := r.Header.Get("X-Hook-UUID")
|
||||
if uuid == "" {
|
||||
webhooks.DefaultLog.Error("Missing X-Hook-UUID Header")
|
||||
http.Error(w, "400 Bad Request - Missing X-Hook-UUID Header", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Hook-UUID:%s", uuid))
|
||||
|
||||
if uuid != hook.uuid {
|
||||
http.Error(w, "403 Forbidden - Missing X-Hook-UUID does not match", http.StatusForbidden)
|
||||
return
|
||||
if len(hook.uuid) > 0 {
|
||||
if uuid != hook.uuid {
|
||||
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")
|
||||
if event == "" {
|
||||
webhooks.DefaultLog.Error("Missing X-Event-Key Header")
|
||||
http.Error(w, "400 Bad Request - Missing X-Event-Key Header", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Event-Key:%s", event))
|
||||
|
||||
bitbucketEvent := Event(event)
|
||||
|
||||
fn, ok := hook.eventFuncs[bitbucketEvent]
|
||||
// if no event registered
|
||||
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
|
||||
}
|
||||
|
||||
payload, err := ioutil.ReadAll(r.Body)
|
||||
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
|
||||
}
|
||||
|
||||
webhooks.DefaultLog.Debug(fmt.Sprintf("Payload:%s", string(payload)))
|
||||
hd := webhooks.Header(r.Header)
|
||||
|
||||
switch bitbucketEvent {
|
||||
@@ -111,6 +125,10 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
var pl RepoForkPayload
|
||||
json.Unmarshal([]byte(payload), &pl)
|
||||
hook.runProcessPayloadFunc(fn, pl, hd)
|
||||
case RepoUpdatedEvent:
|
||||
var pl RepoUpdatedPayload
|
||||
json.Unmarshal([]byte(payload), &pl)
|
||||
hook.runProcessPayloadFunc(fn, pl, hd)
|
||||
case RepoCommitCommentCreatedEvent:
|
||||
var pl RepoCommitCommentCreatedPayload
|
||||
json.Unmarshal([]byte(payload), &pl)
|
||||
@@ -147,8 +165,8 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
var pl PullRequestApprovedPayload
|
||||
json.Unmarshal([]byte(payload), &pl)
|
||||
hook.runProcessPayloadFunc(fn, pl, hd)
|
||||
case PullRequestApprovalRemovedEvent:
|
||||
var pl PullRequestApprovalRemovedPayload
|
||||
case PullRequestUnapprovedEvent:
|
||||
var pl PullRequestUnapprovedPayload
|
||||
json.Unmarshal([]byte(payload), &pl)
|
||||
hook.runProcessPayloadFunc(fn, pl, hd)
|
||||
case PullRequestMergedEvent:
|
||||
|
||||
+182
-26
@@ -9,7 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
. "gopkg.in/go-playground/assert.v1"
|
||||
"gopkg.in/go-playground/webhooks.v2"
|
||||
"gopkg.in/go-playground/webhooks.v3"
|
||||
)
|
||||
|
||||
// NOTES:
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
//
|
||||
//
|
||||
const (
|
||||
port = 3010
|
||||
port = 3009
|
||||
path = "/webhooks"
|
||||
)
|
||||
|
||||
@@ -39,10 +39,30 @@ func TestMain(m *testing.M) {
|
||||
|
||||
// setup
|
||||
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)
|
||||
time.Sleep(5000)
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
|
||||
os.Exit(m.Run())
|
||||
|
||||
@@ -56,7 +76,7 @@ func TestProvider(t *testing.T) {
|
||||
func TestUUIDMissingEvent(t *testing.T) {
|
||||
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("X-Event-Key", "noneexistant_event")
|
||||
|
||||
@@ -74,7 +94,7 @@ func TestUUIDMissingEvent(t *testing.T) {
|
||||
func TestUUIDDoesNotMatchEvent(t *testing.T) {
|
||||
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("X-Hook-UUID", "THIS_DOES_NOT_MATCH")
|
||||
|
||||
@@ -92,7 +112,7 @@ func TestUUIDDoesNotMatchEvent(t *testing.T) {
|
||||
func TestBadNoEventHeader(t *testing.T) {
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
|
||||
@@ -110,7 +130,7 @@ func TestBadNoEventHeader(t *testing.T) {
|
||||
func TestUnsubscribedEvent(t *testing.T) {
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
req.Header.Set("X-Event-Key", "noneexistant_event")
|
||||
@@ -129,7 +149,7 @@ func TestUnsubscribedEvent(t *testing.T) {
|
||||
func TestBadBody(t *testing.T) {
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
req.Header.Set("X-Event-Key", "repo:fork")
|
||||
@@ -445,6 +465,142 @@ func TestRepoFork(t *testing.T) {
|
||||
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) {
|
||||
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
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("X-Hook-UUID", "MY_UUID")
|
||||
req.Header.Set("X-Event-Key", "pull_request:comment_deleted")
|
||||
|
||||
+457
-337
@@ -2,388 +2,508 @@ package bitbucket
|
||||
|
||||
import "time"
|
||||
|
||||
// PullRequestCommentDeletedPayload is the Bitbucket pull_request:comment_deleted payload
|
||||
type PullRequestCommentDeletedPayload struct {
|
||||
Actor User `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"`
|
||||
// RepoPushPayload is the Bitbucket repo:push payload
|
||||
type RepoPushPayload struct {
|
||||
Actor Owner `json:"actor"`
|
||||
Repository Repository `json:"repository"`
|
||||
Issue Issue `json:"issue"`
|
||||
Comment Comment `json:"comment"`
|
||||
}
|
||||
|
||||
// IssueUpdatedPayload is the Bitbucket issue:updated payload
|
||||
type IssueUpdatedPayload struct {
|
||||
Actor User `json:"actor"`
|
||||
Issue Issue `json:"issue"`
|
||||
Repository Repository `json:"repository"`
|
||||
Comment Comment `json:"comment"`
|
||||
Changes IssueChanges `json:"changes"`
|
||||
}
|
||||
|
||||
// IssueCreatedPayload is the Bitbucket issue:created payload
|
||||
type IssueCreatedPayload struct {
|
||||
Actor User `json:"actor"`
|
||||
Issue Issue `json:"issue"`
|
||||
Repository Repository `json:"repository"`
|
||||
}
|
||||
|
||||
// RepoCommitStatusUpdatedPayload is the Bitbucket repo:commit_status_updated payload
|
||||
type RepoCommitStatusUpdatedPayload struct {
|
||||
Actor User `json:"actor"`
|
||||
Repository Repository `json:"repository"`
|
||||
CommitStatus CommitStatus `json:"commit_status"`
|
||||
}
|
||||
|
||||
// RepoCommitStatusCreatedPayload is the Bitbucket repo:commit_status_created payload
|
||||
type RepoCommitStatusCreatedPayload struct {
|
||||
Actor User `json:"actor"`
|
||||
Repository Repository `json:"repository"`
|
||||
CommitStatus CommitStatus `json:"commit_status"`
|
||||
}
|
||||
|
||||
// RepoCommitCommentCreatedPayload is the Bitbucket repo:commit_comment_created payload
|
||||
type RepoCommitCommentCreatedPayload struct {
|
||||
Actor User `json:"actor"`
|
||||
Comment Comment `json:"comment"`
|
||||
Repository Repository `json:"repository"`
|
||||
Commit CommitHash `json:"commit"`
|
||||
Push struct {
|
||||
Changes []struct {
|
||||
New 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:"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
|
||||
type RepoForkPayload struct {
|
||||
Actor User `json:"actor"`
|
||||
Actor Owner `json:"actor"`
|
||||
Repository Repository `json:"repository"`
|
||||
Fork Repository `json:"fork"`
|
||||
}
|
||||
|
||||
// RepoPushPayload is the Bitbucket repo:push payload
|
||||
type RepoPushPayload struct {
|
||||
Actor User `json:"actor"`
|
||||
// RepoUpdatedPayload is the Bitbucket repo:updated payload
|
||||
type RepoUpdatedPayload struct {
|
||||
Actor Owner `json:"actor"`
|
||||
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
|
||||
type Approval struct {
|
||||
Date time.Time `json:"date"`
|
||||
User User `json:"user"`
|
||||
// RepoCommitCommentCreatedPayload is the Bitbucket repo:commit_comment_created payload
|
||||
type RepoCommitCommentCreatedPayload struct {
|
||||
Actor Owner `json:"actor"`
|
||||
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
|
||||
type IssueChanges struct {
|
||||
Status IssueChangeStatus `json:"status"`
|
||||
// RepoCommitStatusCreatedPayload is the Bitbucket repo:commit_status_created payload
|
||||
type RepoCommitStatusCreatedPayload struct {
|
||||
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
|
||||
type IssueChangeStatus struct {
|
||||
Old string `json:"old"`
|
||||
New string `json:"new"`
|
||||
// RepoCommitStatusUpdatedPayload is the Bitbucket repo:commit_status_updated payload
|
||||
type RepoCommitStatusUpdatedPayload struct {
|
||||
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"`
|
||||
}
|
||||
|
||||
// CommitStatus is the common Bitbucket CommitStatus Sub Entity
|
||||
type 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 LinksSelfCommit `json:"links"`
|
||||
// IssueCreatedPayload is the Bitbucket issue:created payload
|
||||
type IssueCreatedPayload struct {
|
||||
Actor Owner `json:"actor"`
|
||||
Issue Issue `json:"issue"`
|
||||
Repository Repository `json:"repository"`
|
||||
}
|
||||
|
||||
// Push is the common Bitbucket Push Sub Entity
|
||||
type Push struct {
|
||||
Changes []Change `json:"changes"`
|
||||
// IssueUpdatedPayload is the Bitbucket issue:updated payload
|
||||
type IssueUpdatedPayload struct {
|
||||
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
|
||||
type Change struct {
|
||||
New ChangeData `json:"new"`
|
||||
Old ChangeData `json:"old"`
|
||||
Links LinksHTMLDiffCommits `json:"links"`
|
||||
Created bool `json:"created"`
|
||||
Forced bool `json:"forced"`
|
||||
Closed bool `json:"closed"`
|
||||
Commits []Commit `json:"commits"`
|
||||
Truncated bool `json:"truncated"`
|
||||
// IssueCommentCreatedPayload is the Bitbucket pullrequest:created payload
|
||||
type IssueCommentCreatedPayload struct {
|
||||
Actor Owner `json:"actor"`
|
||||
Repository Repository `json:"repository"`
|
||||
Issue Issue `json:"issue"`
|
||||
Comment Comment `json:"comment"`
|
||||
}
|
||||
|
||||
// ChangeData is the common Bitbucket ChangeData Sub Entity
|
||||
type ChangeData struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Target Target `json:"target"`
|
||||
Links LinksHTMLSelfCommits `json:"links"`
|
||||
// PullRequestCreatedPayload is the Bitbucket pullrequest:created payload
|
||||
type PullRequestCreatedPayload struct {
|
||||
Actor Owner `json:"actor"`
|
||||
PullRequest PullRequest `json:"pullrequest"`
|
||||
Repository Repository `json:"repository"`
|
||||
}
|
||||
|
||||
// Target is the common Bitbucket Target Sub Entity
|
||||
type Target struct {
|
||||
Type string `json:"type"`
|
||||
Hash string `json:"hash"`
|
||||
Author User `json:"author"`
|
||||
Message string `json:"message"`
|
||||
Date time.Time `json:"date"`
|
||||
Parents []Parent `json:"parents"`
|
||||
Links LinksHTMLSelf `json:"links"`
|
||||
// PullRequestUpdatedPayload is the Bitbucket pullrequest:updated payload
|
||||
type PullRequestUpdatedPayload struct {
|
||||
Actor Owner `json:"actor"`
|
||||
PullRequest PullRequest `json:"pullrequest"`
|
||||
Repository Repository `json:"repository"`
|
||||
}
|
||||
|
||||
// Parent is the common Bitbucket Parent Sub Entity
|
||||
type Parent struct {
|
||||
Type string `json:"type"`
|
||||
Hash string `json:"hash"`
|
||||
Links LinksHTMLSelf `json:"links"`
|
||||
// PullRequestApprovedPayload is the Bitbucket pullrequest:approved payload
|
||||
type PullRequestApprovedPayload struct {
|
||||
Actor Owner `json:"actor"`
|
||||
PullRequest PullRequest `json:"pullrequest"`
|
||||
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
|
||||
type Commit struct {
|
||||
Hash string `json:"hash"`
|
||||
Type string `json:"type"`
|
||||
Message string `json:"message"`
|
||||
Author User `json:"author"`
|
||||
Links LinksHTMLSelf `json:"links"`
|
||||
// PullRequestUnapprovedPayload is the Bitbucket pullrequest:unapproved payload
|
||||
type PullRequestUnapprovedPayload struct {
|
||||
Actor Owner `json:"actor"`
|
||||
PullRequest PullRequest `json:"pullrequest"`
|
||||
Repository Repository `json:"repository"`
|
||||
Approval struct {
|
||||
Date time.Time `json:"date"`
|
||||
User Owner `json:"user"`
|
||||
} `json:"approval"`
|
||||
}
|
||||
|
||||
// User is the common Bitbucket User Entity
|
||||
type User struct {
|
||||
// PullRequestMergedPayload is the Bitbucket pullrequest:fulfilled payload
|
||||
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"`
|
||||
DisplayName string `json:"display_name"`
|
||||
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 {
|
||||
Links Links `json:"links"`
|
||||
UUID string `json:"uuid"`
|
||||
FullName string `json:"full_name"`
|
||||
Name string `json:"name"`
|
||||
Scm string `json:"scm"`
|
||||
IsPrivate bool `json:"is_private"`
|
||||
Type string `json:"type"`
|
||||
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"`
|
||||
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 {
|
||||
ID int64 `json:"id"`
|
||||
Component string `json:"component"`
|
||||
Title string `json:"title"`
|
||||
Content Content `json:"content"`
|
||||
Priority string `json:"priority"`
|
||||
State string `json:"state"`
|
||||
Type string `json:"type"`
|
||||
Milestone Milestone `json:"milestone"`
|
||||
Version Version `json:"version"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
UpdatedOn time.Time `json:"updated_on"`
|
||||
Links LinksHTMLSelf `json:"links"`
|
||||
ID int64 `json:"id"`
|
||||
Component string `json:"component"`
|
||||
Title string `json:"title"`
|
||||
Content struct {
|
||||
Raw string `json:"raw"`
|
||||
HTML string `json:"html"`
|
||||
Markup string `json:"markup"`
|
||||
} `json:"content"`
|
||||
Priority string `json:"priority"`
|
||||
State string `json:"state"`
|
||||
Type string `json:"type"`
|
||||
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 {
|
||||
ID int64 `json:"id"`
|
||||
Parent ParentID `json:"parent"`
|
||||
Content Content `json:"content"`
|
||||
Inline Inline `json:"inline"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
UpdatedOn time.Time `json:"updated_on"`
|
||||
Links LinksHTMLSelf `json:"links"`
|
||||
ID int64 `json:"id"`
|
||||
Parent struct {
|
||||
ID int64 `json:"id"`
|
||||
} `json:"parent"`
|
||||
Content struct {
|
||||
Raw string `json:"raw"`
|
||||
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 {
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
State string `json:"state"`
|
||||
Author User `json:"author"`
|
||||
Source Source `json:"source"`
|
||||
Destination Destination `json:"destination"`
|
||||
MergeCommit CommitHash `json:"merge_commit"`
|
||||
Participants []User `json:"participants"`
|
||||
Reviewers []User `json:"reviewers"`
|
||||
CloseSourceBranch bool `json:"close_source_branch"`
|
||||
ClosedBy User `json:"closed_by"`
|
||||
Reason string `json:"reason"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
UpdatedOn time.Time `json:"updated_on"`
|
||||
Links LinksHTMLSelf `json:"links"`
|
||||
}
|
||||
|
||||
// Destination is the common Bitbucket Destination Sub Entity
|
||||
type Destination struct {
|
||||
Branch Branch `json:"branch"`
|
||||
Commit CommitHash `json:"commit"`
|
||||
Repository Repository `json:"repository"`
|
||||
}
|
||||
|
||||
// Source is the common Bitbucket Source Sub Entity
|
||||
type Source struct {
|
||||
Branch Branch `json:"branch"`
|
||||
Commit CommitHash `json:"commit"`
|
||||
Repository Repository `json:"repository"`
|
||||
}
|
||||
|
||||
// Branch is the common Bitbucket Branch Sub Entity
|
||||
type Branch struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// CommitHash is the common Bitbucket CommitHash Sub Entity
|
||||
type CommitHash struct {
|
||||
Hash string `json:"hash"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
State string `json:"state"`
|
||||
Author Owner `json:"author"`
|
||||
Source struct {
|
||||
Branch struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"branch"`
|
||||
Commit struct {
|
||||
Hash string `json:"hash"`
|
||||
} `json:"commit"`
|
||||
Repository Repository `json:"repository"`
|
||||
} `json:"source"`
|
||||
Destination struct {
|
||||
Branch struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"branch"`
|
||||
Commit struct {
|
||||
Hash string `json:"hash"`
|
||||
} `json:"commit"`
|
||||
Repository Repository `json:"repository"`
|
||||
} `json:"destination"`
|
||||
MergeCommit struct {
|
||||
Hash string `json:"hash"`
|
||||
} `json:"merge_commit"`
|
||||
Participants []Owner `json:"participants"`
|
||||
Reviewers []Owner `json:"reviewers"`
|
||||
CloseSourceBranch bool `json:"close_source_branch"`
|
||||
ClosedBy Owner `json:"closed_by"`
|
||||
Reason string `json:"reason"`
|
||||
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"`
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/go-playground/webhooks.v2"
|
||||
"gopkg.in/go-playground/webhooks.v2/github"
|
||||
"gopkg.in/go-playground/webhooks.v3"
|
||||
"gopkg.in/go-playground/webhooks.v3/github"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -14,7 +14,6 @@ const (
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
hook := github.New(&github.Config{Secret: "MyGitHubSuperSecretSecrect...?"})
|
||||
hook.RegisterEvents(HandleRelease, github.ReleaseEvent)
|
||||
hook.RegisterEvents(HandlePullRequest, github.PullRequestEvent)
|
||||
@@ -27,13 +26,12 @@ func main() {
|
||||
|
||||
// HandleRelease handles GitHub release events
|
||||
func HandleRelease(payload interface{}, header webhooks.Header) {
|
||||
|
||||
fmt.Println("Handling Release")
|
||||
|
||||
pl := payload.(github.ReleasePayload)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/go-playground/webhooks.v2"
|
||||
"gopkg.in/go-playground/webhooks.v2/github"
|
||||
"gopkg.in/go-playground/webhooks.v3"
|
||||
"gopkg.in/go-playground/webhooks.v3/github"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -14,7 +14,6 @@ const (
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
hook := github.New(&github.Config{Secret: "MyGitHubSuperSecretSecrect...?"})
|
||||
hook.RegisterEvents(HandleMultiple, github.ReleaseEvent, github.PullRequestEvent) // Add as many as you want
|
||||
|
||||
@@ -26,7 +25,6 @@ func main() {
|
||||
|
||||
// HandleMultiple handles multiple GitHub events
|
||||
func HandleMultiple(payload interface{}, header webhooks.Header) {
|
||||
|
||||
fmt.Println("Handling Payload..")
|
||||
|
||||
switch payload.(type) {
|
||||
|
||||
+79
-14
@@ -5,10 +5,11 @@ import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"gopkg.in/go-playground/webhooks.v2"
|
||||
"gopkg.in/go-playground/webhooks.v3"
|
||||
)
|
||||
|
||||
// Webhook instance contains all methods needed to process events
|
||||
@@ -35,18 +36,30 @@ const (
|
||||
DeploymentStatusEvent Event = "deployment_status"
|
||||
ForkEvent Event = "fork"
|
||||
GollumEvent Event = "gollum"
|
||||
InstallationEvent Event = "installation"
|
||||
IntegrationInstallationEvent Event = "integration_installation"
|
||||
IssueCommentEvent Event = "issue_comment"
|
||||
IssuesEvent Event = "issues"
|
||||
LabelEvent Event = "label"
|
||||
MemberEvent Event = "member"
|
||||
MembershipEvent Event = "membership"
|
||||
MilestoneEvent Event = "milestone"
|
||||
OrganizationEvent Event = "organization"
|
||||
OrgBlockEvent Event = "org_block"
|
||||
PageBuildEvent Event = "page_build"
|
||||
PingEvent Event = "ping"
|
||||
ProjectCardEvent Event = "project_card"
|
||||
ProjectColumnEvent Event = "project_column"
|
||||
ProjectEvent Event = "project"
|
||||
PublicEvent Event = "public"
|
||||
PullRequestReviewCommentEvent Event = "pull_request_review_comment"
|
||||
PullRequestEvent Event = "pull_request"
|
||||
PullRequestReviewEvent Event = "pull_request_review"
|
||||
PullRequestReviewCommentEvent Event = "pull_request_review_comment"
|
||||
PushEvent Event = "push"
|
||||
RepositoryEvent Event = "repository"
|
||||
ReleaseEvent Event = "release"
|
||||
RepositoryEvent Event = "repository"
|
||||
StatusEvent Event = "status"
|
||||
TeamEvent Event = "team"
|
||||
TeamAddEvent Event = "team_add"
|
||||
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.
|
||||
func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
webhooks.DefaultLog.Info("Parsing Payload...")
|
||||
|
||||
event := r.Header.Get("X-GitHub-Event")
|
||||
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)
|
||||
return
|
||||
}
|
||||
webhooks.DefaultLog.Debug(fmt.Sprintf("X-GitHub-Event:%s", event))
|
||||
|
||||
gitHubEvent := Event(event)
|
||||
|
||||
fn, ok := hook.eventFuncs[gitHubEvent]
|
||||
// if no event registered
|
||||
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
|
||||
}
|
||||
|
||||
payload, err := ioutil.ReadAll(r.Body)
|
||||
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
|
||||
}
|
||||
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-Hub-Signature")
|
||||
|
||||
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)
|
||||
return
|
||||
}
|
||||
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Hub-Signature:%s", signature))
|
||||
|
||||
mac := hmac.New(sha1.New, []byte(hook.secret))
|
||||
mac.Write(payload)
|
||||
@@ -124,6 +144,7 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
expectedMAC := hex.EncodeToString(mac.Sum(nil))
|
||||
|
||||
if !hmac.Equal([]byte(signature[5:]), []byte(expectedMAC)) {
|
||||
webhooks.DefaultLog.Error("HMAC verification failed")
|
||||
http.Error(w, "403 Forbidden - HMAC verification failed", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
@@ -161,6 +182,10 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
var g GollumPayload
|
||||
json.Unmarshal([]byte(payload), &g)
|
||||
hook.runProcessPayloadFunc(fn, g, hd)
|
||||
case InstallationEvent, IntegrationInstallationEvent:
|
||||
var i InstallationPayload
|
||||
json.Unmarshal([]byte(payload), &i)
|
||||
hook.runProcessPayloadFunc(fn, i, hd)
|
||||
case IssueCommentEvent:
|
||||
var i IssueCommentPayload
|
||||
json.Unmarshal([]byte(payload), &i)
|
||||
@@ -169,6 +194,10 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
var i IssuesPayload
|
||||
json.Unmarshal([]byte(payload), &i)
|
||||
hook.runProcessPayloadFunc(fn, i, hd)
|
||||
case LabelEvent:
|
||||
var l LabelPayload
|
||||
json.Unmarshal([]byte(payload), &l)
|
||||
hook.runProcessPayloadFunc(fn, l, hd)
|
||||
case MemberEvent:
|
||||
var m MemberPayload
|
||||
json.Unmarshal([]byte(payload), &m)
|
||||
@@ -177,38 +206,74 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
var m MembershipPayload
|
||||
json.Unmarshal([]byte(payload), &m)
|
||||
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:
|
||||
var p PageBuildPayload
|
||||
json.Unmarshal([]byte(payload), &p)
|
||||
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:
|
||||
var p PublicPayload
|
||||
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 PullRequestEvent:
|
||||
var p PullRequestPayload
|
||||
json.Unmarshal([]byte(payload), &p)
|
||||
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:
|
||||
var p PushPayload
|
||||
json.Unmarshal([]byte(payload), &p)
|
||||
hook.runProcessPayloadFunc(fn, p, hd)
|
||||
case RepositoryEvent:
|
||||
var r RepositoryPayload
|
||||
json.Unmarshal([]byte(payload), &r)
|
||||
hook.runProcessPayloadFunc(fn, r, hd)
|
||||
case ReleaseEvent:
|
||||
var r ReleasePayload
|
||||
json.Unmarshal([]byte(payload), &r)
|
||||
hook.runProcessPayloadFunc(fn, r, hd)
|
||||
case RepositoryEvent:
|
||||
var r RepositoryPayload
|
||||
json.Unmarshal([]byte(payload), &r)
|
||||
hook.runProcessPayloadFunc(fn, r, hd)
|
||||
case StatusEvent:
|
||||
var s StatusPayload
|
||||
json.Unmarshal([]byte(payload), &s)
|
||||
hook.runProcessPayloadFunc(fn, s, hd)
|
||||
case TeamEvent:
|
||||
var t TeamPayload
|
||||
json.Unmarshal([]byte(payload), &t)
|
||||
hook.runProcessPayloadFunc(fn, t, hd)
|
||||
case TeamAddEvent:
|
||||
var t TeamAddPayload
|
||||
json.Unmarshal([]byte(payload), &t)
|
||||
|
||||
+2394
-633
File diff suppressed because it is too large
Load Diff
+5044
-661
File diff suppressed because it is too large
Load Diff
+26
-13
@@ -2,10 +2,11 @@ package gitlab
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"gopkg.in/go-playground/webhooks.v2"
|
||||
"gopkg.in/go-playground/webhooks.v3"
|
||||
)
|
||||
|
||||
// Webhook instance contains all methods needed to process events
|
||||
@@ -25,14 +26,15 @@ type Event string
|
||||
|
||||
// GitLab hook types
|
||||
const (
|
||||
PushEvents Event = "Push Hook"
|
||||
TagEvents Event = "Tag Push Hook"
|
||||
IssuesEvents Event = "Issue Hook"
|
||||
CommentEvents Event = "Note Hook"
|
||||
MergerRequestEvents Event = "Merge Request Hook"
|
||||
WikiPageEvents Event = "Wiki Page Hook"
|
||||
PipelineEvents Event = "Pipeline Hook"
|
||||
BuildEvents Event = "Build Hook"
|
||||
PushEvents Event = "Push Hook"
|
||||
TagEvents Event = "Tag Push Hook"
|
||||
IssuesEvents Event = "Issue Hook"
|
||||
ConfidentialIssuesEvents Event = "Confidential Issue Hook"
|
||||
CommentEvents Event = "Note Hook"
|
||||
MergeRequestEvents Event = "Merge Request Hook"
|
||||
WikiPageEvents Event = "Wiki Page Hook"
|
||||
PipelineEvents Event = "Pipeline Hook"
|
||||
BuildEvents Event = "Build Hook"
|
||||
)
|
||||
|
||||
// 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.
|
||||
func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
webhooks.DefaultLog.Info("Parsing Payload...")
|
||||
|
||||
event := r.Header.Get("X-Gitlab-Event")
|
||||
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)
|
||||
return
|
||||
}
|
||||
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Gitlab-Event:%s", event))
|
||||
|
||||
gitLabEvent := Event(event)
|
||||
|
||||
fn, ok := hook.eventFuncs[gitLabEvent]
|
||||
// if no event registered
|
||||
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
|
||||
}
|
||||
|
||||
payload, err := ioutil.ReadAll(r.Body)
|
||||
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
|
||||
}
|
||||
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-Gitlab-Token")
|
||||
|
||||
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)
|
||||
return
|
||||
}
|
||||
@@ -105,6 +113,11 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
json.Unmarshal([]byte(payload), &te)
|
||||
hook.runProcessPayloadFunc(fn, te, hd)
|
||||
|
||||
case ConfidentialIssuesEvents:
|
||||
var cie ConfidentialIssueEventPayload
|
||||
json.Unmarshal([]byte(payload), &cie)
|
||||
hook.runProcessPayloadFunc(fn, cie, hd)
|
||||
|
||||
case IssuesEvents:
|
||||
var ie IssueEventPayload
|
||||
json.Unmarshal([]byte(payload), &ie)
|
||||
@@ -115,7 +128,7 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
|
||||
json.Unmarshal([]byte(payload), &ce)
|
||||
hook.runProcessPayloadFunc(fn, ce, hd)
|
||||
|
||||
case MergerRequestEvents:
|
||||
case MergeRequestEvents:
|
||||
var mre MergeRequestEventPayload
|
||||
json.Unmarshal([]byte(payload), &mre)
|
||||
hook.runProcessPayloadFunc(fn, mre, hd)
|
||||
|
||||
+222
-86
@@ -9,7 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
. "gopkg.in/go-playground/assert.v1"
|
||||
"gopkg.in/go-playground/webhooks.v2"
|
||||
"gopkg.in/go-playground/webhooks.v3"
|
||||
)
|
||||
|
||||
// NOTES:
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
//
|
||||
|
||||
const (
|
||||
port = 3009
|
||||
port = 3011
|
||||
path = "/webhooks"
|
||||
)
|
||||
|
||||
@@ -43,14 +43,15 @@ func TestMain(m *testing.M) {
|
||||
PushEvents,
|
||||
TagEvents,
|
||||
IssuesEvents,
|
||||
ConfidentialIssuesEvents,
|
||||
CommentEvents,
|
||||
MergerRequestEvents,
|
||||
MergeRequestEvents,
|
||||
WikiPageEvents,
|
||||
PipelineEvents,
|
||||
BuildEvents,
|
||||
)
|
||||
go webhooks.Run(hook, "127.0.0.1:"+strconv.Itoa(port), path)
|
||||
time.Sleep(5000)
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
|
||||
os.Exit(m.Run())
|
||||
|
||||
@@ -64,7 +65,7 @@ func TestProvider(t *testing.T) {
|
||||
func TestBadNoEventHeader(t *testing.T) {
|
||||
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")
|
||||
|
||||
Equal(t, err, nil)
|
||||
@@ -81,7 +82,7 @@ func TestBadNoEventHeader(t *testing.T) {
|
||||
func TestUnsubscribedEvent(t *testing.T) {
|
||||
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("X-Gitlab-Event", "noneexistant_event")
|
||||
|
||||
@@ -99,7 +100,7 @@ func TestUnsubscribedEvent(t *testing.T) {
|
||||
func TestBadBody(t *testing.T) {
|
||||
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("X-Gitlab-Event", "Note Hook")
|
||||
|
||||
@@ -117,7 +118,7 @@ func TestBadBody(t *testing.T) {
|
||||
func TestTokenMissmatch(t *testing.T) {
|
||||
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("X-Gitlab-Event", "Note Hook")
|
||||
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("X-Gitlab-Event", "Push Hook")
|
||||
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("X-Gitlab-Event", "Tag Push Hook")
|
||||
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("X-Gitlab-Event", "Issue Hook")
|
||||
req.Header.Set("X-Gitlab-Token", "sampleToken!")
|
||||
@@ -349,6 +350,78 @@ func TestIssueEvent(t *testing.T) {
|
||||
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) {
|
||||
|
||||
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("X-Gitlab-Event", "Note Hook")
|
||||
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("X-Gitlab-Event", "Note Hook")
|
||||
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("X-Gitlab-Event", "Note Hook")
|
||||
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("X-Gitlab-Event", "Note Hook")
|
||||
req.Header.Set("X-Gitlab-Token", "sampleToken!")
|
||||
@@ -734,85 +807,148 @@ func TestCommentSunippetEvent(t *testing.T) {
|
||||
func TestMergeRequestEvent(t *testing.T) {
|
||||
|
||||
payload := `{
|
||||
"object_kind": "merge_request",
|
||||
"user": {
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"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"
|
||||
"object_kind": "merge_request",
|
||||
"user": {
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
||||
},
|
||||
"target": {
|
||||
"name":"Awesome Project",
|
||||
"project": {
|
||||
"id": 1,
|
||||
"name":"Gitlab Test",
|
||||
"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,
|
||||
"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",
|
||||
"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":"awesome_space/awesome_project",
|
||||
"path_with_namespace":"gitlabhq/gitlab-test",
|
||||
"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"
|
||||
"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"
|
||||
},
|
||||
"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)"
|
||||
"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": 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,
|
||||
"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"
|
||||
"labels": [{
|
||||
"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
|
||||
}],
|
||||
"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("X-Gitlab-Event", "Merge Request Hook")
|
||||
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("X-Gitlab-Event", "Wiki Page Hook")
|
||||
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("X-Gitlab-Event", "Pipeline Hook")
|
||||
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("X-Gitlab-Event", "Build Hook")
|
||||
req.Header.Set("X-Gitlab-Token", "sampleToken!")
|
||||
|
||||
+100
-64
@@ -38,6 +38,14 @@ type IssueEventPayload struct {
|
||||
Repository Repository `json:"repository"`
|
||||
ObjectAttributes ObjectAttributes `json:"object_attributes"`
|
||||
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
|
||||
@@ -45,6 +53,9 @@ type MergeRequestEventPayload struct {
|
||||
ObjectKind string `json:"object_kind"`
|
||||
User User `json:"user"`
|
||||
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
|
||||
@@ -54,15 +65,15 @@ type PushEventPayload struct {
|
||||
After string `json:"after"`
|
||||
Ref string `json:"ref"`
|
||||
CheckoutSHA string `json:"checkout_sha"`
|
||||
UserID int `json:"user_id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
UserEmail string `json:"user_email"`
|
||||
UserAvatar string `json:"user_avatar"`
|
||||
ProjectID int `json:"project_id"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
Project Project `json:"Project"`
|
||||
Repository Repository `json:"repository"`
|
||||
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
|
||||
@@ -72,14 +83,14 @@ type TagEventPayload struct {
|
||||
After string `json:"after"`
|
||||
Ref string `json:"ref"`
|
||||
CheckoutSHA string `json:"checkout_sha"`
|
||||
UserID int `json:"user_id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
UserAvatar string `json:"user_avatar"`
|
||||
ProjectID int `json:"project_id"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
Project Project `json:"Project"`
|
||||
Repository Repository `json:"repository"`
|
||||
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
|
||||
@@ -105,7 +116,7 @@ type PipelineEventPayload struct {
|
||||
type CommentEventPayload struct {
|
||||
ObjectKind string `json:"object_kind"`
|
||||
User User `json:"user"`
|
||||
ProjectID int `json:"project_id"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
Project Project `json:"project"`
|
||||
Repository Repository `json:"repository"`
|
||||
ObjectAttributes ObjectAttributes `json:"object_attributes"`
|
||||
@@ -122,41 +133,41 @@ type BuildEventPayload struct {
|
||||
Tag bool `json:"tag"`
|
||||
BeforeSHA string `json:"before_sha"`
|
||||
SHA string `json:"sha"`
|
||||
BuildID int `json:"build_id"`
|
||||
BuildID int64 `json:"build_id"`
|
||||
BuildName string `json:"build_name"`
|
||||
BuildStage string `json:"build_stage"`
|
||||
BuildStatus string `json:"build_status"`
|
||||
BuildStartedAt customTime `json:"build_started_at"`
|
||||
BuildFinishedAt customTime `json:"build_finished_at"`
|
||||
BuildDuration int `json:"build_duration"`
|
||||
BuildDuration int64 `json:"build_duration"`
|
||||
BuildAllowFailure bool `json:"build_allow_failure"`
|
||||
ProjectID int `json:"project_id"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
ProjectName string `json:"project_name"`
|
||||
User User `json:"user"`
|
||||
Commit BuildCommit `json:"commit"`
|
||||
Repository Repository `json:"repository"`
|
||||
}
|
||||
|
||||
// Issue contais all of the GitLab issue information
|
||||
// Issue contains all of the GitLab issue information
|
||||
type Issue struct {
|
||||
ID int `json:"id"`
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
AssigneeID int `json:"assignee_id"`
|
||||
AuthorID int `json:"author_id"`
|
||||
ProjectID int `json:"project_id"`
|
||||
AssigneeID int64 `json:"assignee_id"`
|
||||
AuthorID int64 `json:"author_id"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
CreatedAt customTime `json:"created_at"`
|
||||
UpdatedAt customTime `json:"updated_at"`
|
||||
Position int `json:"position"`
|
||||
Position int64 `json:"position"`
|
||||
BranchName string `json:"branch_name"`
|
||||
Description string `json:"description"`
|
||||
MilestoneID int `json:"milestone_id"`
|
||||
MilestoneID int64 `json:"milestone_id"`
|
||||
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 {
|
||||
ID int `json:"id"`
|
||||
ID int64 `json:"id"`
|
||||
Stage string `json:"stage"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
@@ -170,13 +181,13 @@ type Build struct {
|
||||
ArtifactsFile ArtifactsFile `json:"artifactsfile"`
|
||||
}
|
||||
|
||||
// ArtifactsFile contais all of the GitLab artifact information
|
||||
// ArtifactsFile contains all of the GitLab artifact information
|
||||
type ArtifactsFile struct {
|
||||
Filename string `json:"filename"`
|
||||
Size string `json:"size"`
|
||||
}
|
||||
|
||||
// Wiki contais all of the GitLab wiki information
|
||||
// Wiki contains all of the GitLab wiki information
|
||||
type Wiki struct {
|
||||
WebURL string `json:"web_url"`
|
||||
GitSSHURL string `json:"git_ssh_url"`
|
||||
@@ -185,7 +196,7 @@ type Wiki struct {
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
}
|
||||
|
||||
// Commit contais all of the GitLab commit information
|
||||
// Commit contains all of the GitLab commit information
|
||||
type Commit struct {
|
||||
ID string `json:"id"`
|
||||
Message string `json:"message"`
|
||||
@@ -197,42 +208,42 @@ type Commit struct {
|
||||
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 {
|
||||
ID int `json:"id"`
|
||||
ID int64 `json:"id"`
|
||||
SHA string `json:"sha"`
|
||||
Message string `json:"message"`
|
||||
AuthorName string `json:"auuthor_name"`
|
||||
AuthorEmail string `json:"author_email"`
|
||||
Status string `json:"status"`
|
||||
Duration int `json:"duration"`
|
||||
Duration int64 `json:"duration"`
|
||||
StartedAt customTime `json:"started_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 {
|
||||
ID int `json:"id"`
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
AuthorID int `json:"author_id"`
|
||||
ProjectID int `json:"project_id"`
|
||||
AuthorID int64 `json:"author_id"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
CreatedAt customTime `json:"created_at"`
|
||||
UpdatedAt customTime `json:"updated_at"`
|
||||
FileName string `json:"file_name"`
|
||||
ExpiresAt customTime `json:"expires_at"`
|
||||
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 {
|
||||
Name string `json:"name"`
|
||||
UserName string `json:"username"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
}
|
||||
|
||||
// Project contais all of the GitLab project information
|
||||
// Project contains all of the GitLab project information
|
||||
type Project struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
@@ -241,7 +252,7 @@ type Project struct {
|
||||
GitSSSHURL string `json:"git_ssh_url"`
|
||||
GitHTTPURL string `json:"git_http_url"`
|
||||
Namespace string `json:"namespace"`
|
||||
VisibilityLevel int `json:"visibility_level"`
|
||||
VisibilityLevel int64 `json:"visibility_level"`
|
||||
PathWithNamespace string `json:"path_with_namespace"`
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
Homepage string `json:"homepage"`
|
||||
@@ -250,7 +261,7 @@ type Project struct {
|
||||
HTTPURL string `json:"http_url"`
|
||||
}
|
||||
|
||||
// Repository contais all of the GitLab repository information
|
||||
// Repository contains all of the GitLab repository information
|
||||
type Repository struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
@@ -258,27 +269,27 @@ type Repository struct {
|
||||
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 {
|
||||
ID int `json:"id"`
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
AssigneeID int `json:"assignee_id"`
|
||||
AuthorID int `json:"author_id"`
|
||||
ProjectID int `json:"project_id"`
|
||||
AssigneeID int64 `json:"assignee_id"`
|
||||
AuthorID int64 `json:"author_id"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
CreatedAt customTime `json:"created_at"`
|
||||
UpdatedAt customTime `json:"updated_at"`
|
||||
Position int `json:"position"`
|
||||
Position int64 `json:"position"`
|
||||
BranchName string `json:"branch_name"`
|
||||
Description string `json:"description"`
|
||||
MilestoneID int `json:"milestone_id"`
|
||||
MilestoneID int64 `json:"milestone_id"`
|
||||
State string `json:"state"`
|
||||
IID int `json:"iid"`
|
||||
IID int64 `json:"iid"`
|
||||
URL string `json:"url"`
|
||||
Action string `json:"action"`
|
||||
TargetBranch string `json:"target_branch"`
|
||||
SourceBranch string `json:"source_branch"`
|
||||
SourceProjectID int `json:"source_project_id"`
|
||||
TargetProjectID int `json:"target_project_id"`
|
||||
SourceProjectID int64 `json:"source_project_id"`
|
||||
TargetProjectID int64 `json:"target_project_id"`
|
||||
StCommits string `json:"st_commits"`
|
||||
MergeStatus string `json:"merge_status"`
|
||||
Content string `json:"content"`
|
||||
@@ -291,13 +302,13 @@ type ObjectAttributes struct {
|
||||
BeforeSHA string `json:"before_sha"`
|
||||
Status string `json:"status"`
|
||||
Stages []string `json:"stages"`
|
||||
Duration int `json:"duration"`
|
||||
Duration int64 `json:"duration"`
|
||||
Note string `json:"note"`
|
||||
NotebookType string `json:"noteable_type"`
|
||||
At customTime `json:"attachment"`
|
||||
LineCode string `json:"line_code"`
|
||||
CommitID string `json:"commit_id"`
|
||||
NoteableID int `json:"noteable_id"`
|
||||
NoteableID int64 `json:"noteable_id"`
|
||||
System bool `json:"system"`
|
||||
WorkInProgress bool `json:"work_in_progress"`
|
||||
StDiffs []StDiff `json:"st_diffs"`
|
||||
@@ -307,24 +318,24 @@ type ObjectAttributes struct {
|
||||
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 {
|
||||
ID int `json:"id"`
|
||||
ID int64 `json:"id"`
|
||||
TargetBranch string `json:"target_branch"`
|
||||
SourceBranch string `json:"source_branch"`
|
||||
SourceProjectID string `json:"source_project_id"`
|
||||
AssigneeID int `json:"assignee_id"`
|
||||
AuthorID int `json:"author_id"`
|
||||
SourceProjectID int64 `json:"source_project_id"`
|
||||
AssigneeID int64 `json:"assignee_id"`
|
||||
AuthorID int64 `json:"author_id"`
|
||||
Title string `json:"title"`
|
||||
CreatedAt customTime `json:"created_at"`
|
||||
UpdatedAt customTime `json:"updated_at"`
|
||||
MilestoneID int `json:"milestone_id"`
|
||||
MilestoneID int64 `json:"milestone_id"`
|
||||
State string `json:"state"`
|
||||
MergeStatus string `json:"merge_status"`
|
||||
TargetProjectID int `json:"target_project_id"`
|
||||
IID int `json:"iid"`
|
||||
TargetProjectID int64 `json:"target_project_id"`
|
||||
IID int64 `json:"iid"`
|
||||
Description string `json:"description"`
|
||||
Position int `json:"position"`
|
||||
Position int64 `json:"position"`
|
||||
LockedAt customTime `json:"locked_at"`
|
||||
Source Source `json:"source"`
|
||||
Target Target `json:"target"`
|
||||
@@ -333,14 +344,14 @@ type MergeRequest struct {
|
||||
Assignee Assignee `json:"assignee"`
|
||||
}
|
||||
|
||||
// Assignee contais all of the GitLab assignee information
|
||||
// Assignee contains all of the GitLab assignee information
|
||||
type Assignee struct {
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
}
|
||||
|
||||
// StDiff contais all of the GitLab diff information
|
||||
// StDiff contains all of the GitLab diff information
|
||||
type StDiff struct {
|
||||
Diff string `json:"diff"`
|
||||
NewPath string `json:"new_path"`
|
||||
@@ -352,7 +363,7 @@ type StDiff struct {
|
||||
DeletedFile bool `json:"deleted_file"`
|
||||
}
|
||||
|
||||
// Source contais all of the GitLab source information
|
||||
// Source contains all of the GitLab source information
|
||||
type Source struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
@@ -361,7 +372,7 @@ type Source struct {
|
||||
GitSSHURL string `json:"git_ssh_url"`
|
||||
GitHTTPURL string `json:"git_http_url"`
|
||||
Namespace string `json:"namespace"`
|
||||
VisibilityLevel int `json:"visibility_level"`
|
||||
VisibilityLevel int64 `json:"visibility_level"`
|
||||
PathWithNamespace string `json:"path_with_namespace"`
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
Homepage string `json:"homepage"`
|
||||
@@ -370,7 +381,7 @@ type Source struct {
|
||||
HTTPURL string `json:"http_url"`
|
||||
}
|
||||
|
||||
// Target contais all of the GitLab target information
|
||||
// Target contains all of the GitLab target information
|
||||
type Target struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
@@ -379,7 +390,7 @@ type Target struct {
|
||||
GitSSHURL string `json:"git_ssh_url"`
|
||||
GitHTTPURL string `json:"git_http_url"`
|
||||
Namespace string `json:"namespace"`
|
||||
VisibilityLevel int `json:"visibility_level"`
|
||||
VisibilityLevel int64 `json:"visibility_level"`
|
||||
PathWithNamespace string `json:"path_with_namespace"`
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
Homepage string `json:"homepage"`
|
||||
@@ -388,7 +399,7 @@ type Target struct {
|
||||
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 {
|
||||
ID string `json:"id"`
|
||||
Message string `json:"message"`
|
||||
@@ -397,8 +408,33 @@ type LastCommit struct {
|
||||
Author Author `json:"author"`
|
||||
}
|
||||
|
||||
// Author contais all of the GitLab author information
|
||||
// Author contains all of the GitLab author information
|
||||
type Author struct {
|
||||
Name string `json:"name"`
|
||||
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
@@ -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)
|
||||
}
|
||||
@@ -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
@@ -1,6 +1,9 @@
|
||||
package webhooks
|
||||
|
||||
import "net/http"
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Header provides http.Header to minimize imports
|
||||
type Header http.Header
|
||||
@@ -16,6 +19,8 @@ func (p Provider) String() string {
|
||||
return "Bitbucket"
|
||||
case GitLab:
|
||||
return "GitLab"
|
||||
case Gogs:
|
||||
return "Gogs"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
@@ -26,31 +31,41 @@ const (
|
||||
GitHub Provider = iota
|
||||
Bitbucket
|
||||
GitLab
|
||||
Gogs
|
||||
)
|
||||
|
||||
// Webhook interface defines a webhook to recieve events
|
||||
// Webhook interface defines a webhook to receive events
|
||||
type Webhook interface {
|
||||
Provider() Provider
|
||||
ParsePayload(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
type server struct {
|
||||
hook Webhook
|
||||
path string
|
||||
hook Webhook
|
||||
path string
|
||||
includePathCheck bool
|
||||
}
|
||||
|
||||
// ProcessPayloadFunc is a common function for payload return values
|
||||
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
|
||||
func Run(hook Webhook, addr string, path string) error {
|
||||
srv := &server{
|
||||
hook: hook,
|
||||
path: path,
|
||||
hook: hook,
|
||||
path: path,
|
||||
includePathCheck: true,
|
||||
}
|
||||
|
||||
s := &http.Server{Addr: addr, Handler: srv}
|
||||
|
||||
DefaultLog.Info(fmt.Sprintf("Listening on addr: %s path: %s", addr, path))
|
||||
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 {
|
||||
|
||||
srv := &server{
|
||||
hook: hook,
|
||||
path: path,
|
||||
hook: hook,
|
||||
path: path,
|
||||
includePathCheck: true,
|
||||
}
|
||||
|
||||
s.Handler = srv
|
||||
|
||||
DefaultLog.Info(fmt.Sprintf("Listening on addr: %s path: %s", s.Addr, path))
|
||||
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 {
|
||||
|
||||
srv := &server{
|
||||
hook: hook,
|
||||
path: path,
|
||||
hook: hook,
|
||||
path: path,
|
||||
includePathCheck: true,
|
||||
}
|
||||
|
||||
s.Handler = srv
|
||||
|
||||
DefaultLog.Info(fmt.Sprintf("Listening on addr: %s path: %s", s.Addr, path))
|
||||
return s.ListenAndServeTLS("", "")
|
||||
}
|
||||
|
||||
// ServeHTTP is the Handler for every posted WebHook Event
|
||||
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
DefaultLog.Info("Webhook received")
|
||||
|
||||
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)
|
||||
return
|
||||
}
|
||||
if r.URL.Path != s.path {
|
||||
http.Error(w, "404 Not found", http.StatusNotFound)
|
||||
return
|
||||
|
||||
DefaultLog.Debug(fmt.Sprintf("Include path check: %t", s.includePathCheck))
|
||||
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)
|
||||
|
||||
+40
-1
@@ -8,6 +8,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"net/http/httptest"
|
||||
|
||||
. "gopkg.in/go-playground/assert.v1"
|
||||
)
|
||||
|
||||
@@ -47,6 +49,43 @@ func TestMain(m *testing.M) {
|
||||
// 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) {
|
||||
|
||||
go Run(fakeHook, "127.0.0.1:3006", "/webhooks")
|
||||
@@ -97,7 +136,7 @@ func TestRun(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRunServer(t *testing.T) {
|
||||
|
||||
DefaultLog = NewLogger(true)
|
||||
server := &http.Server{Addr: "127.0.0.1:3007", Handler: nil}
|
||||
go RunServer(server, fakeHook, "/webhooks")
|
||||
time.Sleep(5000)
|
||||
|
||||
Reference in New Issue
Block a user