build-buddy 1.0.6
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.
- checksums.yaml +7 -0
- data/bin/build-buddy +47 -0
- data/lib/build_buddy.rb +9 -0
- data/lib/build_buddy/builder.rb +80 -0
- data/lib/build_buddy/config.rb +28 -0
- data/lib/build_buddy/server.rb +288 -0
- data/lib/build_buddy/watcher.rb +17 -0
- metadata +204 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0b2d3eab19b59adf57beb5489d827f289c871f8e
|
4
|
+
data.tar.gz: b6ea074f9c8e13b36247c839715e549bc25428bc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 66842f29b1f61fd65b290d88e346fa364dcdce66585100f77370c5216ed673e3b2c4a8831c800084eab887f7ffc122549eded0d780b6eacdfe72b640c02a37fb
|
7
|
+
data.tar.gz: 20063e74483fc136eab52fbbb6a772491a1a6b6fd7f600a0d02b4efa22ecd3d9d4f1e255d627d897f9cf1ef1148c75388c2117449328fba45b2a3bd6b62aecbd
|
data/bin/build-buddy
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'celluloid/current'
|
6
|
+
require 'celluloid/supervision'
|
7
|
+
require 'celluloid/supervision/container'
|
8
|
+
require 'methadone'
|
9
|
+
require 'build_buddy'
|
10
|
+
|
11
|
+
class Tool
|
12
|
+
include Methadone::Main
|
13
|
+
include Methadone::CLILogging
|
14
|
+
|
15
|
+
main do |config_name|
|
16
|
+
config_file_name = config_name
|
17
|
+
|
18
|
+
if File.extname(config_file_name) != '.bbconfig'
|
19
|
+
config_file_name += '.bbconfig'
|
20
|
+
end
|
21
|
+
|
22
|
+
load config_file_name
|
23
|
+
|
24
|
+
build_log_dir = BuildBuddy::Config.build_log_dir
|
25
|
+
|
26
|
+
unless Dir.exist?(build_log_dir)
|
27
|
+
Dir.mkdir(build_log_dir)
|
28
|
+
end
|
29
|
+
|
30
|
+
Slack.configure do |config|
|
31
|
+
config.token = BuildBuddy::Config.slack_api_token
|
32
|
+
end
|
33
|
+
|
34
|
+
Celluloid.logger = Reel::Logger.logger
|
35
|
+
|
36
|
+
BuildBuddy::Builder.supervise as: :builder
|
37
|
+
BuildBuddy::Server.supervise as: :server
|
38
|
+
|
39
|
+
sleep
|
40
|
+
end
|
41
|
+
|
42
|
+
version BuildBuddy::VERSION
|
43
|
+
description 'Build Buddy'
|
44
|
+
arg :config_name, :required
|
45
|
+
|
46
|
+
go!
|
47
|
+
end
|
data/lib/build_buddy.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'celluloid'
|
4
|
+
require 'ostruct'
|
5
|
+
require_relative './watcher.rb'
|
6
|
+
require_relative './config.rb'
|
7
|
+
|
8
|
+
module BuildBuddy
|
9
|
+
class Builder
|
10
|
+
include Celluloid
|
11
|
+
include Celluloid::Internals::Logger
|
12
|
+
|
13
|
+
# TODO: Respond to request to kill the build.
|
14
|
+
# TODO: Kill the build pid after a certain amount of time has elapsed and report.
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@pid = nil
|
18
|
+
@watcher = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_build(build_data)
|
22
|
+
@build_data = build_data
|
23
|
+
repo_parts = build_data.repo_full_name.split('/')
|
24
|
+
command = "bash "
|
25
|
+
env = {
|
26
|
+
"GIT_REPO_OWNER" => repo_parts[0],
|
27
|
+
"GIT_REPO_NAME" => repo_parts[1],
|
28
|
+
"RBENV_DIR" => nil,
|
29
|
+
"RBENV_VERSION" => nil,
|
30
|
+
"PATH" => ENV['PATH'].split(':').select { |v| !v.match(/\.rbenv\/versions/) }.join(':')
|
31
|
+
}
|
32
|
+
|
33
|
+
case build_data.build_type
|
34
|
+
when :pull_request
|
35
|
+
env["GIT_PULL_REQUEST"] = build_data.pull_request.to_s
|
36
|
+
command += Config.pull_request_build_script
|
37
|
+
when :master
|
38
|
+
command += Config.master_build_script
|
39
|
+
when :release
|
40
|
+
env["GIT_BRANCH"] = build_data.build_version
|
41
|
+
command += Config.release_build_script
|
42
|
+
else
|
43
|
+
raise "Unknown build type"
|
44
|
+
end
|
45
|
+
|
46
|
+
build_log_filename = File.join(Config.build_log_dir, "build_#{build_data.build_type.to_s}_#{Time.now.utc.strftime('%Y%m%d%H%M%S')}.log")
|
47
|
+
build_data.build_log_filename = build_log_filename
|
48
|
+
|
49
|
+
command += " >#{build_log_filename} 2>&1"
|
50
|
+
|
51
|
+
Bundler.with_clean_env do
|
52
|
+
@pid = Process.spawn(env, command)
|
53
|
+
end
|
54
|
+
info "Running '#{command}' (process #{@pid})"
|
55
|
+
|
56
|
+
if @watcher
|
57
|
+
@watcher.terminate
|
58
|
+
end
|
59
|
+
|
60
|
+
@watcher = Watcher.new(@pid)
|
61
|
+
@watcher.async.watch_pid
|
62
|
+
end
|
63
|
+
|
64
|
+
def process_done(status)
|
65
|
+
@build_data.termination_type = (status.signaled? ? :killed : :exited)
|
66
|
+
@build_data.exit_code = (status.exited? ? status.exitstatus : -1)
|
67
|
+
info "Process #{status.pid} #{@build_data.termination_type == :killed ? 'was terminated' : "exited (#{@build_data.exit_code})"}"
|
68
|
+
Celluloid::Actor[:server].async.on_build_completed(@build_data)
|
69
|
+
@watcher.terminate
|
70
|
+
@watcher = nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def stop_build
|
74
|
+
if @pid
|
75
|
+
info "Killing pid #{@pid}"
|
76
|
+
Process.kill(:SIGABRT, @pid)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module BuildBuddy
|
2
|
+
module Config
|
3
|
+
extend self
|
4
|
+
|
5
|
+
attr_accessor :github_webhook_secret_token
|
6
|
+
attr_accessor :github_webhook_repo_full_name
|
7
|
+
attr_accessor :github_api_token
|
8
|
+
attr_accessor :slack_api_token
|
9
|
+
attr_accessor :slack_build_channel
|
10
|
+
attr_accessor :slack_builders
|
11
|
+
attr_accessor :xcode_workspace
|
12
|
+
attr_accessor :xcode_test_scheme
|
13
|
+
attr_accessor :build_log_dir
|
14
|
+
attr_accessor :pull_request_build_script
|
15
|
+
attr_accessor :master_build_script
|
16
|
+
attr_accessor :release_build_script
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def configure
|
21
|
+
block_given? ? yield(Config) : Config
|
22
|
+
end
|
23
|
+
|
24
|
+
def config
|
25
|
+
Config
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,288 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'celluloid/current'
|
3
|
+
require 'reel'
|
4
|
+
require 'slack-ruby-client'
|
5
|
+
require 'json'
|
6
|
+
require 'ostruct'
|
7
|
+
require 'octokit'
|
8
|
+
require 'thread'
|
9
|
+
require 'timers'
|
10
|
+
require 'rack'
|
11
|
+
require_relative './builder.rb'
|
12
|
+
|
13
|
+
module BuildBuddy
|
14
|
+
class Server < Reel::Server::HTTP
|
15
|
+
include Celluloid::Internals::Logger
|
16
|
+
|
17
|
+
def initialize(host = "127.0.0.1", port = 4567)
|
18
|
+
super(host, port, &method(:on_connection))
|
19
|
+
@gh_client ||= Octokit::Client.new(:access_token => Config.github_api_token)
|
20
|
+
@rt_client = Slack::RealTime::Client.new
|
21
|
+
@rt_client.on :hello do
|
22
|
+
self.on_slack_hello()
|
23
|
+
end
|
24
|
+
@rt_client.on :message do |data|
|
25
|
+
self.on_slack_data(data)
|
26
|
+
end
|
27
|
+
@rt_client.on :error do |error|
|
28
|
+
self.on_slack_error(error)
|
29
|
+
end
|
30
|
+
@rt_client.start_async
|
31
|
+
@active_build = nil
|
32
|
+
@build_queue = Queue.new
|
33
|
+
@done_queue = Queue.new
|
34
|
+
@notify_slack_channel = nil
|
35
|
+
@reverse_user_map = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_slack_error(error)
|
39
|
+
sub_error = error['error']
|
40
|
+
error "Whoops! Slack error #{sub_error['code']} - #{sub_error['msg']}}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_slack_hello
|
44
|
+
user_id = @rt_client.self['id']
|
45
|
+
user_map = @rt_client.users.map {|user| [user['name'], user['id']]}.to_h
|
46
|
+
@reverse_user_map = user_map.invert
|
47
|
+
info "Connected to Slack as user id #{user_id} (@#{@reverse_user_map[user_id]})"
|
48
|
+
|
49
|
+
channel_map = @rt_client.channels.map {|channel| [channel['name'], channel['id']]}.to_h
|
50
|
+
group_map = @rt_client.groups.map {|group| [group['name'], group['id']]}.to_h
|
51
|
+
channel = Config.slack_build_channel
|
52
|
+
is_channel = (channel[0] == '#')
|
53
|
+
|
54
|
+
@notify_slack_channel = (is_channel ? channel_map[channel[1..-1]] : group_map[channel])
|
55
|
+
if @notify_slack_channel.nil?
|
56
|
+
error "Unable to identify the slack channel #{channel}"
|
57
|
+
else
|
58
|
+
info "Slack notification channel is #{@notify_slack_channel} (#{channel})"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def on_slack_data(data)
|
63
|
+
message = data['text']
|
64
|
+
|
65
|
+
# If no message, then there's nothing to do
|
66
|
+
if message.nil?
|
67
|
+
return
|
68
|
+
end
|
69
|
+
|
70
|
+
sending_user_id = data['user']
|
71
|
+
sending_user_name = @reverse_user_map[sending_user_id]
|
72
|
+
|
73
|
+
# Don't respond if _we_ sent the message!
|
74
|
+
if sending_user_id == @rt_client.self['id']
|
75
|
+
return
|
76
|
+
end
|
77
|
+
|
78
|
+
sender_is_a_builder = (Config.slack_builders.nil? ? true : Config.slack_builders.include?('@' + sending_user_name))
|
79
|
+
|
80
|
+
c = data['channel'][0]
|
81
|
+
in_channel = (c == 'C' || c == 'G')
|
82
|
+
|
83
|
+
# Don't respond if the message is to a channel and our name is not in the message
|
84
|
+
if in_channel and !message.match(@rt_client.self['id'])
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
88
|
+
case message
|
89
|
+
when /build/i
|
90
|
+
unless sender_is_a_builder
|
91
|
+
if in_channel
|
92
|
+
response = "I'm sorry @#{sending_user_name} you are not on my list of allowed builders."
|
93
|
+
else
|
94
|
+
response = "I'm sorry but you are not on my list of allowed builders."
|
95
|
+
end
|
96
|
+
else
|
97
|
+
case message
|
98
|
+
when /master/i
|
99
|
+
response = "OK, I've queued a build of the `master` branch."
|
100
|
+
queue_a_build(OpenStruct.new(
|
101
|
+
:build_type => :master,
|
102
|
+
:repo_full_name => Config.github_webhook_repo_full_name))
|
103
|
+
when /(?<version>v\d+\.\d+)/
|
104
|
+
version = $~[:version]
|
105
|
+
response = "OK, I've queued a build of `#{version}` branch."
|
106
|
+
queue_a_build(OpenStruct.new(
|
107
|
+
:build_type => :release,
|
108
|
+
:build_version => version,
|
109
|
+
:repo_full_name => Config.github_webhook_repo_full_name))
|
110
|
+
when /stop/i
|
111
|
+
build_data = @active_build
|
112
|
+
if build_data.nil?
|
113
|
+
response = "There is no build running to stop"
|
114
|
+
else
|
115
|
+
# TODO: We need some more checks here to avoid accidental stoppage
|
116
|
+
response = "OK, I'm trying to *stop* the currently running build..."
|
117
|
+
Celluloid::Actor[:builder].async.stop_build
|
118
|
+
end
|
119
|
+
else
|
120
|
+
response = "Sorry#{in_channel ? " <@#{data['user']}>" : ""}, I'm not sure if you want do an internal *master*, external *M.m* build, or maybe *stop* any running build?"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
when /status/i
|
124
|
+
build_data = @active_build
|
125
|
+
queue_length = @build_queue.length
|
126
|
+
if build_data == nil
|
127
|
+
response = "There is currently no build running"
|
128
|
+
if queue_length == 0
|
129
|
+
response += " and no builds in the queue."
|
130
|
+
else
|
131
|
+
response += " and #{queue_length} in the queue."
|
132
|
+
end
|
133
|
+
else
|
134
|
+
case build_data.build_type
|
135
|
+
when :pull_request
|
136
|
+
response = "There is a pull request build in progress for https://github.com/#{build_data.repo_full_name}/pull/#{build_data.pull_request}."
|
137
|
+
when :master
|
138
|
+
response = "There is a build of the `master` branch of https://github.com/#{build_data.repo_full_name} in progress."
|
139
|
+
when :release
|
140
|
+
response = "There is a build of the `#{build_data.build_version}` branch of https://github.com/#{build_data.repo_full_name} in progress."
|
141
|
+
end
|
142
|
+
if queue_length == 1
|
143
|
+
response += " There is one build in the queue."
|
144
|
+
elsif queue_length > 1
|
145
|
+
response += " There are #{queue_length} builds in the queue."
|
146
|
+
end
|
147
|
+
end
|
148
|
+
when /help/i, /what can/i
|
149
|
+
# TODO: The repository should be a link to GitHub
|
150
|
+
response = %Q(Hello#{in_channel ? " <@#{data['user']}>" : ""}, I'm the *@#{@rt_client.self['name']}* build bot! I look after 3 types of build: pull request, master and release.
|
151
|
+
|
152
|
+
A pull request *build* happens when you make a pull request to the *#{Config.github_webhook_repo_full_name}* GitHub repository. I can stop those builds if you ask me too through Slack, but you have to start them with a pull request.
|
153
|
+
|
154
|
+
I can run builds of the *master* branch when you ask me, as well as doing builds of a release branch, e.g. *v1.0*, *v2.3*, etc..
|
155
|
+
|
156
|
+
You can also ask me about the *status* of builds and I'll tell you if anything is currently happening.
|
157
|
+
|
158
|
+
I am configured to let the *\##{Config.slack_build_channel}* channel know if master or release builds fail. Note the words I have highlighted in bold. These are the keywords that I'll look for to understand what you are asking me.
|
159
|
+
)
|
160
|
+
else
|
161
|
+
response = "Sorry#{in_channel ? " <@#{data['user']}>" : ""}, I'm not sure how to respond."
|
162
|
+
end
|
163
|
+
@rt_client.message channel: data['channel'], text: response
|
164
|
+
info "Slack message '#{message}' from #{data['channel']} handled"
|
165
|
+
end
|
166
|
+
|
167
|
+
def on_connection(connection)
|
168
|
+
connection.each_request do |request|
|
169
|
+
case request.method
|
170
|
+
when 'POST'
|
171
|
+
case request.path
|
172
|
+
when '/webhook'
|
173
|
+
case request.headers["X-GitHub-Event"]
|
174
|
+
when 'pull_request'
|
175
|
+
payload_text = request.body.to_s
|
176
|
+
# TODO: Also need to validate that it's the github_webhook_repo_full_name
|
177
|
+
if !verify_signature(payload_text, request.headers["X-Hub-Signature"])
|
178
|
+
request.respond 500, "Signatures didn't match!"
|
179
|
+
else
|
180
|
+
payload = JSON.parse(payload_text)
|
181
|
+
pull_request = payload['pull_request']
|
182
|
+
build_data = OpenStruct.new(
|
183
|
+
:build_type => :pull_request,
|
184
|
+
:pull_request => pull_request['number'],
|
185
|
+
:repo_sha => pull_request['head']['sha'],
|
186
|
+
:repo_full_name => pull_request['base']['repo']['full_name'])
|
187
|
+
info "Got pull request #{build_data[:pull_request]} from GitHub"
|
188
|
+
queue_a_build(build_data)
|
189
|
+
request.respond 200
|
190
|
+
end
|
191
|
+
when 'ping'
|
192
|
+
request.respond 200, "Running"
|
193
|
+
else
|
194
|
+
request.respond 404, "Path not found"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
else
|
198
|
+
request.respond 404, "Method not supported"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def queue_a_build(build_data)
|
204
|
+
@build_queue.push(build_data)
|
205
|
+
|
206
|
+
case build_data.build_type
|
207
|
+
when :pull_request
|
208
|
+
@gh_client.create_status(
|
209
|
+
build_data.repo_full_name, build_data.repo_sha, 'pending',
|
210
|
+
{ :description => "This build is in the queue" })
|
211
|
+
info "Pull request build queued"
|
212
|
+
when :master
|
213
|
+
info "Internal build queued"
|
214
|
+
when :release
|
215
|
+
info "External build queued"
|
216
|
+
end
|
217
|
+
|
218
|
+
if @build_timer.nil?
|
219
|
+
@build_timer = every(5) { on_build_interval }
|
220
|
+
info "Build timer started"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def on_build_interval
|
225
|
+
if @active_build.nil?
|
226
|
+
if @build_queue.length > 0
|
227
|
+
build_data = @build_queue.pop()
|
228
|
+
@active_build = build_data
|
229
|
+
# TODO: Add timing information into the build_data
|
230
|
+
if build_data.build_type == :pull_request
|
231
|
+
@gh_client.create_status(
|
232
|
+
build_data.repo_full_name, build_data.repo_sha, 'pending',
|
233
|
+
{ :description => "This build has started" })
|
234
|
+
end
|
235
|
+
Celluloid::Actor[:builder].async.start_build(build_data)
|
236
|
+
elsif @done_queue.length > 0
|
237
|
+
# TODO: Should pop everything in the done queue
|
238
|
+
build_data = @done_queue.pop
|
239
|
+
term_msg = (build_data.termination_type == :killed ? "was stopped" : "completed")
|
240
|
+
if build_data.termination_type == :exited
|
241
|
+
if build_data.exit_code != 0
|
242
|
+
term_msg += " with errors (exit code #{build_data.exit_code}). See log file `#{build_data.build_log_filename}` for more details."
|
243
|
+
else
|
244
|
+
term_msg += " successfully"
|
245
|
+
end
|
246
|
+
end
|
247
|
+
if build_data.build_type == :pull_request
|
248
|
+
description = "The buddy build #{term_msg}"
|
249
|
+
@gh_client.create_status(
|
250
|
+
build_data.repo_full_name, build_data.repo_sha,
|
251
|
+
build_data.termination_type == :killed ? 'failure' : build_data.exit_code != 0 ? 'error' : 'success',
|
252
|
+
{ :description => description })
|
253
|
+
info "Pull request build #{term_msg}"
|
254
|
+
else
|
255
|
+
case build_data.build_type
|
256
|
+
when :master
|
257
|
+
message = "A build of the `master` branch #{term_msg}."
|
258
|
+
info "Internal build #{term_msg}"
|
259
|
+
when :release
|
260
|
+
message = "A build of the `#{build_data.build_version}` branch #{term_msg}."
|
261
|
+
info "External build #{term_msg}"
|
262
|
+
end
|
263
|
+
unless @notify_slack_channel.nil?
|
264
|
+
@rt_client.message(channel: @notify_slack_channel, text: message)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
else
|
268
|
+
@build_timer.cancel
|
269
|
+
@build_timer = nil
|
270
|
+
info "Build timer stopped"
|
271
|
+
end
|
272
|
+
else
|
273
|
+
# TODO: Make sure that the build has not run too long and kill if necessary
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def on_build_completed(build_data)
|
278
|
+
@active_build = nil
|
279
|
+
@done_queue.push(build_data)
|
280
|
+
end
|
281
|
+
|
282
|
+
def verify_signature(payload_body, gh_signature)
|
283
|
+
signature = 'sha1=' + OpenSSL::HMAC.hexdigest(
|
284
|
+
OpenSSL::Digest.new('sha1'), Config.github_webhook_secret_token, payload_body)
|
285
|
+
Rack::Utils.secure_compare(signature, gh_signature)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'celluloid'
|
3
|
+
|
4
|
+
module BuildBuddy
|
5
|
+
class Watcher
|
6
|
+
include Celluloid
|
7
|
+
|
8
|
+
def initialize(pid)
|
9
|
+
@pid = pid
|
10
|
+
end
|
11
|
+
|
12
|
+
def watch_pid
|
13
|
+
Process.waitpid2(@pid)
|
14
|
+
Celluloid::Actor[:builder].async.process_done($?)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: build-buddy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Lyon-smith
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: timers
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: celluloid
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.17.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.17.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: celluloid-supervision
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.20.5
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.20.5
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: methadone
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.9'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.9'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: slack-ruby-client
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.5.3
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.5.3
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: json
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.8'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.8'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: http
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: reel
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.6.0.pre3
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.6.0.pre3
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: octokit
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '4.2'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '4.2'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rack
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '1.6'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '1.6'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: code-tools
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '5.0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '5.0'
|
167
|
+
description: A build buddy bot with GitHub and Slack integration.
|
168
|
+
email: john@jamoki.com
|
169
|
+
executables:
|
170
|
+
- build-buddy
|
171
|
+
extensions: []
|
172
|
+
extra_rdoc_files: []
|
173
|
+
files:
|
174
|
+
- bin/build-buddy
|
175
|
+
- lib/build_buddy.rb
|
176
|
+
- lib/build_buddy/builder.rb
|
177
|
+
- lib/build_buddy/config.rb
|
178
|
+
- lib/build_buddy/server.rb
|
179
|
+
- lib/build_buddy/watcher.rb
|
180
|
+
homepage: http://rubygems.org/gems/build-buddy
|
181
|
+
licenses:
|
182
|
+
- MIT
|
183
|
+
metadata: {}
|
184
|
+
post_install_message:
|
185
|
+
rdoc_options: []
|
186
|
+
require_paths:
|
187
|
+
- lib
|
188
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - "~>"
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '2.2'
|
193
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
194
|
+
requirements:
|
195
|
+
- - ">="
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0'
|
198
|
+
requirements: []
|
199
|
+
rubyforge_project:
|
200
|
+
rubygems_version: 2.4.5
|
201
|
+
signing_key:
|
202
|
+
specification_version: 4
|
203
|
+
summary: An automated build buddy
|
204
|
+
test_files: []
|