Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Add gitea webhook
  • Loading branch information
pongsatt committed Jun 14, 2019
commit d3005182e72ce3db755fc0e1fff0072c6a81ff2e
33 changes: 16 additions & 17 deletions gitea/gitea.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,17 @@ import (
"io/ioutil"
"net/http"

models "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/structs"
)

// parse errors
var (
ErrEventNotSpecifiedToParse = errors.New("no Event specified to parse")
ErrInvalidHTTPMethod = errors.New("invalid HTTP Method")
ErrMissingGiteaEventHeader = errors.New("missing X-Gitea-Event Header")
ErrMissingGiteaSignatureHeader = errors.New("missing X-Gitea-Signature Header")
ErrEventNotFound = errors.New("event not defined to be parsed")
ErrParsingPayload = errors.New("error parsing payload")
ErrHMACVerificationFailed = errors.New("HMAC verification failed")
ErrEventNotSpecifiedToParse = errors.New("no Event specified to parse")
ErrInvalidHTTPMethod = errors.New("invalid HTTP Method")
ErrMissingGiteaEventHeader = errors.New("missing X-Gitea-Event Header")
ErrEventNotFound = errors.New("event not defined to be parsed")
ErrParsingPayload = errors.New("error parsing payload")
ErrSecretNotMatch = errors.New("secret not match")
)

// Option is a configuration option for the webhook
Expand Down Expand Up @@ -72,7 +71,7 @@ func New(options ...Option) (*Webhook, error) {

func (hook Webhook) verifySecret(secret string) error {
if len(hook.secret) > 0 && hook.secret != secret {
return fmt.Errorf("secret %s not match", secret)
return ErrSecretNotMatch
}

return nil
Expand Down Expand Up @@ -118,7 +117,7 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)

switch giteaEvent {
case CreateEvent:
var pl models.CreatePayload
var pl structs.CreatePayload
err = json.Unmarshal([]byte(payload), &pl)

if err == nil {
Expand All @@ -128,7 +127,7 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
return pl, err

case ReleaseEvent:
var pl models.ReleasePayload
var pl structs.ReleasePayload
err = json.Unmarshal([]byte(payload), &pl)

if err == nil {
Expand All @@ -138,7 +137,7 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
return pl, err

case PushEvent:
var pl models.PushPayload
var pl structs.PushPayload
err = json.Unmarshal([]byte(payload), &pl)

if err == nil {
Expand All @@ -148,7 +147,7 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
return pl, err

case DeleteEvent:
var pl models.DeletePayload
var pl structs.DeletePayload
err = json.Unmarshal([]byte(payload), &pl)

if err == nil {
Expand All @@ -158,7 +157,7 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
return pl, err

case ForkEvent:
var pl models.ForkPayload
var pl structs.ForkPayload
err = json.Unmarshal([]byte(payload), &pl)

if err == nil {
Expand All @@ -168,7 +167,7 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
return pl, err

case IssuesEvent:
var pl models.IssuePayload
var pl structs.IssuePayload
err = json.Unmarshal([]byte(payload), &pl)

if err == nil {
Expand All @@ -178,7 +177,7 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
return pl, err

case IssueCommentEvent:
var pl models.IssueCommentPayload
var pl structs.IssueCommentPayload
err = json.Unmarshal([]byte(payload), &pl)

if err == nil {
Expand All @@ -188,7 +187,7 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
return pl, err

case PullRequestEvent:
var pl models.PullRequestPayload
var pl structs.PullRequestPayload
err = json.Unmarshal([]byte(payload), &pl)

if err == nil {
Expand Down
174 changes: 174 additions & 0 deletions gitea/gitea_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package gitea_test

import (
"bytes"
"io"
"net/http"
"net/http/httptest"
"os"
"reflect"
"testing"

"code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/require"
"gopkg.in/go-playground/webhooks.v5/gitea"
)

const (
path = "/webhooks"
)

func newServer(handler http.HandlerFunc) *httptest.Server {
mux := http.NewServeMux()
mux.HandleFunc(path, handler)
return httptest.NewServer(mux)
}

func TestWebhooks(t *testing.T) {
assert := require.New(t)
tests := []struct {
name string
event gitea.Event
typ interface{}
filename string
headers http.Header
}{
{
name: "PushEvent",
event: gitea.PushEvent,
typ: structs.PushPayload{},
filename: "../testdata/gitea/push-event.json",
headers: http.Header{
"X-Gitea-Event": []string{"push"},
},
},
}

hook, _ := gitea.New(gitea.Options.Secret("mytoken"))

for _, tt := range tests {
tc := tt
client := &http.Client{}
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
payload, err := os.Open(tc.filename)
assert.NoError(err)
defer func() {
_ = payload.Close()
}()

var parseError error
var results interface{}
server := newServer(func(w http.ResponseWriter, r *http.Request) {
results, parseError = hook.Parse(r, tc.event)
})
defer server.Close()
req, err := http.NewRequest(http.MethodPost, server.URL+path, payload)
assert.NoError(err)
req.Header = tc.headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitea-Token", "mytoken")

resp, err := client.Do(req)
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
assert.NoError(parseError)
assert.Equal(reflect.TypeOf(tc.typ), reflect.TypeOf(results))
})
}
}

func TestBadRequests(t *testing.T) {
assert := require.New(t)
tests := []struct {
name string
event gitea.Event
payload io.Reader
headers http.Header
method string
expcectedError error
}{
{
name: "ErrEventNotSpecifiedToParse",
event: "",
method: http.MethodPost,
payload: bytes.NewBuffer([]byte("{}")),
headers: http.Header{},
expcectedError: gitea.ErrEventNotSpecifiedToParse,
},
{
name: "ErrInvalidHTTPMethod",
event: gitea.PushEvent,
method: http.MethodGet,
payload: bytes.NewBuffer([]byte("{}")),
headers: http.Header{},
expcectedError: gitea.ErrInvalidHTTPMethod,
},
{
name: "ErrMissingGiteaEventHeader",
event: gitea.PushEvent,
method: http.MethodPost,
payload: bytes.NewBuffer([]byte("{}")),
headers: http.Header{},
expcectedError: gitea.ErrMissingGiteaEventHeader,
},
{
name: "ErrEventNotFound",
event: gitea.PushEvent,
method: http.MethodPost,
payload: bytes.NewBuffer([]byte("{}")),
headers: http.Header{
"X-Gitea-Event": []string{"create"},
},
expcectedError: gitea.ErrEventNotFound,
},
{
name: "ErrParsingPayload",
event: gitea.PushEvent,
method: http.MethodPost,
payload: bytes.NewBuffer([]byte("")),
headers: http.Header{
"X-Gitea-Event": []string{"push"},
},
expcectedError: gitea.ErrParsingPayload,
},
{
name: "ErrSecretNotMatch",
event: gitea.PushEvent,
method: http.MethodPost,
payload: bytes.NewBuffer([]byte("{\"secret\":\"test\"}")),
headers: http.Header{
"X-Gitea-Event": []string{"push"},
},
expcectedError: gitea.ErrSecretNotMatch,
},
}

hook, _ := gitea.New(gitea.Options.Secret("mytoken"))

for _, tt := range tests {
tc := tt
client := &http.Client{}
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var parseError error
server := newServer(func(w http.ResponseWriter, r *http.Request) {
if tc.event != "" {
_, parseError = hook.Parse(r, tc.event)
} else {
_, parseError = hook.Parse(r)
}
})
defer server.Close()
req, err := http.NewRequest(tc.method, server.URL+path, tc.payload)
assert.NoError(err)
req.Header = tc.headers
req.Header.Set("Content-Type", "application/json")

resp, err := client.Do(req)
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
assert.Equal(tc.expcectedError, parseError)
})
}
}
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pongsatt/webhooks v5.11.0+incompatible h1:em6nJiHEUFHWlgD1xcJuTTAVh4yXyAhYE6rJJ18jofs=
github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e h1:ApqncJ84HYN8x8x5WV1T1YWDuPRF/0aXZhr91LnRMCQ=
github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk=
github.com/prometheus/client_golang v0.9.0 h1:tXuTFVHC03mW0D+Ua1Q2d1EAVqLTuggX50V0VLICCzY=
Expand Down
82 changes: 82 additions & 0 deletions testdata/gitea/push-event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"secret": "mytoken",
"ref": "refs/heads/master",
"before": "d6f4a1b021308a40937e8d565698945c3cdfe1ec",
"after": "d6f4a1b021308a40937e8d565698945c3cdfe1ec",
"compare_url": "",
"commits": [
{
"id": "d6f4a1b021308a40937e8d565698945c3cdfe1ec",
"message": "init\n",
"url": "https://git.test.com/testrepo/commit/d6f4a1b021308a40937e8d565698945c3cdfe1ec",
"author": {
"name": "example",
"email": "[email protected]",
"username": ""
},
"committer": {
"name": "example",
"email": "[email protected]",
"username": ""
},
"verification": null,
"timestamp": "0001-01-01T00:00:00Z"
}
],
"repository": {
"id": 2,
"owner": {
"id": 1,
"login": "example",
"full_name": "",
"email": "[email protected]",
"avatar_url": "https://secure.gravatar.com/avatar/asdfasfsafd?d=identicon",
"language": "en-US",
"username": "example"
},
"name": "testrepo",
"full_name": "example/testrepo",
"description": "",
"empty": false,
"private": false,
"fork": false,
"parent": null,
"mirror": false,
"size": 12,
"html_url": "https://git.test.com/testrepo",
"ssh_url": "[email protected]:example/testrepo.git",
"clone_url": "https://git.test.com/testrepo.git",
"website": "",
"stars_count": 0,
"forks_count": 0,
"watchers_count": 1,
"open_issues_count": 0,
"default_branch": "master",
"archived": false,
"created_at": "2019-06-08T02:17:50Z",
"updated_at": "2019-06-09T10:43:22Z",
"permissions": {
"admin": false,
"push": false,
"pull": false
}
},
"pusher": {
"id": 1,
"login": "example",
"full_name": "",
"email": "[email protected]",
"avatar_url": "https://secure.gravatar.com/avatar/asdfasfsafd?d=identicon",
"language": "en-US",
"username": "example"
},
"sender": {
"id": 1,
"login": "example",
"full_name": "",
"email": "[email protected]",
"avatar_url": "https://secure.gravatar.com/avatar/asdfasfsafd?d=identicon",
"language": "en-US",
"username": "example"
}
}