build-buddy 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 16fb9e784891a36a8605bfb28a2dc0b6732bddfe
4
- data.tar.gz: cea6d9d71a7cbf7fc60a7bcd2f616f3b528a6e7e
3
+ metadata.gz: 329f4a21f34dfda0663a97f4d74b691bba541491
4
+ data.tar.gz: 7f3da88951d7fd2a1a7bd982cc324eb550a82e0d
5
5
  SHA512:
6
- metadata.gz: 45137cb1f04cf4ef5ff8bbf5a175284b6dc688d92e7860d3399dba051fdee8a69c2c20df26fa0704637dea133193c154ee970fab188dad22441010476342f17e
7
- data.tar.gz: 8bd2411712d0deba74f0043d793a0f55d01decba069e986355e6ab24a8383dd89e5bdad9a9d312c1e3f4015ecbe7b950f82672153af1f5d398b376ce8d316abb
6
+ metadata.gz: 0608f25926cd5646ea0665b86e53d1a5a1aa18079504a9d166dc99fb8ab85cd3c21e34f47566a8504bd6f8f598ef5569e67bea6112e901124ad6249735f20665
7
+ data.tar.gz: 5d5e776f0f9115d2636f3f8095132d8da9316e4d33acb39b208a2fc6ebca5f8016d926fead214a012670e784a438b0dbb8652829d2aaeeb8d746613d749ab37f
data/bin/build-buddy CHANGED
@@ -41,9 +41,16 @@ module BuildBuddy
41
41
  Celluloid.logger = Reel::Logger.logger
42
42
 
43
43
  Builder.supervise as: :builder
44
+ Slacker.supervise as: :slacker
45
+ Gitter.supervise as: :gitter
46
+ Scheduler.supervise as: :scheduler
44
47
  Server.supervise as: :server
45
48
 
46
- sleep
49
+ begin
50
+ sleep
51
+ rescue Interrupt => e
52
+ puts
53
+ end
47
54
  end
48
55
 
49
56
  version BuildBuddy::VERSION
data/lib/build_buddy.rb CHANGED
@@ -1,9 +1,12 @@
1
1
  require 'build_buddy/config'
2
- require 'build_buddy/server'
2
+ require 'build_buddy/slacker'
3
+ require 'build_buddy/gitter'
3
4
  require 'build_buddy/builder'
4
5
  require 'build_buddy/watcher'
6
+ require 'build_buddy/scheduler'
7
+ require 'build_buddy/server'
5
8
  require 'build_buddy/build_data'
6
9
 
7
10
  module BuildBuddy
8
- VERSION = "1.3.1"
11
+ VERSION = "1.4.0"
9
12
  end
@@ -6,7 +6,7 @@ module BuildBuddy
6
6
  attr_accessor :pull_request
7
7
  attr_accessor :repo_full_name
8
8
  attr_accessor :repo_sha
9
- attr_accessor :termination_type
9
+ attr_accessor :termination_type # :killed or :exited
10
10
  attr_accessor :exit_code
11
11
  attr_accessor :start_time
12
12
  attr_accessor :end_time
@@ -1,7 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'bundler'
3
3
  require 'celluloid'
4
- require 'ostruct'
5
4
  require_relative './watcher.rb'
6
5
  require_relative './config.rb'
7
6
 
@@ -70,7 +69,7 @@ module BuildBuddy
70
69
  @build_data.termination_type = (status.signaled? ? :killed : :exited)
71
70
  @build_data.exit_code = (status.exited? ? status.exitstatus : -1)
72
71
  info "Process #{status.pid} #{@build_data.termination_type == :killed ? 'was terminated' : "exited (#{@build_data.exit_code})"}"
73
- Celluloid::Actor[:server].async.on_build_completed(@build_data)
72
+ Celluloid::Actor[:scheduler].async.on_build_completed(@build_data)
74
73
  @watcher.terminate
75
74
  @watcher = nil
76
75
  end
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'celluloid'
4
+ require 'octokit'
5
+ require_relative './config.rb'
6
+
7
+ module BuildBuddy
8
+ class Gitter
9
+ include Celluloid
10
+ include Celluloid::Internals::Logger
11
+
12
+ def initialize()
13
+ @gh_client ||= Octokit::Client.new(:access_token => Config.github_api_token)
14
+ info "Connected to Github"
15
+ end
16
+
17
+ def set_status(repo_full_name, repo_sha, status, description)
18
+ @gh_client.create_status(
19
+ repo_full_name, repo_sha, status.to_s, { :description => description.length > 140 ? "#{description[0..136]}..." : description})
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,106 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'celluloid'
4
+ require 'timers'
5
+ require_relative './config.rb'
6
+
7
+ module BuildBuddy
8
+ class Scheduler
9
+ include Celluloid
10
+ include Celluloid::Internals::Logger
11
+
12
+ attr_reader :active_build
13
+
14
+ def initialize()
15
+ @build_queue = Queue.new
16
+ @done_queue = Queue.new
17
+ @build_timer = nil
18
+ end
19
+
20
+ def queue_a_build(build_data)
21
+ @build_queue.push(build_data)
22
+
23
+ case build_data.build_type
24
+ when :pull_request
25
+ Celluloid::Actor[:gitter].async.set_status(
26
+ build_data.repo_full_name, build_data.repo_sha, :pending, "This build is in the queue")
27
+ info "Pull request build queued"
28
+ when :master
29
+ info "`master` branch build queued"
30
+ when :release
31
+ info "Release branch build queued"
32
+ end
33
+
34
+ if @build_timer.nil?
35
+ @build_timer = every(5) { on_build_interval }
36
+ info "Build timer started"
37
+ end
38
+ end
39
+
40
+ def queue_length
41
+ @build_queue.length
42
+ end
43
+
44
+ def stop_build
45
+ # Centralize stopping bulids here in case we allow multiple active builders in future
46
+ unless @active_build.nil?
47
+ Celluloid::Actor[:builder].stop_build
48
+ true
49
+ else
50
+ false
51
+ end
52
+ end
53
+
54
+ def on_build_interval
55
+ if @active_build.nil?
56
+ if @build_queue.length > 0
57
+ build_data = @build_queue.pop()
58
+ @active_build = build_data
59
+ if build_data.build_type == :pull_request
60
+ Celluloid::Actor[:gitter].async.set_status(
61
+ build_data.repo_full_name, build_data.repo_sha, :pending, "This build has started")
62
+ end
63
+ Celluloid::Actor[:builder].async.start_build(build_data)
64
+ elsif @done_queue.length > 0
65
+ build_data = @done_queue.pop
66
+ status_message = build_data.termination_type == :killed ? "was stopped" : build_data.exit_code != 0 ? "failed" : "succeeded"
67
+
68
+ if build_data.build_type == :pull_request
69
+ message = "The buddy build #{status_message}"
70
+ Celluloid::Actor[:gitter].async.set_status(
71
+ build_data.repo_full_name, build_data.repo_sha,
72
+ build_data.termination_type == :killed ? :failure : build_data.exit_code != 0 ? :error : :success,
73
+ message)
74
+ info "Pull request build #{status_message}"
75
+ else
76
+ if build_data.exit_code != 0
77
+ status_message += ". Exit code #{build_data.exit_code}, log file `#{build_data.build_log_filename}`."
78
+ end
79
+ if build_data.build_type == :master
80
+ message = "A build of the `master` branch #{status_message}"
81
+ info "`master` branch build #{status_message}"
82
+ else
83
+ message = "A build of the `#{build_data.build_version}` branch #{status_message}"
84
+ info "Release branch build #{status_message}"
85
+ end
86
+ Celluloid::Actor[:slacker].async.notify_channel(message)
87
+ end
88
+ else
89
+ @build_timer.cancel
90
+ @build_timer = nil
91
+ info "Build timer stopped"
92
+ end
93
+ else
94
+ # Make sure that the build has not run too long and kill if necessary
95
+ if Time.now.utc - @active_build.start_time > Config.kill_build_after_mins * 60
96
+ Celluloid::Actor[:builder].async.stop_build()
97
+ end
98
+ end
99
+ end
100
+
101
+ def on_build_completed(build_data)
102
+ @active_build = nil
103
+ @done_queue.push(build_data)
104
+ end
105
+ end
106
+ end
@@ -1,11 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'celluloid/current'
3
3
  require 'reel'
4
- require 'slack-ruby-client'
5
4
  require 'json'
6
- require 'octokit'
7
- require 'thread'
8
- require 'timers'
9
5
  require 'rack'
10
6
  require_relative './builder.rb'
11
7
 
@@ -13,164 +9,9 @@ module BuildBuddy
13
9
  class Server < Reel::Server::HTTP
14
10
  include Celluloid::Internals::Logger
15
11
 
16
- def initialize(host = "127.0.0.1", port = Config.github_webhook_port)
17
- super(host, port, &method(:on_connection))
18
- @gh_client ||= Octokit::Client.new(:access_token => Config.github_api_token)
19
- @rt_client = Slack::RealTime::Client.new
20
- @rt_client.on :hello do
21
- self.on_slack_hello()
22
- end
23
- @rt_client.on :message do |data|
24
- self.on_slack_data(data)
25
- end
26
- @rt_client.on :error do |error|
27
- self.on_slack_error(error)
28
- end
29
- @rt_client.start_async
30
- @active_build = nil
31
- @build_queue = Queue.new
32
- @done_queue = Queue.new
33
- @notify_slack_channel = nil
34
- @reverse_user_map = nil
35
- end
36
-
37
- def on_slack_error(error)
38
- sub_error = error['error']
39
- error "Whoops! Slack error #{sub_error['code']} - #{sub_error['msg']}}"
40
- end
41
-
42
- def on_slack_hello
43
- user_id = @rt_client.self['id']
44
- user_map = @rt_client.users.map {|user| [user['name'], user['id']]}.to_h
45
- @reverse_user_map = user_map.invert
46
- info "Connected to Slack as user id #{user_id} (@#{@reverse_user_map[user_id]})"
47
-
48
- channel_map = @rt_client.channels.map {|channel| [channel['name'], channel['id']]}.to_h
49
- group_map = @rt_client.groups.map {|group| [group['name'], group['id']]}.to_h
50
- channel = Config.slack_build_channel
51
- is_channel = (channel[0] == '#')
52
-
53
- @notify_slack_channel = (is_channel ? channel_map[channel[1..-1]] : group_map[channel])
54
- if @notify_slack_channel.nil?
55
- error "Unable to identify the slack channel #{channel}"
56
- else
57
- info "Slack notification channel is #{@notify_slack_channel} (#{channel})"
58
- end
59
- end
60
-
61
- def on_slack_data(data)
62
- message = data['text']
63
-
64
- # If no message, then there's nothing to do
65
- if message.nil?
66
- return
67
- end
68
-
69
- sending_user_id = data['user']
70
-
71
- # Only respond to messages from users and bots
72
- if sending_user_id.nil?
73
- if data['username'].nil? or data['subtype'] != 'bot_message'
74
- return
75
- end
76
- sending_user_name = data['username']
77
- else
78
- sending_user_name = @reverse_user_map[sending_user_id]
79
- end
80
-
81
- # Don't respond if _we_ sent the message!
82
- if sending_user_id == @rt_client.self['id']
83
- return
84
- end
85
-
86
- sender_is_a_builder = (Config.slack_builders.nil? ? true : Config.slack_builders.include?('@' + sending_user_name))
87
-
88
- c = data['channel'][0]
89
- in_channel = (c == 'C' || c == 'G')
90
-
91
- # Don't respond if the message is to a channel and our name is not in the message
92
- if in_channel and !message.match(@rt_client.self['id'])
93
- return
94
- end
95
-
96
- case message
97
- when /build/i
98
- unless sender_is_a_builder
99
- if in_channel
100
- response = "I'm sorry @#{sending_user_name} you are not on my list of allowed builders."
101
- else
102
- response = "I'm sorry but you are not on my list of allowed builders."
103
- end
104
- else
105
- case message
106
- when /master/i
107
- response = "OK, I've queued a build of the `master` branch."
108
- queue_a_build(BuildData.new(:master,
109
- :repo_full_name => Config.github_webhook_repo_full_name))
110
- when /(?<version>v\d+\.\d+)/
111
- version = $~[:version]
112
- if Config.valid_release_versions.include?(version)
113
- response = "OK, I've queued a build of `#{version}` branch."
114
- queue_a_build(BuildData.new(:release,
115
- :build_version => version,
116
- :repo_full_name => Config.github_webhook_repo_full_name))
117
- else
118
- response = "I'm sorry, I cannot build the #{version} release branch"
119
- end
120
- when /stop/i
121
- build_data = @active_build
122
- if build_data.nil?
123
- response = "There is no build running to stop"
124
- else
125
- response = "OK, I killed the currently running build..."
126
- Celluloid::Actor[:builder].async.stop_build
127
- end
128
- else
129
- response = "Sorry#{in_channel ? " <@#{data['user']}>" : ""}, I'm not sure if you want do a *master*, or *M.m* branch build, or maybe *stop* any running build?"
130
- end
131
- end
132
- when /status/i
133
- build_data = @active_build
134
- queue_length = @build_queue.length
135
- if build_data == nil
136
- response = "There is currently no build running"
137
- if queue_length == 0
138
- response += " and no builds in the queue."
139
- else
140
- response += " and #{queue_length} in the queue."
141
- end
142
- else
143
- case build_data.build_type
144
- when :pull_request
145
- response = "There is a pull request build in progress for https://github.com/#{build_data.repo_full_name}/pull/#{build_data.pull_request}."
146
- when :master
147
- response = "There is a build of the `master` branch of https://github.com/#{build_data.repo_full_name} in progress."
148
- when :release
149
- response = "There is a build of the `#{build_data.build_version}` branch of https://github.com/#{build_data.repo_full_name} in progress."
150
- end
151
- if queue_length == 1
152
- response += " There is one build in the queue."
153
- elsif queue_length > 1
154
- response += " There are #{queue_length} builds in the queue."
155
- end
156
- end
157
- when /help/i, /what can/i
158
- # TODO: The repository should be a link to GitHub
159
- 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.
160
-
161
- 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.
162
-
163
- 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..
164
-
165
- You can also ask me about the *status* of builds and I'll tell you if anything is currently happening.
166
-
167
- 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.
168
- )
169
- else
170
- response = "Sorry#{in_channel ? " <@#{data['user']}>" : ""}, I'm not sure how to respond."
171
- end
172
- @rt_client.message channel: data['channel'], text: response
173
- info "Slack message '#{message}' from #{data['channel']} handled"
12
+ def initialize()
13
+ super("127.0.0.1", Config.github_webhook_port, &method(:on_connection))
14
+ info "Listening on port #{Config.github_webhook_port}"
174
15
  end
175
16
 
176
17
  def on_connection(connection)
@@ -180,114 +21,37 @@ module BuildBuddy
180
21
  case request.path
181
22
  when Config.github_webhook_path
182
23
  case request.headers["X-GitHub-Event"]
183
- when 'pull_request'
184
- payload_text = request.body.to_s
185
- # TODO: Also need to validate that it's the github_webhook_repo_full_name
186
- if !verify_signature(payload_text, request.headers["X-Hub-Signature"])
187
- request.respond 500, "Signatures didn't match!"
188
- else
189
- payload = JSON.parse(payload_text)
190
- pull_request = payload['pull_request']
191
- build_data = BuildData.new(:pull_request,
192
- :pull_request => pull_request['number'],
193
- :repo_sha => pull_request['head']['sha'],
194
- :repo_full_name => pull_request['base']['repo']['full_name'])
195
- info "Got pull request #{build_data.pull_request} from GitHub"
196
- queue_a_build(build_data)
197
- request.respond 200
198
- end
199
- when 'ping'
200
- request.respond 200, "Running"
24
+ when 'pull_request'
25
+ payload_text = request.body.to_s
26
+ if !verify_signature(payload_text, request.headers["X-Hub-Signature"])
27
+ request.respond 500, "Signatures didn't match!"
201
28
  else
202
- request.respond 404, "Path not found"
203
- end
204
- end
205
- else
206
- request.respond 404, "Method not supported"
207
- end
208
- end
209
- end
210
-
211
- def queue_a_build(build_data)
212
- @build_queue.push(build_data)
213
-
214
- case build_data.build_type
215
- when :pull_request
216
- @gh_client.create_status(
217
- build_data.repo_full_name, build_data.repo_sha, 'pending',
218
- { :description => "This build is in the queue" })
219
- info "Pull request build queued"
220
- when :master
221
- info "`master` branch build queued"
222
- when :release
223
- info "Release branch build queued"
224
- end
225
-
226
- if @build_timer.nil?
227
- @build_timer = every(5) { on_build_interval }
228
- info "Build timer started"
229
- end
230
- end
231
-
232
- def on_build_interval
233
- if @active_build.nil?
234
- if @build_queue.length > 0
235
- build_data = @build_queue.pop()
236
- @active_build = build_data
237
- if build_data.build_type == :pull_request
238
- @gh_client.create_status(
239
- build_data.repo_full_name, build_data.repo_sha, 'pending',
240
- { :description => "This build has started" })
241
- end
242
- Celluloid::Actor[:builder].async.start_build(build_data)
243
- elsif @done_queue.length > 0
244
- build_data = @done_queue.pop
245
- term_msg = (build_data.termination_type == :killed ? "was stopped" : "completed")
246
- if build_data.termination_type == :exited
247
- if build_data.exit_code != 0
248
- term_msg += " with errors (exit code #{build_data.exit_code}). See log file `#{build_data.build_log_filename}` for more details."
29
+ payload = JSON.parse(payload_text)
30
+ pull_request = payload['pull_request']
31
+ build_data = BuildData.new(:pull_request,
32
+ :pull_request => pull_request['number'],
33
+ :repo_sha => pull_request['head']['sha'],
34
+ :repo_full_name => pull_request['base']['repo']['full_name'])
35
+ info "Got pull request #{build_data.pull_request} from GitHub"
36
+ Celluloid::Actor[:scheduler].queue_a_build(build_data)
37
+ request.respond 200
38
+ end
39
+ when 'ping'
40
+ request.respond 200, "Running"
249
41
  else
250
- term_msg += " successfully"
42
+ request.respond 404, "Path not found"
251
43
  end
252
- end
253
- if build_data.build_type == :pull_request
254
- description = "The buddy build #{term_msg}"
255
- @gh_client.create_status(
256
- build_data.repo_full_name, build_data.repo_sha,
257
- build_data.termination_type == :killed ? 'failure' : build_data.exit_code != 0 ? 'error' : 'success',
258
- { :description => description.length > 140 ? "#{description[0..137]}..." : description })
259
- info "Pull request build #{term_msg}"
260
44
  else
261
- case build_data.build_type
262
- when :master
263
- message = "A build of the `master` branch #{term_msg}."
264
- info "`master` branch build #{term_msg}"
265
- when :release
266
- message = "A build of the `#{build_data.build_version}` branch #{term_msg}."
267
- info "Release branch build #{term_msg}"
268
- end
269
- unless @notify_slack_channel.nil?
270
- @rt_client.message(channel: @notify_slack_channel, text: message)
271
- end
45
+ request.respond 404, "Path not found"
272
46
  end
47
+ # TODO: Implement basic access authentication from config file
48
+ # TODO: Implement getting the log file
273
49
  else
274
- @build_timer.cancel
275
- @build_timer = nil
276
- info "Build timer stopped"
277
- end
278
- else
279
- # Make sure that the build has not run too long and kill if necessary
280
- if Time.now.utc - @active_build.start_time > Config.kill_build_after_mins * 60
281
- Celluloid::Actor[:builder].async.stop_build()
50
+ request.respond 404, "Method not supported"
282
51
  end
283
52
  end
284
53
  end
285
54
 
286
- def on_build_completed(build_data)
287
- @active_build = nil
288
- @done_queue.push(build_data)
289
- end
290
-
291
55
  def verify_signature(payload_body, gh_signature)
292
56
  signature = 'sha1=' + OpenSSL::HMAC.hexdigest(
293
57
  OpenSSL::Digest.new('sha1'), Config.github_webhook_secret_token, payload_body)
@@ -0,0 +1,175 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'celluloid'
4
+ require 'slack-ruby-client'
5
+ require_relative './config.rb'
6
+
7
+ module BuildBuddy
8
+ class Slacker
9
+ include Celluloid
10
+ include Celluloid::Internals::Logger
11
+
12
+ def initialize()
13
+ @rt_client = Slack::RealTime::Client.new
14
+ @rt_client.on :hello do
15
+ self.on_slack_hello()
16
+ end
17
+ @rt_client.on :message do |data|
18
+ self.on_slack_data(data)
19
+ end
20
+ @rt_client.on :error do |error|
21
+ self.on_slack_error(error)
22
+ end
23
+ @rt_client.start_async
24
+ @notify_slack_channel = nil
25
+ @reverse_user_map = nil
26
+ end
27
+
28
+ def on_slack_error(error)
29
+ sub_error = error['error']
30
+ error "Whoops! Slack error #{sub_error['code']} - #{sub_error['msg']}}"
31
+ end
32
+
33
+ def on_slack_hello
34
+ user_id = @rt_client.self['id']
35
+ user_map = @rt_client.users.map {|user| [user['name'], user['id']]}.to_h
36
+ @reverse_user_map = user_map.invert
37
+ info "Connected to Slack as user id #{user_id} (@#{@reverse_user_map[user_id]})"
38
+
39
+ channel_map = @rt_client.channels.map {|channel| [channel['name'], channel['id']]}.to_h
40
+ group_map = @rt_client.groups.map {|group| [group['name'], group['id']]}.to_h
41
+ channel = Config.slack_build_channel
42
+ is_channel = (channel[0] == '#')
43
+
44
+ @notify_slack_channel = (is_channel ? channel_map[channel[1..-1]] : group_map[channel])
45
+ if @notify_slack_channel.nil?
46
+ error "Unable to identify the slack channel #{channel}"
47
+ else
48
+ info "Slack notification channel is #{@notify_slack_channel} (#{channel})"
49
+ end
50
+ end
51
+
52
+ def on_slack_data(data)
53
+ message = data['text']
54
+
55
+ # If no message, then there's nothing to do
56
+ if message.nil?
57
+ return
58
+ end
59
+
60
+ sending_user_id = data['user']
61
+
62
+ # Only respond to messages from users and bots
63
+ if sending_user_id.nil?
64
+ if data['username'].nil? or data['subtype'] != 'bot_message'
65
+ return
66
+ end
67
+ sending_user_name = data['username']
68
+ else
69
+ sending_user_name = @reverse_user_map[sending_user_id]
70
+ end
71
+
72
+ # Don't respond if _we_ sent the message!
73
+ if sending_user_id == @rt_client.self['id']
74
+ return
75
+ end
76
+
77
+ sender_is_a_builder = (Config.slack_builders.nil? ? true : Config.slack_builders.include?('@' + sending_user_name))
78
+
79
+ c = data['channel'][0]
80
+ in_channel = (c == 'C' || c == 'G')
81
+
82
+ # Don't respond if the message is to a channel and our name is not in the message
83
+ if in_channel and !message.match(@rt_client.self['id'])
84
+ return
85
+ end
86
+
87
+ scheduler = Celluloid::Actor[:scheduler]
88
+
89
+ case message
90
+ when /build/i
91
+ unless sender_is_a_builder
92
+ if in_channel
93
+ response = "I'm sorry @#{sending_user_name} you are not on my list of allowed builders."
94
+ else
95
+ response = "I'm sorry but you are not on my list of allowed builders."
96
+ end
97
+ else
98
+ case message
99
+ when /master/i
100
+ response = "OK, I've queued a build of the `master` branch."
101
+ scheduler.queue_a_build(BuildData.new(:master,
102
+ :repo_full_name => Config.github_webhook_repo_full_name))
103
+ when /(?<version>v\d+\.\d+)/
104
+ version = $~[:version]
105
+ if Config.valid_release_versions.include?(version)
106
+ response = "OK, I've queued a build of `#{version}` branch."
107
+ scheduler.queue_a_build(BuildData.new(:release,
108
+ :build_version => version,
109
+ :repo_full_name => Config.github_webhook_repo_full_name))
110
+ else
111
+ response = "I'm sorry, I cannot build the #{version} release branch"
112
+ end
113
+ when /stop/i
114
+ if scheduler.stop_build
115
+ response = "OK, I stopped the currently running build."
116
+ else
117
+ response = "There is no build running to stop."
118
+ end
119
+ else
120
+ response = "Sorry#{in_channel ? " <@#{data['user']}>" : ""}, I'm not sure if you want do a `master` or release branch build, or maybe `stop` any running build?"
121
+ end
122
+ end
123
+ when /status/i
124
+ build_data = scheduler.active_build
125
+ queue_length = scheduler.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 version #{BuildBuddy::VERSION}! 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.
153
+
154
+ I can run builds of the master branch if you say `build master`. I can do builds of release branches, e.g. `build v2.3` but only for those branches that I am allowed to build.
155
+
156
+ I can stop any running build if you ask me to `stop build`, even pull request builds.
157
+
158
+ You can also ask me for `status` and I'll tell you what's being built and what's in the queue.
159
+
160
+ I am configured to let the *#{Config.slack_build_channel}* channel know if master or release builds are stopped.
161
+ )
162
+ else
163
+ response = "Sorry#{in_channel ? " <@#{data['user']}>" : ""}, I'm not sure how to respond."
164
+ end
165
+ @rt_client.message channel: data['channel'], text: response
166
+ info "Slack message '#{message}' from #{data['channel']} handled"
167
+ end
168
+
169
+ def notify_channel(message)
170
+ unless @notify_slack_channel.nil?
171
+ @rt_client.message(channel: @notify_slack_channel, text: message)
172
+ end
173
+ end
174
+ end
175
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: build-buddy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Lyon-smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-29 00:00:00.000000000 Z
11
+ date: 2016-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: timers
@@ -176,7 +176,10 @@ files:
176
176
  - lib/build_buddy/build_data.rb
177
177
  - lib/build_buddy/builder.rb
178
178
  - lib/build_buddy/config.rb
179
+ - lib/build_buddy/gitter.rb
180
+ - lib/build_buddy/scheduler.rb
179
181
  - lib/build_buddy/server.rb
182
+ - lib/build_buddy/slacker.rb
180
183
  - lib/build_buddy/watcher.rb
181
184
  homepage: http://rubygems.org/gems/build-buddy
182
185
  licenses: