Skip to content

Commit

Permalink
Merge pull request #93 from overcat/master
Browse files Browse the repository at this point in the history
Add support for gitee.com webhook
  • Loading branch information
abiosoft committed Sep 12, 2018
2 parents 3ea4951 + 1f4cd72 commit 1a56540
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -69,6 +69,7 @@ Note that because the hook URL is used as an API endpoint, you shouldn't have an
* [bitbucket](https://bitbucket.org)
* [travis](https://travis-ci.org)
* [gogs](https://gogs.io)
* [gitee](https://gitee.com)
* generic

## Examples
Expand Down
108 changes: 108 additions & 0 deletions gitee_hook.go
@@ -0,0 +1,108 @@
package git

import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"
)

// GiteeHook is webhook for gitee.com
type GiteeHook struct{}

type giteePush struct {
Ref string `json:"ref"`
}

// DoesHandle satisfies hookHandler.
func (g GiteeHook) DoesHandle(h http.Header) bool {
event := h.Get("X-Gitee-Event")

// for Gitee you can use X-Gitee-Event header to test if you could handle the request
if event != "" {
return true
}
return false
}

// Handle satisfies hookHandler.
func (g GiteeHook) Handle(w http.ResponseWriter, r *http.Request, repo *Repo) (int, error) {
if r.Method != "POST" {
return http.StatusMethodNotAllowed, errors.New("the request had an invalid method")
}

body, err := ioutil.ReadAll(r.Body)
if err != nil {
return http.StatusRequestTimeout, errors.New("could not read body from request")
}

err = g.handleToken(r, body, repo.Hook.Secret)
if err != nil {
return http.StatusBadRequest, err
}

event := r.Header.Get("X-Gitee-Event")
if event == "" {
return http.StatusBadRequest, errors.New("the 'X-Gitee-Event' header is required but was missing")
}

switch event {
case "Push Hook":
err = g.handlePush(body, repo)
if !hookIgnored(err) && err != nil {
return http.StatusBadRequest, err
}

// return 400 if we do not handle the event type.
default:
return http.StatusBadRequest, nil
}

return http.StatusOK, err
}

// handleToken checks for an optional token in the request. Gitee's webhook tokens are just
// simple strings that get sent as a header with the hook request. If one
// exists, verify that it matches the secret in the Caddy configuration.
func (g GiteeHook) handleToken(r *http.Request, body []byte, secret string) error {
token := r.Header.Get("X-Gitee-Token")
if token != "" {
if secret == "" {
Logger().Print("Unable to verify request. Secret not set in caddyfile!\n")
} else {
if token != secret {
return errors.New("Unable to verify request. The token and specified secret do not match!")
}
}
}

return nil
}

func (g GiteeHook) handlePush(body []byte, repo *Repo) error {
var push giteePush

err := json.Unmarshal(body, &push)
if err != nil {
return err
}

// extract the branch being pushed from the ref string
// and if it matches with our locally tracked one, pull.
refSlice := strings.Split(push.Ref, "/")
if len(refSlice) != 3 {
return errors.New("the push request contained an invalid reference string")
}

branch := refSlice[2]
if branch != repo.Branch {
return hookIgnoredError{hookType: hookName(g), err: fmt.Errorf("found different branch %v", branch)}
}

Logger().Print("Received pull notification for the tracking branch, updating...\n")
repo.Pull()

return nil
}
61 changes: 61 additions & 0 deletions gitee_hook_test.go
@@ -0,0 +1,61 @@
package git

import (
"bytes"
"net/http"
"net/http/httptest"
"testing"
)

func TestGiteeDeployPush(t *testing.T) {
repo := &Repo{Branch: "master", Hook: HookConfig{URL: "/gitee_deploy"}}
glHook := GiteeHook{}

for i, test := range []struct {
body string
event string
responseBody string
code int
}{
{"", "", "", 400},
{"", "Push Hook", "", 400},
{pushGiteeBodyOther, "Push Hook", "", 200},
{pushGiteeBodyPartial, "Push Hook", "", 400},
{"", "Some other Event", "", 400},
} {

req, err := http.NewRequest("POST", "/gitee_deploy", bytes.NewBuffer([]byte(test.body)))
if err != nil {
t.Fatalf("Test %v: Could not create HTTP request: %v", i, err)
}

if test.event != "" {
req.Header.Add("X-Gitee-Event", test.event)
}

rec := httptest.NewRecorder()

code, err := glHook.Handle(rec, req, repo)

if code != test.code {
t.Errorf("Test %d: Expected response code to be %d but was %d", i, test.code, code)
}

if rec.Body.String() != test.responseBody {
t.Errorf("Test %d: Expected response body to be '%v' but was '%v'", i, test.responseBody, rec.Body.String())
}
}

}

var pushGiteeBodyPartial = `
{
"ref": ""
}
`

var pushGiteeBodyOther = `
{
"ref": "refs/heads/some-other-branch"
}
`
2 changes: 2 additions & 0 deletions webhook.go
Expand Up @@ -66,6 +66,7 @@ var handlers = map[string]hookHandler{
"generic": GenericHook{},
"travis": TravisHook{},
"gogs": GogsHook{},
"gitee": GiteeHook{},
}

// defaultHandlers is the list of handlers to choose from
Expand All @@ -76,6 +77,7 @@ var defaultHandlers = []string{
"bitbucket",
"travis",
"gogs",
"gitee",
}

// ServeHTTP implements the middlware.Handler interface.
Expand Down

0 comments on commit 1a56540

Please sign in to comment.