webhookd 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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