Merge pull request #2 from jackspirou/master
Adding auth and debug options.
This commit is contained in:
commit
38877a0a7c
|
@ -1 +1 @@
|
|||
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.Hsd15sfwSET0yXg92mosT1cs-1kiyW7VZlSZiWKkIu4EKDWnslBPZzbTKVi9OY4lXKJmXuAo38E3wtj5EvD7GA5azd090-Rnv-VOrQfXNmjZd9jxc7861IWQOFZb9XEDQZF6X2JM8fK_psSs6mrew9BjuOx6ws68h-zTl8ttcjHZC3Y7SZ5AjYj5i4T-Z0hJpLk2kwjCYF3SH599R3L3kZxDi6IcO9qW_Lj6zcBT5SttLgikUpvHwY409pbFBohl-AVhCZuDuyJPDns4n7jjWj4sELH4w-8dbc5oijzxI1FoxnUhXTRsrwNgfgCBAFM_umXGXLHAQlb2QzH2JHtB6g.rednhhAPc9V-KExp.qf0pSc_4pCgKIgK5T03yEmWz1yF5u2S0lSDBAvu7yOeCl469QBRIOxCv_RHImCG4tjOwYZjNaS8gaKVIoNNtxhKxC04Y2G7pxYDgNh2pU-sJOi05A1BaIbdIC209uK0r-mKkX_hfMDtNNWuOCyHXju4ugbNHwH64KvLzy4_RfFa0n9AOhpS1xNT3aa_eJvj0RQCfFs10BckWJoGlIfbS6VMyeeHeQEX6QWFSauxUwUPOAvrRlNjtNSxxVvNr1CbJso_8Cl0frD8DELaWxu3uKvLkSm2_GVMjPbvmZIqvcVxpxYnFMjwngQOAqnmiI-n_3LlO-dZb-Gf5AwN2F61PQDKXkdOcNiM4bNU_V11VKHP_BCJpVcaL6detQLNzHIuyU93zbw.fkefbX3B_-97eQdiQcyCYQ
|
||||
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.Hsd15sfwSET0yXg92mosT1cs-1kiyW7VZlSZiWKkIu4EKDWnslBPZzbTKVi9OY4lXKJmXuAo38E3wtj5EvD7GA5azd090-Rnv-VOrQfXNmjZd9jxc7861IWQOFZb9XEDQZF6X2JM8fK_psSs6mrew9BjuOx6ws68h-zTl8ttcjHZC3Y7SZ5AjYj5i4T-Z0hJpLk2kwjCYF3SH599R3L3kZxDi6IcO9qW_Lj6zcBT5SttLgikUpvHwY409pbFBohl-AVhCZuDuyJPDns4n7jjWj4sELH4w-8dbc5oijzxI1FoxnUhXTRsrwNgfgCBAFM_umXGXLHAQlb2QzH2JHtB6g.rednhhAPc9V-KExp.qf0pSc_4pCgKIgK5T03yEmWz1yF5u2S0lSDBAvu7yOeCl469QBRIOxCv_RHImCG4tjOwYZjNaS8gaKVIoNNtxhKxC04Y2G7pxYDgNh2pU-sJOi05A1BaIbdIC209uK0r-mKkX_hfMDtNNWuOCyHXju4ugbNHwH64KvLzy4_RfFa0n9AOhpS1xNT3aa_eJvj0RQCfFs10BckWJoGlIfbS6VMyeeHeQEX6QWFSauxUwUPOAvrRlNjtNSxxVvNr1CbJso_8Cl0frD8DELaWxu3uKvLkSm2_GVMjPbvmZIqvcVxpxYnFMjwngQOAqnmiI-n_3LlO-dZb-Gf5AwN2F61PQDKXkdOcNiM4bNU_V11VKHP_BCJpVcaL6detQLNzHIuyU93zbw.fkefbX3B_-97eQdiQcyCYQ
|
||||
|
|
75
DOCS.md
75
DOCS.md
|
@ -83,4 +83,77 @@ notify:
|
|||
repo: {{.Repo.FullName}}
|
||||
build: {{.Build.Number}}
|
||||
commit: {{.Build.Commit}}
|
||||
```
|
||||
```
|
||||
|
||||
## Basic Authentication
|
||||
|
||||
>It is important to note that with HTTP Basic Authentication the provided username and password are not encrypted.
|
||||
|
||||
In some cases your webhook may need to authenticate with another service. You can set the basic `Authentication` header with a username and password. For these use cases we expose the following additional parameters:
|
||||
|
||||
* `auth` - Sets the request's `Authorization` header to use HTTP Basic Authentication with the provided username and password below.
|
||||
* `username` - The username as a string.
|
||||
* `password` - The password as a string.
|
||||
|
||||
Example configuration to include HTTP Basic Authentication:
|
||||
|
||||
```yaml
|
||||
notify:
|
||||
webhook:
|
||||
method: POST
|
||||
auth:
|
||||
username: $$USERNAME
|
||||
password: $$PASSWORD
|
||||
urls:
|
||||
- https://tower.example.com/...
|
||||
content_type: application/yaml
|
||||
template: >
|
||||
repo: {{.Repo.FullName}}
|
||||
build: {{.Build.Number}}
|
||||
commit: {{.Build.Commit}}
|
||||
```
|
||||
|
||||
## Debugging Webhooks
|
||||
|
||||
>If you have private variables that are encrypted and hidden in `.drone.sec`, remember that the `debug` flag may print out those sensitive values. Please use `dubug: true` wisely.
|
||||
|
||||
In some cases complicated webhooks may need debugging to ensure `urls`, `template`, `auth` and more a properly configured. For these use cases we expose the following `debug` parameter:
|
||||
|
||||
* `debug` - If `debug: true` it will print out each URL request and response information.
|
||||
|
||||
Example configuration to include the `debug` parameter:
|
||||
|
||||
```yaml
|
||||
notify:
|
||||
webhook:
|
||||
debug: true
|
||||
method: POST
|
||||
auth:
|
||||
username: $$TOWER_USER
|
||||
password: $$TOWER_PASS
|
||||
urls:
|
||||
- http://tower.example.com/api/v1/job_templates/44/launch/
|
||||
- http://tower.example.com/api/v1/job_templates/45/launch/
|
||||
content_type: application/json
|
||||
template: '{"name": "project.deploy","extra_vars": "{\"env\": \"dev\",\"git_branch\": \"{{ .Build.Branch }}\",\"hipchat_token\": \"$$HIPCHAT_TOKEN\"}"}'
|
||||
```
|
||||
|
||||
Example of a debug print result:
|
||||
|
||||
```yaml
|
||||
[debug] Webhook 1
|
||||
URL: http://tower.example.com/api/v1/job_templates/44/launch/
|
||||
METHOD: POST
|
||||
HEADERS: map[Content-Type:[application/json] Authorization:[Basic EMfNB3fakB8EMfNB3fakB8==]]
|
||||
REQUEST BODY: {"name": "project.deploy","extra_vars": "{\"env\": \"dev\",\"git_branch\": \"develop\",\"hipchat_token\": \"h1pchatT0k3n\"}"}
|
||||
RESPONSE STATUS: 202 ACCEPTED
|
||||
RESPONSE BODY: {"job": 236}
|
||||
|
||||
[debug] Webhook 2
|
||||
URL: http://tower.example.com/api/v1/job_templates/45/launch/
|
||||
METHOD: POST
|
||||
HEADERS: map[Content-Type:[application/json] Authorization:[Basic EMfNB3fakB8EMfNB3fakB8==]]
|
||||
REQUEST BODY: {"name": "project.deploy","extra_vars": "{\"env\": \"dev\",\"git_branch\": \"develop\",\"hipchat_token\": \"h1pchatT0k3n\"}"}
|
||||
RESPONSE STATUS: 202 ACCEPTED
|
||||
RESPONSE BODY: {"job": 406}
|
||||
```
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# CGO_ENABLED=0 go build -a -tags netgo
|
||||
# docker build --rm=true -t plugins/drone-webhook .
|
||||
|
||||
FROM gliderlabs/alpine:3.1
|
||||
FROM gliderlabs/alpine:3.2
|
||||
RUN apk-install ca-certificates
|
||||
ADD drone-webhook /bin/
|
||||
ENTRYPOINT ["/bin/drone-webhook"]
|
||||
|
|
28
README.md
28
README.md
|
@ -1,5 +1,5 @@
|
|||
# drone-webhook
|
||||
Drone plugin for sending Webhook notifications by [@chromakode](https://github.com/chromakode).
|
||||
Drone plugin for sending Webhook notifications.
|
||||
|
||||
## Overview
|
||||
|
||||
|
@ -25,7 +25,18 @@ This plugin is responsible for sending build notifications via Webhooks:
|
|||
"author_email": "john.smith@gmail.com"
|
||||
},
|
||||
"vargs": {
|
||||
"urls": [ "https://your.webhook/..." ]
|
||||
"urls": ["https://your.webhook/..."],
|
||||
"debug": true,
|
||||
"auth": {
|
||||
"username": "johnsmith",
|
||||
"password": "secretPass"
|
||||
},
|
||||
"headers": {
|
||||
"SomeHeader": "SomeHeaderValue"
|
||||
},
|
||||
"method": "POST",
|
||||
"template": "{\"git_branch\": \"{{ .Build.Branch }}\"}",
|
||||
"content_type": "application/json"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
@ -63,7 +74,18 @@ docker run -i plugins/drone-webhook <<EOF
|
|||
"author_email": "john.smith@gmail.com"
|
||||
},
|
||||
"vargs": {
|
||||
"urls": [ "https://your.webhook/..." ]
|
||||
"urls": ["https://your.webhook/..."],
|
||||
"debug": true,
|
||||
"auth": {
|
||||
"username": "johnsmith",
|
||||
"password": "secretPass"
|
||||
},
|
||||
"headers": {
|
||||
"SomeHeader": "SomeHeaderValue"
|
||||
},
|
||||
"method": "POST",
|
||||
"template": "{\"git_branch\": \"{{ .Build.Branch }}\"}",
|
||||
"content_type": "application/json"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
|
84
main.go
84
main.go
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
@ -14,26 +15,22 @@ import (
|
|||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// plugin settings
|
||||
var repo = drone.Repo{}
|
||||
var build = drone.Build{}
|
||||
var vargs = struct {
|
||||
Urls []string `json:"urls"`
|
||||
Headers map[string]string `json:"header"`
|
||||
Method string `json:"method"`
|
||||
Template string `json:"template"`
|
||||
ContentType string `json:"content_type"`
|
||||
}{}
|
||||
var vargs = Webhook{}
|
||||
|
||||
// set plugin parameters
|
||||
plugin.Param("repo", &repo)
|
||||
plugin.Param("build", &build)
|
||||
plugin.Param("vargs", &vargs)
|
||||
plugin.Parse()
|
||||
|
||||
// data structure
|
||||
data := struct {
|
||||
Repo drone.Repo `json:"repo"`
|
||||
Build drone.Build `json:"build"`
|
||||
}{repo, build}
|
||||
// parse the parameters
|
||||
if err := plugin.Parse(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// set default values
|
||||
if len(vargs.Method) == 0 {
|
||||
|
@ -43,28 +40,40 @@ func main() {
|
|||
vargs.ContentType = "application/json"
|
||||
}
|
||||
|
||||
// data structure
|
||||
data := struct {
|
||||
Repo drone.Repo `json:"repo"`
|
||||
Build drone.Build `json:"build"`
|
||||
}{repo, build}
|
||||
|
||||
// creates the payload. by default the payload
|
||||
// is the build details in json format, but a custom
|
||||
// template may also be used.
|
||||
var buf bytes.Buffer
|
||||
if len(vargs.Template) == 0 {
|
||||
json.NewEncoder(&buf).Encode(&data)
|
||||
|
||||
if err := json.NewEncoder(&buf).Encode(&data); err != nil {
|
||||
fmt.Printf("Error encoding content template. %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
|
||||
t, err := template.New("_").Parse(vargs.Template)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing content template. %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
t.Execute(&buf, &data)
|
||||
if err != nil {
|
||||
|
||||
if err := t.Execute(&buf, &data); err != nil {
|
||||
fmt.Printf("Error executing content template. %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// post payload to each url
|
||||
for _, rawurl := range vargs.Urls {
|
||||
// build and execute a request for each url.
|
||||
// all auth, headers, method, template (payload),
|
||||
// and content_type values will be applied to
|
||||
// every webhook request.
|
||||
for i, rawurl := range vargs.Urls {
|
||||
|
||||
uri, err := url.Parse(rawurl)
|
||||
if err != nil {
|
||||
|
@ -72,21 +81,54 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(vargs.Method, uri.String(), &buf)
|
||||
// vargs.Method defaults to POST, no need to check
|
||||
b := buf.Bytes()
|
||||
r := bytes.NewReader(b)
|
||||
req, err := http.NewRequest(vargs.Method, uri.String(), r)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating http request. %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// vargs.ContentType defaults to application/json, no need to check
|
||||
req.Header.Set("Content-Type", vargs.ContentType)
|
||||
for key, value := range vargs.Headers {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
|
||||
// set basic auth if a user or user and pass is provided
|
||||
if len(vargs.Auth.Username) > 0 {
|
||||
if len(vargs.Auth.Password) > 0 {
|
||||
req.SetBasicAuth(vargs.Auth.Username, vargs.Auth.Password)
|
||||
} else {
|
||||
req.SetBasicAuth(vargs.Auth.Username, "")
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
fmt.Printf("Error executing http request. %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
resp.Body.Close()
|
||||
defer resp.Body.Close()
|
||||
|
||||
// if debug is on or response status code is bad
|
||||
if vargs.Debug || resp.StatusCode >= http.StatusBadRequest {
|
||||
|
||||
// read the response body
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
// I do not think we need to os.Exit(1) if we are
|
||||
// unable to read a http response body.
|
||||
fmt.Printf("Error reading http response body. %s\n", err)
|
||||
}
|
||||
|
||||
// debug/info print
|
||||
if vargs.Debug {
|
||||
fmt.Printf("[debug] Webhook %d\n URL: %s\n METHOD: %s\n HEADERS: %s\n REQUEST BODY: %s\n RESPONSE STATUS: %s\n RESPONSE BODY: %s\n", i+1, req.URL, req.Method, req.Header, string(b), resp.Status, string(body))
|
||||
} else {
|
||||
fmt.Printf("[info] Webhook %d\n URL: %s\n RESPONSE STATUS: %s\n RESPONSE BODY: %s\n", i+1, req.URL, resp.Status, string(body))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package main
|
||||
|
||||
type Webhook struct {
|
||||
Urls []string `json:"urls"`
|
||||
Debug bool `json:"debug"`
|
||||
Auth BasicAuth `json:"auth"`
|
||||
Headers map[string]string `json:"header"`
|
||||
Method string `json:"method"`
|
||||
Template string `json:"template"`
|
||||
ContentType string `json:"content_type"`
|
||||
}
|
||||
|
||||
type BasicAuth struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
Loading…
Reference in New Issue