Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #93 from overcat/master
Add support for gitee.com webhook
- Loading branch information
Showing
4 changed files
with
172 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters