From 69b094965b3feee4b385a166b7df47d36cde1dc7 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Mon, 16 Sep 2019 23:22:59 +0200 Subject: [PATCH] Refactoring and new plugin lib This commit is doing a general refactoring of the current code base and it also integrates the new plugin lib. --- .drone.starlark | 28 +++++ .drone.yml | 2 +- defaults.go | 16 --- go.mod | 8 +- go.sum | 41 ++++++++ helper.go | 12 +++ main.go | 268 ++++++++++++++++++++++++------------------------ plugin.go | 196 ++++++++++++++++------------------- template.go | 27 +++++ 9 files changed, 340 insertions(+), 258 deletions(-) delete mode 100644 defaults.go create mode 100644 helper.go create mode 100644 template.go diff --git a/.drone.starlark b/.drone.starlark index 7950acb..2445c7a 100644 --- a/.drone.starlark +++ b/.drone.starlark @@ -45,6 +45,34 @@ def testing(): } ] }, + { + 'name': 'lint', + 'image': 'golang:1.12', + 'pull': 'always', + 'commands': [ + 'go run golang.org/x/lint/golint -set_exit_status ./...' + ], + 'volumes': [ + { + 'name': 'gopath', + 'path': '/go' + } + ] + }, + { + 'name': 'staticcheck', + 'image': 'golang:1.12', + 'pull': 'always', + 'commands': [ + 'go run honnef.co/go/tools/cmd/staticcheck ./...' + ], + 'volumes': [ + { + 'name': 'gopath', + 'path': '/go' + } + ] + }, { 'name': 'test', 'image': 'golang:1.12', diff --git a/.drone.yml b/.drone.yml index d7cde30..3e7dd08 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,5 +1,5 @@ --- -{"kind": "pipeline", "type": "docker", "name": "testing", "platform": {"os": "linux", "arch": "amd64"}, "steps": [{"name": "vet", "image": "golang:1.12", "pull": "always", "commands": ["go vet ./..."], "volumes": [{"name": "gopath", "path": "/go"}]}, {"name": "test", "image": "golang:1.12", "pull": "always", "commands": ["go test -cover ./..."], "volumes": [{"name": "gopath", "path": "/go"}]}], "volumes": [{"name": "gopath", "temp": {}}], "trigger": {"ref": ["refs/heads/master", "refs/tags/**", "refs/pull/**"]}} +{"kind": "pipeline", "type": "docker", "name": "testing", "platform": {"os": "linux", "arch": "amd64"}, "steps": [{"name": "vet", "image": "golang:1.12", "pull": "always", "commands": ["go vet ./..."], "volumes": [{"name": "gopath", "path": "/go"}]}, {"name": "lint", "image": "golang:1.12", "pull": "always", "commands": ["go run golang.org/x/lint/golint -set_exit_status ./..."], "volumes": [{"name": "gopath", "path": "/go"}]}, {"name": "staticcheck", "image": "golang:1.12", "pull": "always", "commands": ["go run honnef.co/go/tools/cmd/staticcheck ./..."], "volumes": [{"name": "gopath", "path": "/go"}]}, {"name": "test", "image": "golang:1.12", "pull": "always", "commands": ["go test -cover ./..."], "volumes": [{"name": "gopath", "path": "/go"}]}], "volumes": [{"name": "gopath", "temp": {}}], "trigger": {"ref": ["refs/heads/master", "refs/tags/**", "refs/pull/**"]}} --- {"kind": "pipeline", "type": "docker", "name": "linux-amd64", "platform": {"os": "linux", "arch": "amd64"}, "steps": [{"name": "build-push", "image": "golang:1.12", "pull": "always", "environment": {"CGO_ENABLED": "0"}, "commands": ["go build -v -ldflags \"-X main.version=${DRONE_COMMIT_SHA:0:8}\" -a -tags netgo -o release/linux/amd64/drone-webhook"], "when": {"event": {"exclude": ["tag"]}}}, {"name": "build-tag", "image": "golang:1.12", "pull": "always", "environment": {"CGO_ENABLED": "0"}, "commands": ["go build -v -ldflags \"-X main.version=${DRONE_TAG##v}\" -a -tags netgo -o release/linux/amd64/drone-webhook"], "when": {"event": ["tag"]}}, {"name": "executable", "image": "golang:1.12", "pull": "always", "commands": ["./release/linux/amd64/drone-webhook --help"]}, {"name": "dryrun", "image": "plugins/docker", "pull": "always", "settings": {"dry_run": true, "tags": "linux-amd64", "dockerfile": "docker/Dockerfile.linux.amd64", "repo": "plugins/webhook", "username": {"from_secret": "docker_username"}, "password": {"from_secret": "docker_password"}}, "when": {"event": ["pull_request"]}}, {"name": "publish", "image": "plugins/docker", "pull": "always", "settings": {"auto_tag": true, "auto_tag_suffix": "linux-amd64", "dockerfile": "docker/Dockerfile.linux.amd64", "repo": "plugins/webhook", "username": {"from_secret": "docker_username"}, "password": {"from_secret": "docker_password"}}, "when": {"event": {"exclude": ["pull_request"]}}}], "depends_on": ["testing"], "trigger": {"ref": ["refs/heads/master", "refs/tags/**", "refs/pull/**"]}} --- diff --git a/defaults.go b/defaults.go deleted file mode 100644 index 6e99e0e..0000000 --- a/defaults.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -const respFormat = `Webhook %d - URL: %s - RESPONSE STATUS: %s - RESPONSE BODY: %s -` - -const debugFormat = `Webhook %d - URL: %s - METHOD: %s - HEADERS: %s - REQUEST BODY: %s - RESPONSE STATUS: %s - RESPONSE BODY: %s -` diff --git a/go.mod b/go.mod index d3e57ca..e901a36 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,14 @@ module github.com/drone-plugins/drone-webhook require ( bou.ke/monkey v1.0.1 // indirect github.com/aymerick/raymond v2.0.2+incompatible // indirect + github.com/drone-plugins/drone-plugin-lib v0.0.0-20190916204527-6b33d765aca4 github.com/drone/drone-template-lib v0.0.0-20181004051823-4019baa6c594 + github.com/jackspirou/syscerts v0.0.0-20160531025014-b68f5469dff1 github.com/pkg/errors v0.8.1 // indirect + github.com/sirupsen/logrus v1.4.2 github.com/stretchr/testify v1.3.0 // indirect github.com/tkuchiki/faketime v0.1.1 // indirect - github.com/urfave/cli v1.20.0 - gopkg.in/yaml.v2 v2.2.2 // indirect + github.com/urfave/cli v1.21.0 + golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac // indirect + honnef.co/go/tools v0.0.1-2019.2.3 // indirect ) diff --git a/go.sum b/go.sum index 7093501..732bb7b 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,64 @@ bou.ke/monkey v1.0.1 h1:zEMLInw9xvNakzUUPjfS4Ds6jYPqCFx3m7bRmG5NH2U= bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/aymerick/raymond v2.0.2+incompatible h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfKMjPOA3SbKLtnU0= github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/drone-plugins/drone-plugin-lib v0.0.0-20190905223702-0352df680f17 h1:x441B4/1FGRHg92xWAithZQUhsUysY+hZca3Wo6fuTQ= +github.com/drone-plugins/drone-plugin-lib v0.0.0-20190916204527-6b33d765aca4 h1:CxEkk5WIstHlmg+locKHxTnJ/rzk08P3FE5W1hFCEBk= +github.com/drone-plugins/drone-plugin-lib v0.0.0-20190916204527-6b33d765aca4/go.mod h1:Jd/3DVk8GYEuFXhOZ2UZ3D7iwoXIfZXdIQ1BaBpBBls= github.com/drone/drone-template-lib v0.0.0-20181004051823-4019baa6c594 h1:zPRVfiHpXeGt1XGpK2TQcaj2lRydiGdVz1AoHkaC554= github.com/drone/drone-template-lib v0.0.0-20181004051823-4019baa6c594/go.mod h1:u34woe41m58Whrf21iH6z/xLOIRM3650LhWAyUc7Oik= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/jackspirou/syscerts v0.0.0-20160531025014-b68f5469dff1 h1:9Xm8CKtMZIXgcopfdWk/qZ1rt0HjMgfMR9nxxSeK6vk= +github.com/jackspirou/syscerts v0.0.0-20160531025014-b68f5469dff1/go.mod h1:zuHl3Hh+e9P6gmBPvcqR1HjkaWHC/csgyskg6IaFKFo= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/tkuchiki/faketime v0.1.1 h1:UZjBlktFAi23wo+jWuHuNoHUpLnB0j/5B62bl5nCPls= github.com/tkuchiki/faketime v0.1.1/go.mod h1:RXY/TXAwGGL36IKDjrHFMcjpUrEiyWSEtLhFPw3UWF0= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE= +github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac h1:8R1esu+8QioDxo4E4mX6bFztO+dMTM49DNAaWfO5OeY= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac h1:MQEvx39qSf8vyrx3XRaOe+j1UDIzKwkYOVObRgGPVqI= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/helper.go b/helper.go new file mode 100644 index 0000000..12f6c77 --- /dev/null +++ b/helper.go @@ -0,0 +1,12 @@ +package main + +// intInSlice checks if int is in slice of ints +func intInSlice(s []int, e int) bool { + for _, a := range s { + if a == e { + return true + } + } + + return false +} diff --git a/main.go b/main.go index 3820f66..c8ef24a 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,10 @@ package main import ( - "log" "os" + "github.com/drone-plugins/drone-plugin-lib/pkg/urfave" + log "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -11,6 +12,68 @@ var ( version = "unknown" ) +const ( + // MethodFlag defines the method flag name + MethodFlag = "method" + + // MethodEnvVar defines the method env var + MethodEnvVar = "PLUGIN_METHOD" + + // UsernameFlag defines the username flag name + UsernameFlag = "username" + + // UsernameEnvVar defines the username env var + UsernameEnvVar = "PLUGIN_USERNAME,WEBHOOK_USERNAME" + + // PasswordFlag defines the password flag name + PasswordFlag = "password" + + // PasswordEnvVar defines the password env var + PasswordEnvVar = "PLUGIN_PASSWORD,WEBHOOK_PASSWORD" + + // ContentTypeFlag defines the content type flag name + ContentTypeFlag = "content-type" + + // ContentTypeEnvVar defines the content type env var + ContentTypeEnvVar = "PLUGIN_CONTENT_TYPE" + + // TemplateFlag defines the template flag name + TemplateFlag = "template" + + // TemplateEnvVar defines the template env var + TemplateEnvVar = "PLUGIN_TEMPLATE" + + // HeadersFlag defines the headers flag name + HeadersFlag = "headers" + + // HeadersEnvVar defines the headers env var + HeadersEnvVar = "PLUGIN_HEADERS" + + // URLsFlag defines the urls flag name + URLsFlag = "urls" + + // URLsEnvVar defines the urls env var + URLsEnvVar = "PLUGIN_URLS,PLUGIN_URL,WEBHOOK_URLS,WEBHOOK_URL" + + // ValidResponseCodesFlag defines the valid response codes flag name + ValidResponseCodesFlag = "valid-response-codes" + + // ValidResponseCodesEnvVar defines the valid response codes env var + ValidResponseCodesEnvVar = "PLUGIN_VALID_RESPONSE_CODES" + + // DebugFlag defines the debug flag name + DebugFlag = "debug" + + // DebugEnvVar defines the debug env var + DebugEnvVar = "PLUGIN_DEBUG" + + // SkipVerifyFlag defines the skip verify flag name + SkipVerifyFlag = "skip-verify" + + // SkipVerifyEnvVar defines the skip verify env var + SkipVerifyEnvVar = "PLUGIN_SKIP_VERIFY" +) + func main() { app := cli.NewApp() app.Name = "webhook plugin" @@ -19,179 +82,120 @@ func main() { app.Version = version app.Flags = []cli.Flag{ cli.StringFlag{ - Name: "method", + Name: MethodFlag, Usage: "webhook method", - EnvVar: "PLUGIN_METHOD", + EnvVar: MethodEnvVar, Value: "POST", }, cli.StringFlag{ - Name: "username", + Name: UsernameFlag, Usage: "username for basic auth", - EnvVar: "PLUGIN_USERNAME,WEBHOOK_USERNAME", + EnvVar: UsernameEnvVar, }, cli.StringFlag{ - Name: "password", + Name: PasswordFlag, Usage: "password for basic auth", - EnvVar: "PLUGIN_PASSWORD,WEBHOOK_PASSWORD", + EnvVar: PasswordEnvVar, }, cli.StringFlag{ - Name: "content-type", + Name: ContentTypeFlag, Usage: "content type", - EnvVar: "PLUGIN_CONTENT_TYPE", + EnvVar: ContentTypeEnvVar, Value: "application/json", }, cli.StringFlag{ - Name: "template", + Name: TemplateFlag, Usage: "custom template for webhook", - EnvVar: "PLUGIN_TEMPLATE", + EnvVar: TemplateEnvVar, }, cli.StringSliceFlag{ - Name: "headers", + Name: HeadersFlag, Usage: "custom headers key map", - EnvVar: "PLUGIN_HEADERS", + EnvVar: HeadersEnvVar, }, cli.StringSliceFlag{ - Name: "urls", + Name: URLsFlag, Usage: "list of urls to perform the action on", - EnvVar: "PLUGIN_URLS,WEBHOOK_URLS", + EnvVar: URLsEnvVar, }, cli.IntSliceFlag{ - Name: "valid-response-codes", + Name: ValidResponseCodesFlag, Usage: "list of valid http response codes", - EnvVar: "PLUGIN_VALID_RESPONSE_CODES", + EnvVar: ValidResponseCodesEnvVar, }, cli.BoolFlag{ - Name: "debug", + Name: DebugFlag, Usage: "enable debug information", - EnvVar: "PLUGIN_DEBUG", + EnvVar: DebugEnvVar, }, cli.BoolFlag{ - Name: "skip-verify", + Name: SkipVerifyFlag, Usage: "skip ssl verification", - EnvVar: "PLUGIN_SKIP_VERIFY", - }, - cli.StringFlag{ - Name: "repo.owner", - Usage: "repository owner", - EnvVar: "DRONE_REPO_OWNER", - }, - cli.StringFlag{ - Name: "repo.name", - Usage: "repository name", - EnvVar: "DRONE_REPO_NAME", - }, - cli.StringFlag{ - Name: "commit.sha", - Usage: "git commit sha", - EnvVar: "DRONE_COMMIT_SHA", - }, - cli.StringFlag{ - Name: "commit.ref", - Value: "refs/heads/master", - Usage: "git commit ref", - EnvVar: "DRONE_COMMIT_REF", - }, - cli.StringFlag{ - Name: "commit.branch", - Value: "master", - Usage: "git commit branch", - EnvVar: "DRONE_COMMIT_BRANCH", - }, - cli.StringFlag{ - Name: "commit.author", - Usage: "git author name", - EnvVar: "DRONE_COMMIT_AUTHOR", - }, - cli.StringFlag{ - Name: "commit.message", - Usage: "commit message", - EnvVar: "DRONE_COMMIT_MESSAGE", - }, - cli.StringFlag{ - Name: "build.event", - Value: "push", - Usage: "build event", - EnvVar: "DRONE_BUILD_EVENT", - }, - cli.IntFlag{ - Name: "build.number", - Usage: "build number", - EnvVar: "DRONE_BUILD_NUMBER", - }, - cli.StringFlag{ - Name: "build.status", - Usage: "build status", - Value: "success", - EnvVar: "DRONE_BUILD_STATUS", - }, - cli.StringFlag{ - Name: "build.link", - Usage: "build link", - EnvVar: "DRONE_BUILD_LINK", - }, - cli.Int64Flag{ - Name: "build.started", - Usage: "build started", - EnvVar: "DRONE_BUILD_STARTED", - }, - cli.Int64Flag{ - Name: "build.created", - Usage: "build created", - EnvVar: "DRONE_BUILD_CREATED", - }, - cli.StringFlag{ - Name: "build.tag", - Usage: "build tag", - EnvVar: "DRONE_TAG", - }, - cli.Int64Flag{ - Name: "job.started", - Usage: "job started", - EnvVar: "DRONE_JOB_STARTED", + EnvVar: SkipVerifyEnvVar, }, } + flags := [][]cli.Flag{ + urfave.BuildFlags(), + urfave.RepoFlags(), + urfave.CommitFlags(), + urfave.StageFlags(), + urfave.StepFlags(), + urfave.SemVerFlags(), + } + + for _, flagz := range flags { + app.Flags = append( + app.Flags, + flagz..., + ) + } + if err := app.Run(os.Args); err != nil { - log.Fatal(err) + os.Exit(1) } } func run(c *cli.Context) error { plugin := Plugin{ - Repo: Repo{ - Owner: c.String("repo.owner"), - Name: c.String("repo.name"), - }, - Build: Build{ - Tag: c.String("build.tag"), - Number: c.Int("build.number"), - Event: c.String("build.event"), - Status: c.String("build.status"), - Commit: c.String("commit.sha"), - Ref: c.String("commit.ref"), - Branch: c.String("commit.branch"), - Author: c.String("commit.author"), - Message: c.String("commit.message"), - Link: c.String("build.link"), - Started: c.Int64("build.started"), - Created: c.Int64("build.created"), - }, - Job: Job{ - Started: c.Int64("job.started"), - }, + Build: urfave.BuildFromContext(c), + Repo: urfave.RepoFromContext(c), + Commit: urfave.CommitFromContext(c), + Stage: urfave.StageFromContext(c), + Step: urfave.StepFromContext(c), + SemVer: urfave.SemVerFromContext(c), + Config: Config{ - Method: c.String("method"), - Username: c.String("username"), - Password: c.String("password"), - ContentType: c.String("content-type"), - Template: c.String("template"), - Headers: c.StringSlice("headers"), - URLs: c.StringSlice("urls"), - ValidCodes: c.IntSlice("valid-response-codes"), - Debug: c.Bool("debug"), - SkipVerify: c.Bool("skip-verify"), + Method: c.String(MethodFlag), + Username: c.String(UsernameFlag), + Password: c.String(PasswordFlag), + ContentType: c.String(ContentTypeFlag), + Template: c.String(TemplateFlag), + Headers: c.StringSlice(HeadersFlag), + URLs: c.StringSlice(URLsFlag), + ValidCodes: c.IntSlice(ValidResponseCodesFlag), + Debug: c.Bool(DebugFlag), + SkipVerify: c.Bool(SkipVerifyFlag), }, } + if plugin.Config.Debug { + log.SetLevel(log.DebugLevel) + } + + if len(plugin.Config.URLs) == 0 { + log.Fatal("You must provide at least one url") + } + return plugin.Exec() } + +func init() { + log.SetFormatter(&log.TextFormatter{ + DisableColors: true, + DisableTimestamp: true, + }) + + log.SetOutput(os.Stdout) + log.SetLevel(log.InfoLevel) +} diff --git a/plugin.go b/plugin.go index b973f4f..4647ba0 100644 --- a/plugin.go +++ b/plugin.go @@ -8,33 +8,16 @@ import ( "io/ioutil" "net/http" "net/url" - "os" "strings" + "github.com/drone-plugins/drone-plugin-lib/pkg/plugin" "github.com/drone/drone-template-lib/template" + "github.com/jackspirou/syscerts" + log "github.com/sirupsen/logrus" ) type ( - Repo struct { - Owner string `json:"owner"` - Name string `json:"name"` - } - - Build struct { - Tag string `json:"tag"` - Event string `json:"event"` - Number int `json:"number"` - Commit string `json:"commit"` - Ref string `json:"ref"` - Branch string `json:"branch"` - Author string `json:"author"` - Message string `json:"message"` - Status string `json:"status"` - Link string `json:"link"` - Started int64 `json:"started"` - Created int64 `json:"created"` - } - + // Config provides the pugin configuration. Config struct { Method string Username string @@ -48,76 +31,51 @@ type ( SkipVerify bool } - Job struct { - Started int64 - } - + // Plugin provides all required attributes. Plugin struct { - Repo Repo - Build Build + Build plugin.Build + Repo plugin.Repo + Commit plugin.Commit + Stage plugin.Stage + Step plugin.Step + SemVer plugin.SemVer Config Config - Job Job } ) +// Exec provides the concrete plugin handler. func (p Plugin) Exec() error { - var ( - buf bytes.Buffer - b []byte - ) + b, err := p.payload() - if len(p.Config.URLs) == 0 { - return fmt.Errorf("You must provide at least one url") + if err != nil { + return err } - if p.Config.Template == "" { - data := struct { - Repo Repo `json:"repo"` - Build Build `json:"build"` - }{p.Repo, p.Build} + for i, raw := range p.Config.URLs { + uri, err := url.Parse(raw) + + if err != nil { + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to parse hook URL") - if err := json.NewEncoder(&buf).Encode(&data); err != nil { - fmt.Printf("Error: Failed to encode JSON payload. %s\n", err) return err } - b = buf.Bytes() - } else { - txt, err := template.RenderTrim(p.Config.Template, p) + req, err := http.NewRequest(p.Config.Method, uri.String(), bytes.NewReader(b)) if err != nil { - return err - } + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to create HTTP request") - text := txt - b = []byte(text) - } - - // 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 p.Config.URLs { - uri, err := url.Parse(rawurl) - - if err != nil { - fmt.Printf("Error: Failed to parse the hook URL. %s\n", err) - os.Exit(1) - } - - r := bytes.NewReader(b) - req, err := http.NewRequest(p.Config.Method, uri.String(), r) - - if err != nil { - fmt.Printf("Error: Failed to create the HTTP request. %s\n", err) return err } req.Header.Set("Content-Type", p.Config.ContentType) for _, value := range p.Config.Headers { - header := strings.Split(value, "=") + header := strings.SplitN(value, "=", 2) req.Header.Set(header[0], header[1]) } @@ -125,22 +83,23 @@ func (p Plugin) Exec() error { req.SetBasicAuth(p.Config.Username, p.Config.Password) } - client := http.DefaultClient - - if p.Config.SkipVerify { - client = &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, + client := &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{ + RootCAs: syscerts.SystemRootsPool(), + InsecureSkipVerify: p.Config.SkipVerify, }, - } + }, } resp, err := client.Do(req) if err != nil { - fmt.Printf("Error: Failed to execute the HTTP request. %s\n", err) + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to execute HTTP request") + return err } @@ -150,46 +109,69 @@ func (p Plugin) Exec() error { body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Printf("Error: Failed to read the HTTP response body. %s\n", err) + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to parse HTTP response") } - if p.Config.Debug { - fmt.Printf( - debugFormat, - i+1, - req.URL, - req.Method, - req.Header, - string(b), - resp.Status, - string(body), - ) - } else { - fmt.Printf( - respFormat, - i+1, - req.URL, - resp.Status, - string(body), - ) + output, err := template.RenderTrim(result, webhook{ + Debug: p.Config.Debug, + Number: i, + URL: req.URL.String(), + Method: req.Method, + Header: req.Header, + Status: resp.Status, + Request: string(b), + Response: string(body), + }) + + if err != nil { + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to parse debug template") + + return err } + + fmt.Println(output) } if len(p.Config.ValidCodes) > 0 && !intInSlice(p.Config.ValidCodes, resp.StatusCode) { - return fmt.Errorf("Error: Response code %d not found among valid response codes", resp.StatusCode) - } + log.WithFields(log.Fields{ + "code": resp.StatusCode, + }).Error("Valid response code not found") + return fmt.Errorf("valid response code not found") + } } return nil } -// Function checks if int is in slice of ints -func intInSlice(s []int, e int) bool { - for _, a := range s { - if a == e { - return true +func (p Plugin) payload() ([]byte, error) { + if p.Config.Template == "" { + res, err := json.Marshal(&p) + + if err != nil { + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to generate JSON response") + + return []byte{}, err } + + return res, nil } - return false + + res, err := template.RenderTrim(p.Config.Template, p) + + if err != nil { + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to parse response template") + + return []byte{}, err + } + + return []byte(res), nil } diff --git a/template.go b/template.go new file mode 100644 index 0000000..219f10c --- /dev/null +++ b/template.go @@ -0,0 +1,27 @@ +package main + +import ( + "net/http" +) + +// webhook defines the result payload. +type webhook struct { + Number int + URL string + Method string + Header http.Header + Status string + Request string + Response string + Debug bool +} + +// result defines the output template. +const result = `Webhook {{Number}} + URL: {{URL}}{{#if Debug}} + METHOD: {{Method}} + HEADERS: {{Headers}} + REQUEST: {{Request}}{{/if}} + STATUS: {{Status}} + RESPONSE: {{Response}} +`