build-buddy 1.3.1 → 1.4.0

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 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: