mirror of
https://github.com/adnanh/webhook.git
synced 2025-05-13 17:14:44 +00:00
Merge pull request #143 from wrouesnel/yaml-decoding
Use the github.com/ghodss/yaml library to unserialize webhooks.
This commit is contained in:
commit
c19e514ee9
5 changed files with 158 additions and 48 deletions
|
@ -15,6 +15,8 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ghodss/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Constants used to specify the parameter source
|
// Constants used to specify the parameter source
|
||||||
|
@ -503,7 +505,7 @@ func (h *Hooks) LoadFromFile(path string) error {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
e = json.Unmarshal(file, h)
|
e = yaml.Unmarshal(file, h)
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -233,6 +233,7 @@ var hooksLoadFromFileTests = []struct {
|
||||||
ok bool
|
ok bool
|
||||||
}{
|
}{
|
||||||
{"../hooks.json.example", true},
|
{"../hooks.json.example", true},
|
||||||
|
{"../hooks.yaml.example", true},
|
||||||
{"", true},
|
{"", true},
|
||||||
// failures
|
// failures
|
||||||
{"missing.json", false},
|
{"missing.json", false},
|
||||||
|
|
28
hooks.yaml.example
Normal file
28
hooks.yaml.example
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
- id: webhook
|
||||||
|
execute-command: /home/adnan/redeploy-go-webhook.sh
|
||||||
|
command-working-directory: /home/adnan/go
|
||||||
|
response-message: I got the payload!
|
||||||
|
response-headers:
|
||||||
|
- name: Access-Control-Allow-Origin
|
||||||
|
value: '*'
|
||||||
|
pass-arguments-to-command:
|
||||||
|
- source: payload
|
||||||
|
name: head_commit.id
|
||||||
|
- source: payload
|
||||||
|
name: pusher.name
|
||||||
|
- source: payload
|
||||||
|
name: pusher.email
|
||||||
|
trigger-rule:
|
||||||
|
and:
|
||||||
|
- match:
|
||||||
|
type: payload-hash-sha1
|
||||||
|
secret: mysecret
|
||||||
|
parameter:
|
||||||
|
source: header
|
||||||
|
name: X-Hub-Signature
|
||||||
|
- match:
|
||||||
|
type: value
|
||||||
|
value: refs/heads/master
|
||||||
|
parameter:
|
||||||
|
source: payload
|
||||||
|
name: ref
|
75
test/hooks.yaml.tmpl
Normal file
75
test/hooks.yaml.tmpl
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
- trigger-rule:
|
||||||
|
and:
|
||||||
|
- match:
|
||||||
|
parameter:
|
||||||
|
source: header
|
||||||
|
name: X-Hub-Signature
|
||||||
|
secret: mysecret
|
||||||
|
type: payload-hash-sha1
|
||||||
|
- match:
|
||||||
|
parameter:
|
||||||
|
source: payload
|
||||||
|
name: ref
|
||||||
|
type: value
|
||||||
|
value: refs/heads/master
|
||||||
|
include-command-output-in-response: true
|
||||||
|
trigger-rule-mismatch-http-response-code: 400
|
||||||
|
execute-command: '{{ .Hookecho }}'
|
||||||
|
pass-arguments-to-command:
|
||||||
|
- source: payload
|
||||||
|
name: head_commit.id
|
||||||
|
- source: payload
|
||||||
|
name: head_commit.author.email
|
||||||
|
pass-environment-to-command:
|
||||||
|
- source: payload
|
||||||
|
name: head_commit.timestamp
|
||||||
|
id: github
|
||||||
|
command-working-directory: /
|
||||||
|
- trigger-rule:
|
||||||
|
and:
|
||||||
|
- match:
|
||||||
|
parameter:
|
||||||
|
source: payload
|
||||||
|
name: payload.canon_url
|
||||||
|
type: value
|
||||||
|
value: https://bitbucket.org
|
||||||
|
- match:
|
||||||
|
parameter:
|
||||||
|
source: payload
|
||||||
|
name: payload.repository.absolute_url
|
||||||
|
type: value
|
||||||
|
value: /webhook/testing/
|
||||||
|
- match:
|
||||||
|
parameter:
|
||||||
|
source: payload
|
||||||
|
name: payload.commits.0.branch
|
||||||
|
type: value
|
||||||
|
value: master
|
||||||
|
parse-parameters-as-json:
|
||||||
|
- source: payload
|
||||||
|
name: payload
|
||||||
|
trigger-rule-mismatch-http-response-code: 999
|
||||||
|
execute-command: '{{ .Hookecho }}'
|
||||||
|
response-message: success
|
||||||
|
include-command-output-in-response: false
|
||||||
|
id: bitbucket
|
||||||
|
command-working-directory: /
|
||||||
|
- trigger-rule:
|
||||||
|
match:
|
||||||
|
parameter:
|
||||||
|
source: payload
|
||||||
|
name: ref
|
||||||
|
type: value
|
||||||
|
value: refs/heads/master
|
||||||
|
pass-arguments-to-command:
|
||||||
|
- source: payload
|
||||||
|
name: commits.0.id
|
||||||
|
- source: payload
|
||||||
|
name: user_name
|
||||||
|
- source: payload
|
||||||
|
name: user_email
|
||||||
|
execute-command: '{{ .Hookecho }}'
|
||||||
|
response-message: success
|
||||||
|
include-command-output-in-response: true
|
||||||
|
id: gitlab
|
||||||
|
command-working-directory: /
|
|
@ -21,60 +21,62 @@ func TestWebhook(t *testing.T) {
|
||||||
hookecho, cleanupHookecho := buildHookecho(t)
|
hookecho, cleanupHookecho := buildHookecho(t)
|
||||||
defer cleanupHookecho()
|
defer cleanupHookecho()
|
||||||
|
|
||||||
config, cleanupConfig := genConfig(t, hookecho)
|
for _, hookTmpl := range []string{"test/hooks.json.tmpl", "test/hooks.yaml.tmpl"} {
|
||||||
defer cleanupConfig()
|
config, cleanupConfig := genConfig(t, hookecho, hookTmpl)
|
||||||
|
defer cleanupConfig()
|
||||||
|
|
||||||
webhook, cleanupWebhook := buildWebhook(t)
|
webhook, cleanupWebhook := buildWebhook(t)
|
||||||
defer cleanupWebhook()
|
defer cleanupWebhook()
|
||||||
|
|
||||||
ip, port := serverAddress(t)
|
ip, port := serverAddress(t)
|
||||||
args := []string{fmt.Sprintf("-hooks=%s", config), fmt.Sprintf("-ip=%s", ip), fmt.Sprintf("-port=%s", port), "-verbose"}
|
args := []string{fmt.Sprintf("-hooks=%s", config), fmt.Sprintf("-ip=%s", ip), fmt.Sprintf("-port=%s", port), "-verbose"}
|
||||||
|
|
||||||
cmd := exec.Command(webhook, args...)
|
cmd := exec.Command(webhook, args...)
|
||||||
//cmd.Stderr = os.Stderr // uncomment to see verbose output
|
//cmd.Stderr = os.Stderr // uncomment to see verbose output
|
||||||
cmd.Env = webhookEnv()
|
cmd.Env = webhookEnv()
|
||||||
cmd.Args[0] = "webhook"
|
cmd.Args[0] = "webhook"
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
t.Fatalf("failed to start webhook: %s", err)
|
t.Fatalf("failed to start webhook: %s", err)
|
||||||
}
|
|
||||||
defer killAndWait(cmd)
|
|
||||||
|
|
||||||
waitForServerReady(t, ip, port)
|
|
||||||
|
|
||||||
for _, tt := range hookHandlerTests {
|
|
||||||
url := fmt.Sprintf("http://%s:%s/hooks/%s", ip, port, tt.id)
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", url, ioutil.NopCloser(strings.NewReader(tt.body)))
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("New request failed: %s", err)
|
|
||||||
}
|
}
|
||||||
|
defer killAndWait(cmd)
|
||||||
|
|
||||||
for k, v := range tt.headers {
|
waitForServerReady(t, ip, port)
|
||||||
req.Header.Add(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
var res *http.Response
|
for _, tt := range hookHandlerTests {
|
||||||
|
url := fmt.Sprintf("http://%s:%s/hooks/%s", ip, port, tt.id)
|
||||||
|
|
||||||
if tt.urlencoded == true {
|
req, err := http.NewRequest("POST", url, ioutil.NopCloser(strings.NewReader(tt.body)))
|
||||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
if err != nil {
|
||||||
} else {
|
t.Errorf("New request failed: %s", err)
|
||||||
req.Header.Add("Content-Type", "application/json")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
client := &http.Client{}
|
for k, v := range tt.headers {
|
||||||
res, err = client.Do(req)
|
req.Header.Add(k, v)
|
||||||
if err != nil {
|
}
|
||||||
t.Errorf("client.Do failed: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
var res *http.Response
|
||||||
res.Body.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("POST %q: failed to ready body: %s", tt.desc, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.StatusCode != tt.respStatus || string(body) != tt.respBody {
|
if tt.urlencoded == true {
|
||||||
t.Errorf("failed %q (id: %s):\nexpected status: %#v, response: %s\ngot status: %#v, response: %s", tt.desc, tt.id, tt.respStatus, tt.respBody, res.StatusCode, body)
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
} else {
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
res, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("client.Do failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("POST %q: failed to ready body: %s", tt.desc, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode != tt.respStatus || string(body) != tt.respBody {
|
||||||
|
t.Errorf("failed %q (id: %s):\nexpected status: %#v, response: %s\ngot status: %#v, response: %s", tt.desc, tt.id, tt.respStatus, tt.respBody, res.StatusCode, body)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,8 +105,8 @@ func buildHookecho(t *testing.T) (bin string, cleanup func()) {
|
||||||
return bin, func() { os.RemoveAll(tmp) }
|
return bin, func() { os.RemoveAll(tmp) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func genConfig(t *testing.T, bin string) (config string, cleanup func()) {
|
func genConfig(t *testing.T, bin string, hookTemplate string) (config string, cleanup func()) {
|
||||||
tmpl := template.Must(template.ParseFiles("test/hooks.json.tmpl"))
|
tmpl := template.Must(template.ParseFiles(hookTemplate))
|
||||||
|
|
||||||
tmp, err := ioutil.TempDir("", "webhook-config-")
|
tmp, err := ioutil.TempDir("", "webhook-config-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -116,7 +118,9 @@ func genConfig(t *testing.T, bin string) (config string, cleanup func()) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
path := filepath.Join(tmp, "hooks.json")
|
outputBaseName := filepath.Ext(filepath.Ext(hookTemplate))
|
||||||
|
|
||||||
|
path := filepath.Join(tmp, outputBaseName)
|
||||||
file, err := os.Create(path)
|
file, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Creating config template: %v", err)
|
t.Fatalf("Creating config template: %v", err)
|
||||||
|
|
Loading…
Add table
Reference in a new issue