webhookd 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 117c81bc0145b051d53dd51e0c85b54c99cc546a
4
+ data.tar.gz: d1874340cf8f379b5f2e7d9d2f76d7da699dab54
5
+ SHA512:
6
+ metadata.gz: 59510634125b6e8de310ba419c9b05867dfa6fab2892a472475c888a0bb1d04dc62cf85e6ba0fb58f2eb826ae125e86fd4eff67092d708c3771a9029894ec146
7
+ data.tar.gz: b2ad48474b9d31a74e171abf5d9b57d1d084821b22142689ff7f6e2e40a86489c1bb68a689556f012be7f8d4fdb61a081885ea400b8a56e7eb943b591cb48d71
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ *.log
15
+ mkmf.log
@@ -0,0 +1,7 @@
1
+ # v0.0.7 (January 31, 2015)
2
+
3
+ * Renaming of the project
4
+
5
+ # v0.0.3 (January 15, 2015)
6
+
7
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in webhookd.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Tobias Brunner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,176 @@
1
+ # Webhookd
2
+
3
+ **Flexible, configurable universal webhook receiver**
4
+
5
+ This app is a flexible, configurable universal webhook receiver, built with
6
+ sinatra.
7
+ It can receive a webhook, parse its payload and take action according to the
8
+ configuration.
9
+
10
+ Example: A git push to Gitlab sends a webhook to the webhookd. The webhookd then
11
+ parses the payload which contains the name and the branch of the pushed commit.
12
+ After that it looks up in the configuration what to do: run a different script per
13
+ repo or even per branch.
14
+
15
+ ## Installation
16
+
17
+ Just install the GEM:
18
+
19
+ $ gem install webhookd
20
+
21
+ The GEM has some dependencies which maybe need to build native extensions. Therefore on Ubuntu
22
+ and Debian the packages `ruby-dev` and `build-essential` are needed.
23
+
24
+ Some very basic Debian packaging effort can be found under [tobru/webhookd-debian-packaging](https://github.com/tobru/webhookd-debian-packaging).
25
+
26
+ ## Usage
27
+
28
+ ### Starting and stopping
29
+
30
+ The webhookd uses thin as rack server by default. It has a small CLI utility
31
+ to start and stop the service, called `webhookd`:
32
+
33
+ ```
34
+ Commands:
35
+ webhookd help [COMMAND] # Describe available commands or one specific command
36
+ webhookd start # Starts the webhookd server
37
+ webhookd stop # Stops the thin server
38
+ ```
39
+
40
+ To see the options for `thin`, run `webhookd start -h`. They can simply be added to the `start` command.
41
+ F.e. `webhookd start -d --config-file=/path/to/config.yml`
42
+
43
+ **Starting the webhookd server**
44
+
45
+ `webhookd start --config-file=/path/to/config.yml`
46
+
47
+ Test it with `curl -XGET http://username:password@localhost:8088`
48
+
49
+ **Stopping the webhookd server**
50
+
51
+ `webhookd stop`
52
+
53
+ ### Init script
54
+
55
+ There is an example init script which uses the Debian `/etc/default` mechanism to configured the
56
+ daemon options. Just place the file `scripts/webhookd.init` to `/etc/init.d/webhookd`, the
57
+ file `scripts/webhookd.default` to `/etc/default/webhookd` and update the parameters in the
58
+ defaults file to match your system.
59
+
60
+ It also has some configuration options to use SSL with the thin server. Set `SSL` to `yes` and update
61
+ the parameters `SSK_KEY` and `SSL_CERT`. The daemon starts now with ssl enabled.
62
+ On Debian and Ubuntu you maybe need to install `libssl-dev` and re-install the `eventmachine` gem.
63
+
64
+ You can test the SSL connection with `curl -XGET https://username:password@localhost:8088 -k` or
65
+ `openssl s_client -showcerts -connect localhost:8088`
66
+
67
+ ### Configuration
68
+
69
+ The configuration is written in YAML. To see an example have a look at `etc/example.yml`.
70
+
71
+ **Global configuration**
72
+ This section holds some global parameters:
73
+
74
+ ```YAML
75
+ global:
76
+ loglevel: 'debug'
77
+ logfile: 'app.log'
78
+ username: 'deployer'
79
+ password: 'Deploy1T'
80
+ ```
81
+
82
+ * *loglevel*: One of: debug, info, warn, error, fatal
83
+ * *logfile*: Path (including filename) to the application log
84
+ * *username*: Username for the basic authentication to the application
85
+ * *password*: Password for the basic authentication to the application
86
+
87
+ **Payload type specific configuration**
88
+ Per payload type configuration. Available payload types: vcs. (More to come)
89
+
90
+ **Payload type 'vcs'**
91
+ This is meant for payload types coming from a version control system like git.
92
+
93
+ ```YAML
94
+ vcs:
95
+ myrepo:
96
+ _all:
97
+ command: 'echo _all with branch <%= branch_name %>'
98
+ production:
99
+ command: '/usr/local/bin/deploy-my-app'
100
+ otherbranch:
101
+ command: '/bin/true'
102
+ myotherrepo:
103
+ master:
104
+ command: 'cd /my/local/path; /usr/bin/git pull'
105
+ _all:
106
+ master:
107
+ command: 'echo applies to all master branches of not specifically configured repos'
108
+ _all:
109
+ command: 'echo will be applied to ALL repos and branches if not more specifically configured'
110
+ ```
111
+
112
+ There should be an entry per repository. If needed there can be a catch-all name which applies
113
+ to all repositories: `_all`. On the next level comes the name of the branch. Here could also be a
114
+ catch-all name specified, also called `_all`.
115
+
116
+ The `command` parameter is parsed with the ERB templating system. Available variables:
117
+ * *branch_name*
118
+ * *repo_name*
119
+
120
+ **Examples:**
121
+
122
+ ```YAML
123
+ vcs:
124
+ repo1:
125
+ _all:
126
+ command: 'echo this is the branch <%= branch_name %>'
127
+ _all:
128
+ master:
129
+ command: 'echo this is the repo <%= repo_name.upcase %>'
130
+ ```
131
+
132
+ ### Testing
133
+
134
+ There are some tests in place using `minitest`. Run `rake test` to run all available test.
135
+ It should output a lot of log messages and at the end a summary of all test without any errors.
136
+ For the testcases to succeed, the configuration file `etc/example.yml` is used.
137
+
138
+ ## Contributing
139
+
140
+ 1. Fork it ( https://github.com/tobru/webhookd/fork )
141
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
142
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
143
+ 4. Push to the branch (`git push origin my-new-feature`)
144
+ 5. Create a new Pull Request
145
+
146
+ ### Payload types
147
+
148
+ Payload types are part of the business logic in `lib/webhookd/app.rb`.
149
+ It is defined in the payload endpoint in `lib/webhookd/payloadtype/<payloadtype>.rb`.
150
+ For an example have a look at `lib/webhookd/payloadtype/bitbucket.rb`.
151
+
152
+ Adding a new type would involve the following steps:
153
+ 1. Write a payload parser in `lib/webhookd/payloadtype/`
154
+ 1. Add business logic for the payload type in `lib/webhookd/app.rb` under `case parsed_data[:type]`
155
+
156
+ ### Payload parser
157
+
158
+ The payload parser parses the payload data received from the webhook sender into a standard hash
159
+ which will be consumed by the business logic to take action.
160
+
161
+ **vcs**
162
+
163
+ The `vcs` payload type has the following hash signature:
164
+
165
+ ```ruby
166
+ data[:type]
167
+ data[:source]
168
+ data[:repo_name]
169
+ data[:branch_name]
170
+ data[:author_name]
171
+ ```
172
+
173
+ ## TODO / Ideas
174
+
175
+ * Regex match for repository and branch names
176
+ * Notification mechanism (jabber, irc)
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs = ["lib", "test"]
6
+ t.name = "test"
7
+ t.test_files = FileList['test/test_*.rb']
8
+ end
9
+
10
+ task :default => :test
11
+
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+ bin_file = Pathname.new(__FILE__).realpath
5
+ $:.unshift File.expand_path("../../lib", bin_file)
6
+
7
+ require 'webhookd/cli'
8
+ Webhookd::CLI.start(ARGV)
@@ -0,0 +1,12 @@
1
+ begin
2
+ require 'webhookd'
3
+ rescue LoadError => e
4
+ require 'rubygems'
5
+ require 'bundler'
6
+ path = File.expand_path '../../lib', __FILE__
7
+ $:.unshift(path) if File.directory?(path) && !$:.include?(path)
8
+ Bundler.setup
9
+ require 'webhookd'
10
+ end
11
+
12
+ run Webhookd::App
@@ -0,0 +1,19 @@
1
+ ---
2
+ global:
3
+ loglevel: 'debug'
4
+ logfile: '/tmp/webhookd_dev.log'
5
+ username: 'deployer'
6
+ password: 'Deploy1T'
7
+ vcs:
8
+ puppet-control:
9
+ _all:
10
+ command: 'echo this is <%= branch_name %>'
11
+ production:
12
+ command: 'echo this is production'
13
+ nocommandbranch:
14
+ somethingunknown: 'whats that'
15
+ emptyconfigbranch:
16
+ encdata:
17
+ master:
18
+ command: 'git pull'
19
+
@@ -0,0 +1,12 @@
1
+ ---
2
+ global:
3
+ loglevel: 'debug'
4
+ logfile: '/var/log/webhookd.log'
5
+ username: 'myuser'
6
+ password: 'CHANGEME'
7
+ vcs:
8
+ myproject:
9
+ _all:
10
+ command: 'echo this is <%= branch_name %>'
11
+ master:
12
+ command: 'echo this is master'
@@ -0,0 +1,3 @@
1
+ module Webhookd
2
+ autoload :App, 'webhookd/app'
3
+ end
@@ -0,0 +1,149 @@
1
+ require 'sinatra/base'
2
+ require 'erb'
3
+ require 'thin'
4
+ require 'webhookd/version'
5
+ require 'webhookd/command_runner'
6
+ require 'webhookd/logging'
7
+ require 'webhookd/configuration'
8
+
9
+ module Webhookd
10
+ class App < Sinatra::Base
11
+ configuration_file = ENV["CONFIG_FILE"] || 'etc/example.yml'
12
+ Configuration.load!(configuration_file)
13
+ include Logging
14
+
15
+ # Sinatra configuration
16
+ set :show_exceptions, false
17
+ set server: 'thin', connections: [], history_file: 'history.yml'
18
+
19
+ # helpers
20
+ helpers do
21
+ def protected!
22
+ return if authorized?
23
+ headers['WWW-Authenticate'] = 'Basic realm="Webhookd authentication"'
24
+ halt 401, "Not authorized\n"
25
+ end
26
+
27
+ def authorized?
28
+ @auth ||= Rack::Auth::Basic::Request.new(request.env)
29
+ user = Configuration.settings[:global][:username]
30
+ password = Configuration.settings[:global][:password]
31
+ @auth.provided? and @auth.basic? and @auth.credentials and @auth.credentials == [user,password]
32
+ end
33
+ end
34
+
35
+ # error handling
36
+ not_found do
37
+ "Route not found. Do you know what you want to do?\n"
38
+ end
39
+
40
+ error do |err|
41
+ "I'm so sorry, there was an application error: #{err}\n"
42
+ end
43
+
44
+ ### Sinatra routes
45
+ # we don't have anything to show
46
+ get '/' do
47
+ protected!
48
+ logger.info "incoming request from #{request.ip} for GET /"
49
+ "I'm running. Nice, isn't it?\n"
50
+ end
51
+
52
+ post '/payload/:payloadtype' do
53
+ protected!
54
+ logger.info "incoming request from #{request.ip} for payload type #{params[:payloadtype]}"
55
+
56
+ begin
57
+ logger.debug "try to load webhookd/payloadtype/#{params[:payloadtype]}.rb"
58
+ load "webhookd/payloadtype/#{params[:payloadtype]}.rb"
59
+ rescue LoadError
60
+ logger.error "file not found: webhookd/payloadtype/#{params[:payloadtype]}.rb"
61
+ halt 400, "Payload type unknown\n"
62
+ end
63
+
64
+ parser = ParsePayload.new(request.body.read)
65
+ parsed_data = parser.parse
66
+
67
+ # see if the payloadtype is known
68
+ if Configuration.settings.has_key?(parsed_data[:type].to_sym)
69
+ case parsed_data[:type]
70
+ when 'vcs'
71
+ # reload configuration
72
+ Configuration.load!(configuration_file)
73
+
74
+ branch_name = parsed_data[:branch_name]
75
+ repo_name = parsed_data[:repo_name]
76
+ repo_config = nil
77
+ branch_config = nil
78
+ command = nil
79
+
80
+ # is the repository configured?
81
+ if Configuration.settings[:vcs].has_key?(repo_name.to_sym)
82
+ logger.debug "repository configuration found"
83
+ repo_config = Configuration.settings[:vcs][repo_name.to_sym]
84
+ elsif Configuration.settings[:vcs].has_key?(:_all)
85
+ logger.debug "repository configuration not found, but there is an '_all' rule"
86
+ repo_config = Configuration.settings[:vcs][:_all]
87
+ else
88
+ error_msg = "repository configuration not found: '#{repo_name}' is not configured\n"
89
+ logger.fatal error_msg
90
+ halt 500, "#{error_msg}\n"
91
+ end
92
+
93
+ # check if there is a repo_config available
94
+ if repo_config
95
+ # is the branch explicitely configured?
96
+ if repo_config.has_key?(branch_name.to_sym)
97
+ logger.debug "branch configuration found"
98
+ branch_config = repo_config[branch_name.to_sym]
99
+ elsif repo_config.has_key?(:_all)
100
+ logger.debug "branch configuration not found, but there is an '_all' rule"
101
+ branch_config = repo_config[:_all]
102
+ else
103
+ error_msg = "branch configuration not found: '#{branch_name}' in repo '#{repo_name}' is not configured\n"
104
+ logger.fatal error_msg
105
+ halt 500, "#{error_msg}\n"
106
+ end
107
+ end
108
+
109
+ # check if there is branch configuration data available
110
+ if branch_config
111
+ # is there a command configured?
112
+ if branch_config[:command]
113
+ command = branch_config[:command]
114
+ else
115
+ error_msg = "no command configuration found\n"
116
+ logger.fatal error_msg
117
+ halt 500, error_msg
118
+ end
119
+ else
120
+ error_msg = "branch configuration is empty\n"
121
+ logger.fatal error_msg
122
+ halt 500, error_msg
123
+ end
124
+
125
+ # check for a command to run and then run it
126
+ if command
127
+ parsed_command = ERB.new(command).result(binding)
128
+ command_runner = Commandrunner.new(parsed_command)
129
+ command_runner.run
130
+ end
131
+ # we don't know the type of this known payload
132
+ else
133
+ error_msg = "webhook payload type #{parsed_data[:type]} unknown"
134
+ logger.fatal error_msg
135
+ halt 500, "#{error_msg}\n"
136
+ end
137
+ # this type of payload is not configured
138
+ else
139
+ error_msg = "webhook payload of type #{parsed_data[:type]} not configured"
140
+ logger.info error_msg
141
+ halt 500, "#{error_msg}\n"
142
+ end
143
+
144
+ logger.debug "using configuration file #{configuration_file}"
145
+ # output to the requester
146
+ "webhook received\n"
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,57 @@
1
+ require 'thor'
2
+
3
+ module Webhookd
4
+ class CLI < Thor
5
+ include Thor::Actions
6
+
7
+ attr_reader :name
8
+
9
+ desc "start", "Starts the webhookd server"
10
+ method_option :config_file, :desc => "Path to the configuration file"
11
+ def start(*args)
12
+ port_option = args.include?('-p') ? '' : ' -p 8088'
13
+ args = args.join(' ')
14
+ command = "thin -R #{get_rackup_config} start#{port_option} #{args}"
15
+ command.prepend "export CONFIG_FILE=#{options[:config_file]}; " if options[:config_file]
16
+ begin
17
+ run_command(command)
18
+ rescue SystemExit, Interrupt
19
+ puts "Program interrupted"
20
+ exit
21
+ end
22
+ end
23
+
24
+ desc "stop", "Stops the thin server"
25
+ def stop
26
+ command = "thin -R #{get_rackup_config} stop"
27
+ run_command(command)
28
+ end
29
+
30
+ # map some commands
31
+ map 's' => :start
32
+
33
+ private
34
+
35
+ def get_rackup_config
36
+ begin
37
+ spec = Gem::Specification.find_by_name('webhookd')
38
+ "#{spec.gem_dir}/config.ru"
39
+ rescue Gem::LoadError
40
+ if File.exist?('/etc/webhookd/config.ru')
41
+ '/etc/webhookd/config.ru'
42
+ else
43
+ './config.ru'
44
+ end
45
+ end
46
+ end
47
+
48
+ def run_command(command)
49
+ system(command)
50
+ end
51
+
52
+ def require_file(file)
53
+ require file
54
+ end
55
+ end
56
+ end
57
+
@@ -0,0 +1,33 @@
1
+ require 'open3'
2
+ require 'webhookd/logging'
3
+
4
+ module Webhookd
5
+ class Commandrunner
6
+
7
+ include Logging
8
+
9
+ def initialize(command)
10
+ @command = command
11
+ end
12
+
13
+ def run
14
+ begin
15
+ logger.info "Running command: #{@command}"
16
+ Open3::popen2e(@command) { |stdin, stdout_err, wait_thr|
17
+ while line = stdout_err.gets
18
+ logger.debug("Command output: #{line.strip}")
19
+ end
20
+ if wait_thr.value.success?
21
+ logger.info "command successful"
22
+ return true
23
+ else
24
+ logger.error "command failed"
25
+ return false
26
+ end
27
+ }
28
+ rescue Exception => e
29
+ logger.fatal "Completely failed: #{e.message}"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ require 'yaml'
2
+
3
+ module Configuration
4
+ # we don't want to instantiate this class - it's a singleton,
5
+ # so just keep it as a self-extended module
6
+ extend self
7
+
8
+ @settings = {}
9
+ attr_reader :settings
10
+
11
+ def load!(filename, options = {})
12
+ begin
13
+ @settings = symbolize_keys(YAML::load_file(filename))
14
+ rescue Errno::ENOENT
15
+ puts "[FATAL] configuration file '#{filename}' not found. Exiting."; exit 1
16
+ rescue Psych::SyntaxError
17
+ puts "[FATAL] configuration file '#{filename}' contains invalid syntax. Exiting."; exit 1
18
+ end
19
+ end
20
+
21
+ def symbolize_keys(hash)
22
+ hash.inject({}){|result, (key, value)|
23
+ new_key = case key
24
+ when String then key.to_sym
25
+ else key
26
+ end
27
+ new_value = case value
28
+ when Hash then symbolize_keys(value)
29
+ else value
30
+ end
31
+ result[new_key] = new_value
32
+ result
33
+ }
34
+ end
35
+
36
+ end
@@ -0,0 +1,49 @@
1
+ require 'logger'
2
+ require 'webhookd/configuration'
3
+
4
+ module Logging
5
+ class MultiIO
6
+ def initialize(*targets)
7
+ @targets = targets
8
+ end
9
+
10
+ def write(*args)
11
+ @targets.each {|t| t.write(*args)}
12
+ end
13
+
14
+ def close
15
+ @targets.each(&:close)
16
+ end
17
+ end
18
+
19
+ # This is the magical bit that gets mixed into your classes
20
+ def logger
21
+ @logger ||= Logging.logger_for(self.class.name)
22
+ end
23
+
24
+ # Use a hash class-ivar to cache a unique Logger per class:
25
+ @loggers = {}
26
+
27
+ class << self
28
+ def logger_for(classname)
29
+ @loggers[classname] ||= configure_logger_for(classname)
30
+ end
31
+
32
+ def configure_logger_for(classname)
33
+ logfile = File.open(Configuration.settings[:global][:logfile], 'a')
34
+ logfile.sync = true
35
+ logger = Logger.new MultiIO.new(STDOUT, logfile)
36
+ case Configuration.settings[:global][:loglevel]
37
+ when 'debug' then logger.level = Logger::DEBUG
38
+ when 'info' then logger.level = Logger::INFO
39
+ when 'warn' then logger.level = Logger::WARN
40
+ when 'error' then logger.level = Logger::ERROR
41
+ when 'fatal' then logger.level = Logger::FATAL
42
+ when 'unknown' then logger.level = Logger::UNKNOWN
43
+ else logger.level = Logger::DEBUG
44
+ end
45
+ logger.progname = classname
46
+ logger
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,43 @@
1
+ require 'webhookd/logging'
2
+ module Webhookd
3
+ class ParsePayload
4
+
5
+ include Logging
6
+
7
+ def initialize(payload)
8
+ @payload = payload
9
+ end
10
+
11
+ def parse
12
+ require 'json'
13
+ logger.debug 'parsing payload type bitbucket'
14
+
15
+ prepared = URI.unescape(@payload.gsub("payload=","").gsub("+"," "))
16
+ json_parsed = JSON.parse(URI.unescape(prepared))
17
+ logger.debug "raw received data: #{json_parsed}"
18
+
19
+ # loop through commits to find the branch
20
+ branch_name = '_notfound'
21
+ author_name = '_notfound'
22
+ json_parsed['commits'].each do |commit|
23
+ if commit['branch']
24
+ branch_name = commit['branch']
25
+ author_name = commit['author']
26
+ break
27
+ end
28
+ end
29
+
30
+ data = Hash.new
31
+ data[:type] = 'vcs'
32
+ data[:source] = 'bitbucket'
33
+ data[:repo_name] = json_parsed['repository']['name']
34
+ data[:branch_name] = branch_name
35
+ data[:author_name] = author_name
36
+
37
+ logger.debug "parsed from the bitbucket data: #{data}"
38
+
39
+ # return the hash
40
+ data
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ require 'webhookd/logging'
2
+ module Webhookd
3
+ class ParsePayload
4
+
5
+ include Logging
6
+
7
+ def initialize(payload)
8
+ @payload = payload
9
+ end
10
+
11
+ def parse
12
+ require 'json'
13
+ logger.debug 'parsing payload type gitlab'
14
+
15
+ json_parsed = JSON.parse(@payload)
16
+ logger.debug "raw received data: #{json_parsed}"
17
+
18
+ data = Hash.new
19
+ data[:type] = 'vcs'
20
+ data[:source] = 'gitlab'
21
+ data[:repo_name] = json_parsed['repository']['name']
22
+ data[:branch_name] = json_parsed['ref'].split("/")[2]
23
+ data[:author_name] = json_parsed['user_name']
24
+
25
+ logger.debug "parsed from the gitlab data: #{data}"
26
+
27
+ # return the hash
28
+ data
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Webhookd
2
+ VERSION = "0.0.7"
3
+ end
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ curl -X POST --data 'payload=%7B%22repository%22%3A+%7B%22website%22%3A+%22%22%2C+%22fork%22%3A+false%2C+%22name%22%3A+%22puppet-control%22%2C+%22scm%22%3A+%22git%22%2C+%22owner%22%3A+%22theowner%22%2C+%22absolute_url%22%3A+%22%2Ftheowner%2Fpuppet-control%2F%22%2C+%22slug%22%3A+%22puppet-control%22%2C+%22is_private%22%3A+true%7D%2C+%22truncated%22%3A+false%2C+%22commits%22%3A+%5B%7B%22node%22%3A+%22634d71461df8%22%2C+%22files%22%3A+%5B%7B%22type%22%3A+%22modified%22%2C+%22file%22%3A+%22hooktest.txt%22%7D%5D%2C+%22raw_author%22%3A+%22Tobias+Brunner+%3Ctobias%40mydomain.ch%3E%22%2C+%22utctimestamp%22%3A+%222014-12-03+16%3A04%3A36%2B00%3A00%22%2C+%22author%22%3A+%22tobru%22%2C+%22timestamp%22%3A+%222014-12-03+17%3A04%3A36%22%2C+%22raw_node%22%3A+%22634d71461df82f2095f18955cf967b606cb25f84%22%2C+%22parents%22%3A+%5B%22d94b7645874e%22%5D%2C+%22branch%22%3A+%22production%22%2C+%22message%22%3A+%22hook+test+3%5Cn%22%2C+%22revision%22%3A+null%2C+%22size%22%3A+-1%7D%5D%2C+%22canon_url%22%3A+%22https%3A%2F%2Fbitbucket.org%22%2C+%22user%22%3A+%22tobru%22%7D' http://deployer:Deploy1T@localhost:8088/payload/bitbucket
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ curl -X POST --data 'payload=%7B%22repository%22%3A+%7B%22website%22%3A+%22%22%2C+%22fork%22%3A+false%2C+%22name%22%3A+%22puppet-control%22%2C+%22scm%22%3A+%22git%22%2C+%22owner%22%3A+%22theowner%22%2C+%22absolute_url%22%3A+%22%2Ftheowner%2Fpuppet-control%2F%22%2C+%22slug%22%3A+%22puppet-control%22%2C+%22is_private%22%3A+true%7D%2C+%22truncated%22%3A+false%2C+%22commits%22%3A+%5B%7B%22node%22%3A+%22634d71461df8%22%2C+%22files%22%3A+%5B%7B%22type%22%3A+%22modified%22%2C+%22file%22%3A+%22hooktest.txt%22%7D%5D%2C+%22raw_author%22%3A+%22Tobias+Brunner+%3Ctobias%40domain.com%3E%22%2C+%22utctimestamp%22%3A+%222014-12-03+16%3A04%3A36%2B00%3A00%22%2C+%22author%22%3A+%22tobru%22%2C+%22timestamp%22%3A+%222014-12-03+17%3A04%3A36%22%2C+%22raw_node%22%3A+%22634d71461df82f2095f18955cf967b606cb25f84%22%2C+%22parents%22%3A+%5B%22d94b7645874e%22%5D%2C+%22branch%22%3A+%22prorduction%22%2C+%22message%22%3A+%22hook+test+3%5Cn%22%2C+%22revision%22%3A+null%2C+%22size%22%3A+-1%7D%5D%2C+%22canon_url%22%3A+%22https%3A%2F%2Fbitbucket.org%22%2C+%22user%22%3A+%22tobru%22%7D' http://deployer:Deploy1T@localhost:8088/payload/bitbucket
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ curl -X POST --data 'payload=%7B%22repository%22%3A+%7B%22website%22%3A+%22%22%2C+%22fork%22%3A+false%2C+%22name%22%3A+%22puppet-control%22%2C+%22scm%22%3A+%22git%22%2C+%22owner%22%3A+%22theowner%22%2C+%22absolute_url%22%3A+%22%2Ftheowner%2Fpuppet-control%2F%22%2C+%22slug%22%3A+%22puppet-control%22%2C+%22is_private%22%3A+true%7D%2C+%22truncated%22%3A+false%2C+%22commits%22%3A+%5B%7B%22node%22%3A+%22634d71461df8%22%2C+%22files%22%3A+%5B%7B%22type%22%3A+%22modified%22%2C+%22file%22%3A+%22hooktest.txt%22%7D%5D%2C+%22raw_author%22%3A+%22Tobias+Brunner+%3Ctobias%40domain.com%3E%22%2C+%22utctimestamp%22%3A+%222014-12-03+16%3A04%3A36%2B00%3A00%22%2C+%22author%22%3A+%22tobru%22%2C+%22timestamp%22%3A+%222014-12-03+17%3A04%3A36%22%2C+%22raw_node%22%3A+%22634d71461df82f2095f18955cf967b606cb25f84%22%2C+%22parents%22%3A+%5B%22d94b7645874e%22%5D%2C+%22branch%22%3A+%22nocommandbranch%22%2C+%22message%22%3A+%22hook+test+3%5Cn%22%2C+%22revision%22%3A+null%2C+%22size%22%3A+-1%7D%5D%2C+%22canon_url%22%3A+%22https%3A%2F%2Fbitbucket.org%22%2C+%22user%22%3A+%22tobru%22%7D' http://deployer:Deploy1T@localhost:8088/payload/bitbucket
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ curl -X POST --data 'payload=%7B%22repository%22%3A+%7B%22website%22%3A+%22%22%2C+%22fork%22%3A+false%2C+%22name%22%3A+%22pudppet-control%22%2C+%22scm%22%3A+%22git%22%2C+%22owner%22%3A+%22theowner%22%2C+%22absolute_url%22%3A+%22%2Ftheowner%2Fpuppet-control%2F%22%2C+%22slug%22%3A+%22puppet-control%22%2C+%22is_private%22%3A+true%7D%2C+%22truncated%22%3A+false%2C+%22commits%22%3A+%5B%7B%22node%22%3A+%22634d71461df8%22%2C+%22files%22%3A+%5B%7B%22type%22%3A+%22modified%22%2C+%22file%22%3A+%22hooktest.txt%22%7D%5D%2C+%22raw_author%22%3A+%22Tobias+Brunner+%3Ctobias%40domain.com%3E%22%2C+%22utctimestamp%22%3A+%222014-12-03+16%3A04%3A36%2B00%3A00%22%2C+%22author%22%3A+%22tobru%22%2C+%22timestamp%22%3A+%222014-12-03+17%3A04%3A36%22%2C+%22raw_node%22%3A+%22634d71461df82f2095f18955cf967b606cb25f84%22%2C+%22parents%22%3A+%5B%22d94b7645874e%22%5D%2C+%22branch%22%3A+%22production%22%2C+%22message%22%3A+%22hook+test+3%5Cn%22%2C+%22revision%22%3A+null%2C+%22size%22%3A+-1%7D%5D%2C+%22canon_url%22%3A+%22https%3A%2F%2Fbitbucket.org%22%2C+%22user%22%3A+%22tobru%22%7D' http://deployer:Deploy1T@localhost:8088/payload/bitbucket
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ curl -X POST --data '{"before":"0d066524996aab4e849f9fec39bfd68c67e8f433","after":"2fb697300387b7b083ac339257e5fc21ebbab290","ref":"refs/heads/master","user_id":2,"user_name":"User Name","project_id":16,"repository":{"name":"unknownrepo","url":"git@git.domain.net:project/unknownrepo.git","description":"The unknownrepo","homepage":"https://git.domain.net"},"commits":[{"id":"2fb697300387b7b083ac339257e5fc21ebbab290","message":"a message","timestamp":"2015-01-16T16:50:35+01:00","url":"https://git.domain.net/project/unknownrepo/commit/2fb697300387b7b083ac339257e5fc21ebbab290","author":{"name":"The Author","email":"name@domain.net"}}],"total_commits_count":3}' http://deployer:Deploy1T@localhost:8088/payload/gitlab
@@ -0,0 +1,9 @@
1
+ # /etc/default/webhookd
2
+ # Configuration for Webhookd daemon init script
3
+ AS_USER=root
4
+ AS_GROUP=root
5
+ CONFIGFILE=/etc/webhookd/webhookd.yaml
6
+ PORT=8088
7
+ SSL=no
8
+ SSK_KEY=/etc/ssl/private/mykey.pem
9
+ SSL_CERT=/etc/ssl/certs/mycert.pem
@@ -0,0 +1,67 @@
1
+ #!/bin/bash
2
+
3
+ ### BEGIN INIT INFO
4
+ # Provides: webhookd_start
5
+ # Required-Start: $network $syslog
6
+ # Required-Stop:
7
+ # Default-Start: 2 3 4 5
8
+ # Default-Stop:
9
+ # Short-Description: Starts up the webhookd server
10
+ ### END INIT INFO
11
+
12
+ set -e
13
+
14
+ # Default settings
15
+ AS_USER=root
16
+ AS_GROUP=root
17
+ PORT=8088
18
+ CONFIGFILE=/etc/webhookd.yaml
19
+ SSL=no
20
+
21
+ # You should only need to edit the default/webhookd file and not
22
+ # this init script directly
23
+ if [ -r "/etc/default/webhookd" ] ; then
24
+ . /etc/default/webhookd
25
+ fi
26
+
27
+ SSL_PARAMS=""
28
+ if [ "${SSL}" == "yes" ] ; then
29
+ SSL_PARAMS="--ssl --ssl-key-file ${SSK_KEY} --ssl-cert-file ${SSL_CERT}"
30
+ fi
31
+
32
+ TIMEOUT=${TIMEOUT-60}
33
+ PID=/run/webhookd.${PORT}.pid
34
+ CMD="webhookd start -s1 -d -p ${PORT} -P /run/webhookd.pid --config-file=${CONFIGFILE} -d -u ${AS_USER} -g ${AS_GROUP} --tag webhookd ${SSL_PARAMS}"
35
+
36
+ set -u
37
+
38
+ sig () {
39
+ test -s "$PID" && kill -$1 `cat $PID`
40
+ }
41
+
42
+ run () {
43
+ eval $1
44
+ }
45
+
46
+ case "$1" in
47
+ start)
48
+ sig 0 && echo >&2 "Already running" && exit 0
49
+ run "$CMD"
50
+ ;;
51
+ status)
52
+ [ ! -e "$PID" ] && echo "Not running" && exit 0
53
+ sig 0 && echo >&2 "Running" && exit 0
54
+ ;;
55
+ stop)
56
+ sig QUIT && rm "$PID" && echo "Stopped" && exit 0
57
+ echo >&2 "Not running"
58
+ ;;
59
+ restart)
60
+ sig HUP && echo reloaded OK && exit 0
61
+ echo >&2 "Couldn't reload, starting '$CMD' instead"
62
+ run "$CMD"
63
+ ;;
64
+ *) echo "usage: $0 start|stop|restart" >&2
65
+ exit 1
66
+ ;;
67
+ esac
@@ -0,0 +1,14 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+
3
+ require 'bundler'
4
+ Bundler.require :default, :test
5
+
6
+ require 'minitest/autorun'
7
+ require 'rack/test'
8
+ require_relative '../lib/webhookd/app.rb'
9
+
10
+ include Rack::Test::Methods
11
+
12
+ def app
13
+ Webhookd::App
14
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'helper'
2
+
3
+ describe 'GET /' do
4
+ user = "deployer"
5
+ pass = "Deploy1T"
6
+ it 'should request authentication' do
7
+ get '/'
8
+ last_response.status.must_equal 401
9
+ end
10
+ it 'should respond with authentication' do
11
+ authorize user, pass
12
+ get '/'
13
+ assert last_response.ok?
14
+ assert last_response.body.must_match "I'm running. Nice, isn't it?"
15
+ end
16
+ # payload has a known repository and branch name (aka configured)
17
+ it 'should respond with 500 - webhook payload of type unknowntype not configured' do
18
+ authorize user, pass
19
+ post '/payload/unknowntype', 'payload' => 'empty'
20
+ assert_equal 400, last_response.status
21
+ assert last_response.body.must_match "Payload type unknown"
22
+ end
23
+ end
24
+
@@ -0,0 +1,49 @@
1
+ require 'base64'
2
+ require_relative 'helper'
3
+
4
+ describe 'Bitbucket payload' do
5
+ user = "deployer"
6
+ pass = "Deploy1T"
7
+ # payload has a known repository and branch name (aka configured)
8
+ it 'should output webhook received - known repo and branch' do
9
+ authorize user, pass
10
+ post '/payload/bitbucket', 'payload' => '%7B%22repository%22%3A %7B%22website%22%3A %22%22%2C %22fork%22%3A false%2C %22name%22%3A %22puppet-control%22%2C %22scm%22%3A %22git%22%2C %22owner%22%3A %22theowner%22%2C %22absolute_url%22%3A %22%2Ftheowner%2Fpuppet-control%2F%22%2C %22slug%22%3A %22puppet-control%22%2C %22is_private%22%3A true%7D%2C %22truncated%22%3A false%2C %22commits%22%3A %5B%7B%22node%22%3A %22634d71461df8%22%2C %22files%22%3A %5B%7B%22type%22%3A %22modified%22%2C %22file%22%3A %22hooktest.txt%22%7D%5D%2C %22raw_author%22%3A %22Tobias Brunner %3Ctobias%40domain.com%3E%22%2C %22utctimestamp%22%3A %222014-12-03 16%3A04%3A36%2B00%3A00%22%2C %22author%22%3A %22tobru%22%2C %22timestamp%22%3A %222014-12-03 17%3A04%3A36%22%2C %22raw_node%22%3A %22634d71461df82f2095f18955cf967b606cb25f84%22%2C %22parents%22%3A %5B%22d94b7645874e%22%5D%2C %22branch%22%3A %22production%22%2C %22message%22%3A %22hook test 3%5Cn%22%2C %22revision%22%3A null%2C %22size%22%3A -1%7D%5D%2C %22canon_url%22%3A %22https%3A%2F%2Fbitbucket.org%22%2C %22user%22%3A %22tobru%22%7D'
11
+ assert last_response.ok?
12
+ assert last_response.body.must_match "webhook received"
13
+ end
14
+ # payload has a known repository and unknown branch (uses '_all' branch)
15
+ it 'should output webhook received - known repo and unknown branch' do
16
+ authorize user, pass
17
+ post '/payload/bitbucket', 'payload' => '%7B%22repository%22%3A %7B%22website%22%3A %22%22%2C %22fork%22%3A false%2C %22name%22%3A %22puppet-control%22%2C %22scm%22%3A %22git%22%2C %22owner%22%3A %22theowner%22%2C %22absolute_url%22%3A %22%2Ftheowner%2Fpuppet-control%2F%22%2C %22slug%22%3A %22puppet-control%22%2C %22is_private%22%3A true%7D%2C %22truncated%22%3A false%2C %22commits%22%3A %5B%7B%22node%22%3A %22634d71461df8%22%2C %22files%22%3A %5B%7B%22type%22%3A %22modified%22%2C %22file%22%3A %22hooktest.txt%22%7D%5D%2C %22raw_author%22%3A %22Tobias Brunner %3Ctobias%40domain.com%3E%22%2C %22utctimestamp%22%3A %222014-12-03 16%3A04%3A36%2B00%3A00%22%2C %22author%22%3A %22tobru%22%2C %22timestamp%22%3A %222014-12-03 17%3A04%3A36%22%2C %22raw_node%22%3A %22634d71461df82f2095f18955cf967b606cb25f84%22%2C %22parents%22%3A %5B%22d94b7645874e%22%5D%2C %22branch%22%3A %22unknownbranch%22%2C %22message%22%3A %22hook test 3%5Cn%22%2C %22revision%22%3A null%2C %22size%22%3A -1%7D%5D%2C %22canon_url%22%3A %22https%3A%2F%2Fbitbucket.org%22%2C %22user%22%3A %22tobru%22%7D'
18
+ assert last_response.ok?
19
+ assert last_response.body.must_match "webhook received"
20
+ end
21
+ # payload has a known repository and branch without command configured
22
+ it 'should output 500 - no command configuration found' do
23
+ authorize user, pass
24
+ post '/payload/bitbucket', 'payload' => '%7B%22repository%22%3A %7B%22website%22%3A %22%22%2C %22fork%22%3A false%2C %22name%22%3A %22puppet-control%22%2C %22scm%22%3A %22git%22%2C %22owner%22%3A %22theowner%22%2C %22absolute_url%22%3A %22%2Ftheowner%2Fpuppet-control%2F%22%2C %22slug%22%3A %22puppet-control%22%2C %22is_private%22%3A true%7D%2C %22truncated%22%3A false%2C %22commits%22%3A %5B%7B%22node%22%3A %22634d71461df8%22%2C %22files%22%3A %5B%7B%22type%22%3A %22modified%22%2C %22file%22%3A %22hooktest.txt%22%7D%5D%2C %22raw_author%22%3A %22Tobias Brunner %3Ctobias%40domain.com%3E%22%2C %22utctimestamp%22%3A %222014-12-03 16%3A04%3A36%2B00%3A00%22%2C %22author%22%3A %22tobru%22%2C %22timestamp%22%3A %222014-12-03 17%3A04%3A36%22%2C %22raw_node%22%3A %22634d71461df82f2095f18955cf967b606cb25f84%22%2C %22parents%22%3A %5B%22d94b7645874e%22%5D%2C %22branch%22%3A %22nocommandbranch%22%2C %22message%22%3A %22hook test 3%5Cn%22%2C %22revision%22%3A null%2C %22size%22%3A -1%7D%5D%2C %22canon_url%22%3A %22https%3A%2F%2Fbitbucket.org%22%2C %22user%22%3A %22tobru%22%7D'
25
+ assert_equal 500, last_response.status
26
+ assert last_response.body.must_match "no command configuration found"
27
+ end
28
+ # payload has a known repository and branch without any configuration
29
+ it 'should output 500 - branch configuration is empty' do
30
+ authorize user, pass
31
+ post '/payload/bitbucket', 'payload' => '%7B%22repository%22%3A %7B%22website%22%3A %22%22%2C %22fork%22%3A false%2C %22name%22%3A %22puppet-control%22%2C %22scm%22%3A %22git%22%2C %22owner%22%3A %22theowner%22%2C %22absolute_url%22%3A %22%2Ftheowner%2Fpuppet-control%2F%22%2C %22slug%22%3A %22puppet-control%22%2C %22is_private%22%3A true%7D%2C %22truncated%22%3A false%2C %22commits%22%3A %5B%7B%22node%22%3A %22634d71461df8%22%2C %22files%22%3A %5B%7B%22type%22%3A %22modified%22%2C %22file%22%3A %22hooktest.txt%22%7D%5D%2C %22raw_author%22%3A %22Tobias Brunner %3Ctobias%40domain.com%3E%22%2C %22utctimestamp%22%3A %222014-12-03 16%3A04%3A36%2B00%3A00%22%2C %22author%22%3A %22tobru%22%2C %22timestamp%22%3A %222014-12-03 17%3A04%3A36%22%2C %22raw_node%22%3A %22634d71461df82f2095f18955cf967b606cb25f84%22%2C %22parents%22%3A %5B%22d94b7645874e%22%5D%2C %22branch%22%3A %22emptyconfigbranch%22%2C %22message%22%3A %22hook test 3%5Cn%22%2C %22revision%22%3A null%2C %22size%22%3A -1%7D%5D%2C %22canon_url%22%3A %22https%3A%2F%2Fbitbucket.org%22%2C %22user%22%3A %22tobru%22%7D'
32
+ assert_equal 500, last_response.status
33
+ assert last_response.body.must_match "branch configuration is empty"
34
+ end
35
+ # payload has a known repository and unknown branch and no '_all' configuration
36
+ it 'should output 500 - branch configuration not found: unknownbranch in repo encdata is not configured' do
37
+ authorize user, pass
38
+ post '/payload/bitbucket', 'payload' => '%7B%22repository%22%3A %7B%22website%22%3A %22%22%2C %22fork%22%3A false%2C %22name%22%3A %22encdata%22%2C %22scm%22%3A %22git%22%2C %22owner%22%3A %22theowner%22%2C %22absolute_url%22%3A %22%2Ftheowner%2Fencdata%2F%22%2C %22slug%22%3A %22encdata%22%2C %22is_private%22%3A true%7D%2C %22truncated%22%3A false%2C %22commits%22%3A %5B%7B%22node%22%3A %22634d71461df8%22%2C %22files%22%3A %5B%7B%22type%22%3A %22modified%22%2C %22file%22%3A %22hooktest.txt%22%7D%5D%2C %22raw_author%22%3A %22Tobias Brunner %3Ctobias%40domain.com%3E%22%2C %22utctimestamp%22%3A %222014-12-03 16%3A04%3A36%2B00%3A00%22%2C %22author%22%3A %22tobru%22%2C %22timestamp%22%3A %222014-12-03 17%3A04%3A36%22%2C %22raw_node%22%3A %22634d71461df82f2095f18955cf967b606cb25f84%22%2C %22parents%22%3A %5B%22d94b7645874e%22%5D%2C %22branch%22%3A %22unknownbranch%22%2C %22message%22%3A %22hook test 3%5Cn%22%2C %22revision%22%3A null%2C %22size%22%3A -1%7D%5D%2C %22canon_url%22%3A %22https%3A%2F%2Fbitbucket.org%22%2C %22user%22%3A %22tobru%22%7D'
39
+ assert_equal 500, last_response.status
40
+ assert last_response.body.must_match "branch configuration not found: 'unknownbranch' in repo 'encdata' is not configured"
41
+ end
42
+ # payload has a unknown repository
43
+ it 'should output 500 - repository configuration not found: unknownrepo is not configured' do
44
+ authorize user, pass
45
+ post '/payload/bitbucket', 'payload' => '%7B%22repository%22%3A %7B%22website%22%3A %22%22%2C %22fork%22%3A false%2C %22name%22%3A %22unknownrepo%22%2C %22scm%22%3A %22git%22%2C %22owner%22%3A %22theowner%22%2C %22absolute_url%22%3A %22%2Ftheowner%2Fencdata%2F%22%2C %22slug%22%3A %22encdata%22%2C %22is_private%22%3A true%7D%2C %22truncated%22%3A false%2C %22commits%22%3A %5B%7B%22node%22%3A %22634d71461df8%22%2C %22files%22%3A %5B%7B%22type%22%3A %22modified%22%2C %22file%22%3A %22hooktest.txt%22%7D%5D%2C %22raw_author%22%3A %22Tobias Brunner %3Ctobias%40domain.com%3E%22%2C %22utctimestamp%22%3A %222014-12-03 16%3A04%3A36%2B00%3A00%22%2C %22author%22%3A %22tobru%22%2C %22timestamp%22%3A %222014-12-03 17%3A04%3A36%22%2C %22raw_node%22%3A %22634d71461df82f2095f18955cf967b606cb25f84%22%2C %22parents%22%3A %5B%22d94b7645874e%22%5D%2C %22branch%22%3A %22unknownbranch%22%2C %22message%22%3A %22hook test 3%5Cn%22%2C %22revision%22%3A null%2C %22size%22%3A -1%7D%5D%2C %22canon_url%22%3A %22https%3A%2F%2Fbitbucket.org%22%2C %22user%22%3A %22tobru%22%7D'
46
+ assert_equal 500, last_response.status
47
+ assert last_response.body.must_match "repository configuration not found: 'unknownrepo' is not configured"
48
+ end
49
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'webhookd/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "webhookd"
8
+ spec.version = Webhookd::VERSION
9
+ spec.authors = ["Tobias Brunner"]
10
+ spec.email = ["tobias@tobru.ch"]
11
+ spec.summary = %q{Flexible, configurable universal webhook receiver}
12
+ spec.description = %q{This app is a flexible, configurable universal webhook receiver, built with sinatra. It can receive a webhook, parse its payload and take action according to the configuration.}
13
+ spec.homepage = "https://github.com/tobru/webhookd"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.default_executable = "webhookd"
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.7'
23
+ spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'rack-test', '>= 0.6.0'
25
+
26
+ spec.add_runtime_dependency 'sinatra', '~> 1.4', '>= 1.4.5'
27
+ spec.add_runtime_dependency 'thor', '~> 0.18', '>= 0.18.1'
28
+ spec.add_runtime_dependency 'thin', '~> 1.6', '>= 1.6.3'
29
+
30
+ end
metadata ADDED
@@ -0,0 +1,182 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: webhookd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.7
5
+ platform: ruby
6
+ authors:
7
+ - Tobias Brunner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack-test
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.6.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.6.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: sinatra
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.4'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.4.5
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '1.4'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.4.5
75
+ - !ruby/object:Gem::Dependency
76
+ name: thor
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.18'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 0.18.1
85
+ type: :runtime
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '0.18'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 0.18.1
95
+ - !ruby/object:Gem::Dependency
96
+ name: thin
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.6'
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 1.6.3
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '1.6'
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: 1.6.3
115
+ description: This app is a flexible, configurable universal webhook receiver, built
116
+ with sinatra. It can receive a webhook, parse its payload and take action according
117
+ to the configuration.
118
+ email:
119
+ - tobias@tobru.ch
120
+ executables:
121
+ - webhookd
122
+ extensions: []
123
+ extra_rdoc_files: []
124
+ files:
125
+ - ".gitignore"
126
+ - CHANGELOG.md
127
+ - Gemfile
128
+ - LICENSE
129
+ - README.md
130
+ - Rakefile
131
+ - bin/webhookd
132
+ - config.ru
133
+ - etc/example.yml
134
+ - etc/example.yml.dist
135
+ - lib/webhookd.rb
136
+ - lib/webhookd/app.rb
137
+ - lib/webhookd/cli.rb
138
+ - lib/webhookd/command_runner.rb
139
+ - lib/webhookd/configuration.rb
140
+ - lib/webhookd/logging.rb
141
+ - lib/webhookd/payloadtype/bitbucket.rb
142
+ - lib/webhookd/payloadtype/gitlab.rb
143
+ - lib/webhookd/version.rb
144
+ - scripts/test/curl-bitbucket-explicit-repo-and-branch.sh
145
+ - scripts/test/curl-bitbucket-explicit-repo-wrong-branch.sh
146
+ - scripts/test/curl-bitbucket-nocommand.sh
147
+ - scripts/test/curl-bitbucket-unknown-repo.sh
148
+ - scripts/test/curl-gitlab-unknown-repo.sh
149
+ - scripts/webhookd.default
150
+ - scripts/webhookd.init
151
+ - test/helper.rb
152
+ - test/test_basics.rb
153
+ - test/test_bitbucket.rb
154
+ - webhookd.gemspec
155
+ homepage: https://github.com/tobru/webhookd
156
+ licenses:
157
+ - MIT
158
+ metadata: {}
159
+ post_install_message:
160
+ rdoc_options: []
161
+ require_paths:
162
+ - lib
163
+ required_ruby_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ required_rubygems_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ requirements: []
174
+ rubyforge_project:
175
+ rubygems_version: 2.2.2
176
+ signing_key:
177
+ specification_version: 4
178
+ summary: Flexible, configurable universal webhook receiver
179
+ test_files:
180
+ - test/helper.rb
181
+ - test/test_basics.rb
182
+ - test/test_bitbucket.rb