mirror of
https://github.com/adnanh/webhook.git
synced 2026-07-27 17:49:50 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 147c95dd8b | |||
| cfd138c96d | |||
| c19e514ee9 | |||
| c7ec25f378 | |||
| 6916f89a2b | |||
| ed251c3cc7 | |||
| 9db13ef649 | |||
| 98512463d8 | |||
| 53ec2e7acc | |||
| c581e0532b | |||
| 3a75bbf4db | |||
| 2f1ea098c0 | |||
| ccd28908db |
@@ -12,7 +12,7 @@ If you don't have time to waste configuring, hosting, debugging and maintaining
|
|||||||
|
|
||||||
For example, if you're using Github or Bitbucket, you can use [webhook](https://github.com/adnanh/webhook/) to set up a hook that runs a redeploy script for your project on your staging server, whenever you push changes to the master branch of your project.
|
For example, if you're using Github or Bitbucket, you can use [webhook](https://github.com/adnanh/webhook/) to set up a hook that runs a redeploy script for your project on your staging server, whenever you push changes to the master branch of your project.
|
||||||
|
|
||||||
If you use Slack, you can set up an "Outgoing webhook integration" to run various commands on your server, which can then report back directly to your Slack channels using the "Incoming webhook integrations".
|
If you use Mattermost or Slack, you can set up an "Outgoing webhook integration" or "Slash command" to run various commands on your server, which can then report back directly to you or your channels using the "Incoming webhook integrations", or the appropriate response body.
|
||||||
|
|
||||||
[webhook](https://github.com/adnanh/webhook/) aims to do nothing more than it should do, and that is:
|
[webhook](https://github.com/adnanh/webhook/) aims to do nothing more than it should do, and that is:
|
||||||
1. receive the request,
|
1. receive the request,
|
||||||
@@ -35,8 +35,8 @@ $ go get github.com/adnanh/webhook
|
|||||||
to get the latest version of the [webhook](https://github.com/adnanh/webhook/).
|
to get the latest version of the [webhook](https://github.com/adnanh/webhook/).
|
||||||
|
|
||||||
### Using package manager
|
### Using package manager
|
||||||
#### Debian "sid"
|
#### Debian
|
||||||
If you are using unstable version of Debian linux ("sid"), you can install webhook using `apt-get install webhook` which will install community packaged version (thanks [@freeekanayaka](https://github.com/freeekanayaka)) from https://packages.debian.org/sid/webhook
|
If you are using Debian linux ("stretch" or later), you can install webhook using `apt-get install webhook` which will install community packaged version (thanks [@freeekanayaka](https://github.com/freeekanayaka)) from https://packages.debian.org/sid/webhook
|
||||||
|
|
||||||
### Download prebuilt binaries
|
### Download prebuilt binaries
|
||||||
Prebuilt binaries for different architectures are available at [GitHub Releases](https://github.com/adnanh/webhook/releases).
|
Prebuilt binaries for different architectures are available at [GitHub Releases](https://github.com/adnanh/webhook/releases).
|
||||||
@@ -93,6 +93,11 @@ Big thanks to [all the current contributors](https://github.com/adnanh/webhook/g
|
|||||||
# Community Contributions
|
# Community Contributions
|
||||||
See the [webhook-contrib][wc] repository for a collections of tools and helpers related to [webhook][w] that have been contributed by the [webhook][w] community.
|
See the [webhook-contrib][wc] repository for a collections of tools and helpers related to [webhook][w] that have been contributed by the [webhook][w] community.
|
||||||
|
|
||||||
|
# Sponsors
|
||||||
|
## <a href="https://www.browserstack.com/?ref=webhook"><img src="http://www.hajdarevic.net/browserstack.svg" alt="BrowserStack" width="250"/></a>
|
||||||
|
[BrowserStack](https://www.browserstack.com/?ref=webhook) is a cloud-based cross-browser testing tool that enables developers to test their websites across various browsers on different operating systems and mobile devices, without requiring users to install virtual machines, devices or emulators.
|
||||||
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|||||||
+3
-1
@@ -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},
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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: /
|
||||||
+12
-3
@@ -21,7 +21,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version = "2.6.4"
|
version = "2.6.5"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -152,7 +152,16 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
l := negroni.NewLogger()
|
l := negroni.NewLogger()
|
||||||
l.ALogger = log.New(os.Stderr, "[webhook] ", log.Ldate|log.Ltime)
|
|
||||||
|
l.SetFormat("{{.Status}} | {{.Duration}} | {{.Hostname}} | {{.Method}} {{.Path}} \n")
|
||||||
|
|
||||||
|
standardLogger := log.New(os.Stdout, "[webhook] ", log.Ldate|log.Ltime)
|
||||||
|
|
||||||
|
if !*verbose {
|
||||||
|
standardLogger.SetOutput(ioutil.Discard)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.ALogger = standardLogger
|
||||||
|
|
||||||
negroniRecovery := &negroni.Recovery{
|
negroniRecovery := &negroni.Recovery{
|
||||||
Logger: l.ALogger,
|
Logger: l.ALogger,
|
||||||
@@ -326,7 +335,7 @@ func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, b
|
|||||||
|
|
||||||
log.Printf("executing %s (%s) with arguments %q and environment %s using %s as cwd\n", h.ExecuteCommand, cmd.Path, cmd.Args, envs, cmd.Dir)
|
log.Printf("executing %s (%s) with arguments %q and environment %s using %s as cwd\n", h.ExecuteCommand, cmd.Path, cmd.Args, envs, cmd.Dir)
|
||||||
|
|
||||||
out, err := cmd.Output()
|
out, err := cmd.CombinedOutput()
|
||||||
|
|
||||||
log.Printf("command output: %s\n", out)
|
log.Printf("command output: %s\n", out)
|
||||||
|
|
||||||
|
|||||||
+8
-4
@@ -21,7 +21,8 @@ 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"} {
|
||||||
|
config, cleanupConfig := genConfig(t, hookecho, hookTmpl)
|
||||||
defer cleanupConfig()
|
defer cleanupConfig()
|
||||||
|
|
||||||
webhook, cleanupWebhook := buildWebhook(t)
|
webhook, cleanupWebhook := buildWebhook(t)
|
||||||
@@ -77,6 +78,7 @@ func TestWebhook(t *testing.T) {
|
|||||||
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)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildHookecho(t *testing.T) (bin string, cleanup func()) {
|
func buildHookecho(t *testing.T) (bin string, cleanup func()) {
|
||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user