build-buddy 1.11.0 → 1.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/build-buddy +17 -15
- data/lib/build_buddy.rb +1 -1
- data/lib/build_buddy/build_data.rb +31 -7
- data/lib/build_buddy/builder.rb +32 -7
- data/lib/build_buddy/config.rb +33 -22
- data/lib/build_buddy/gitter.rb +4 -5
- data/lib/build_buddy/recorder.rb +245 -9
- data/lib/build_buddy/scheduler.rb +36 -21
- data/lib/build_buddy/server.rb +101 -8
- data/lib/build_buddy/slacker.rb +149 -125
- metadata +18 -18
@@ -9,24 +9,24 @@ module BuildBuddy
|
|
9
9
|
include Celluloid
|
10
10
|
include Celluloid::Internals::Logger
|
11
11
|
|
12
|
-
attr_reader :active_build
|
13
|
-
|
14
12
|
def initialize()
|
15
|
-
@build_queue =
|
16
|
-
@done_queue =
|
13
|
+
@build_queue = []
|
14
|
+
@done_queue = []
|
17
15
|
@build_timer = nil
|
16
|
+
@active_build = nil
|
18
17
|
end
|
19
18
|
|
20
19
|
def queue_a_build(build_data)
|
21
|
-
@build_queue.
|
20
|
+
@build_queue.unshift(build_data)
|
22
21
|
|
23
22
|
case build_data.type
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
23
|
+
when :pull_request
|
24
|
+
Celluloid::Actor[:gitter].async.set_status(
|
25
|
+
build_data.repo_full_name, build_data.repo_sha, :pending, "Build is queued",
|
26
|
+
build_data.server_log_uri)
|
27
|
+
info "Pull request build queued"
|
28
|
+
when :branch
|
29
|
+
info "'#{build_data.branch}' branch build queued"
|
30
30
|
end
|
31
31
|
|
32
32
|
if @build_timer.nil?
|
@@ -39,14 +39,29 @@ module BuildBuddy
|
|
39
39
|
@build_queue.length
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
42
|
+
def active_build
|
43
|
+
@active_build
|
44
|
+
end
|
45
|
+
|
46
|
+
def stop_build(id, slack_user_name)
|
47
|
+
# Centralize stopping builds here
|
48
|
+
if @active_build != nil and @active_build._id != id
|
49
|
+
@active_build.stopped_by = slack_user_name
|
45
50
|
Celluloid::Actor[:builder].stop_build
|
46
51
|
true
|
47
|
-
else
|
48
|
-
false
|
49
52
|
end
|
53
|
+
|
54
|
+
# Look for the build in the queue
|
55
|
+
i = @build_queue.find { |build_data| build_data._id == id}
|
56
|
+
if i != nil
|
57
|
+
build_data = @build_queue[i]
|
58
|
+
@build_queue.delete_at(i)
|
59
|
+
build_data.stopped_by = slack_user_name
|
60
|
+
Celluloid::Actor[:recorder].async.record_build_data(build_data)
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
false
|
50
65
|
end
|
51
66
|
|
52
67
|
def on_build_interval
|
@@ -60,10 +75,6 @@ module BuildBuddy
|
|
60
75
|
build_data = @build_queue.pop()
|
61
76
|
@active_build = build_data
|
62
77
|
Celluloid::Actor[:recorder].async.record_build_data(build_data)
|
63
|
-
if build_data.type == :pull_request
|
64
|
-
Celluloid::Actor[:gitter].async.set_status(
|
65
|
-
build_data.repo_full_name, build_data.repo_sha, :pending, "This build has started")
|
66
|
-
end
|
67
78
|
Celluloid::Actor[:builder].async.start_build(build_data)
|
68
79
|
else # Otherwise, stop the timer until we get a build queued.
|
69
80
|
@build_timer.cancel
|
@@ -82,7 +93,11 @@ module BuildBuddy
|
|
82
93
|
|
83
94
|
def on_build_completed(build_data)
|
84
95
|
@active_build = nil
|
85
|
-
@done_queue.
|
96
|
+
@done_queue.unshift(build_data)
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_build_queue
|
100
|
+
@build_queue.clone
|
86
101
|
end
|
87
102
|
end
|
88
103
|
end
|
data/lib/build_buddy/server.rb
CHANGED
@@ -30,40 +30,51 @@ module BuildBuddy
|
|
30
30
|
action = payload['action']
|
31
31
|
pull_request = payload['pull_request']
|
32
32
|
|
33
|
+
info "Got pull request '#{action}' from #{forwarded_for(request)}"
|
33
34
|
case action
|
34
35
|
when 'opened', 'reopened', 'synchronize'
|
35
36
|
build_data = BuildData.new(
|
36
37
|
:type => :pull_request,
|
37
38
|
:pull_request => pull_request['number'],
|
38
|
-
:flags =>
|
39
|
+
:flags => {},
|
39
40
|
:repo_sha => pull_request['head']['sha'],
|
40
41
|
:repo_full_name => pull_request['base']['repo']['full_name'])
|
41
42
|
info "Got #{action} pull request #{build_data.pull_request} from GitHub"
|
42
43
|
Celluloid::Actor[:scheduler].queue_a_build(build_data)
|
43
44
|
request.respond 200, "Building"
|
45
|
+
return
|
44
46
|
else
|
45
47
|
request.respond 200, "Ignoring"
|
48
|
+
return
|
46
49
|
end
|
47
50
|
end
|
48
51
|
when 'ping'
|
52
|
+
info "Got pinged from #{forwarded_for(request)}"
|
49
53
|
request.respond 200, "Running"
|
54
|
+
return
|
50
55
|
else
|
51
56
|
request.respond 404, "Event not supported"
|
57
|
+
return
|
52
58
|
end
|
53
59
|
else
|
54
60
|
request.respond 404, "Method not supported"
|
61
|
+
return
|
55
62
|
end
|
56
|
-
when /^\/log\/([0-
|
63
|
+
when /^\/log\/([0-9abcdef]{24})$/
|
57
64
|
case request.method
|
58
65
|
when 'GET'
|
59
66
|
build_data = Celluloid::Actor[:recorder].get_build_data($1)
|
60
|
-
if build_data.nil?
|
61
|
-
sleep 1
|
67
|
+
if build_data.nil?
|
62
68
|
request.respond 404, "Not found"
|
69
|
+
return
|
63
70
|
end
|
64
|
-
|
65
|
-
File.
|
66
|
-
log_contents =
|
71
|
+
log_file_name = build_data.log_file_name
|
72
|
+
if log_file_name.nil? or !File.exist?(log_file_name)
|
73
|
+
log_contents = 'Log file has been deleted.'
|
74
|
+
else
|
75
|
+
File.open(log_file_name) do |io|
|
76
|
+
log_contents = io.read
|
77
|
+
end
|
67
78
|
end
|
68
79
|
html = %Q(
|
69
80
|
<!doctype html>
|
@@ -92,15 +103,97 @@ module BuildBuddy
|
|
92
103
|
</html>
|
93
104
|
)
|
94
105
|
request.respond 200, html
|
106
|
+
return
|
95
107
|
else
|
96
108
|
request.respond 404, "Method not supported"
|
109
|
+
return
|
110
|
+
end
|
111
|
+
when Regexp.new("^/hud/#{Config.hud_secret_token}/(index\\.html|[a-z_]+\\.png)$")
|
112
|
+
if request.method != 'GET'
|
113
|
+
request.response 404, "Method not supported"
|
114
|
+
return
|
115
|
+
end
|
116
|
+
|
117
|
+
if $1 == "index.html"
|
118
|
+
html = %q(
|
119
|
+
<!doctype html>
|
120
|
+
<html lang="en">
|
121
|
+
<head>
|
122
|
+
<title>Build Metrics</title>
|
123
|
+
<meta charset="utf-8">
|
124
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
125
|
+
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
126
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.3/css/bootstrap.min.css" integrity="sha384-MIwDKRSSImVFAZCVLtU0LMDdON6KVCrZHyVQQj6e8wIEJkW4tvwqXrbMIya1vriY" crossorigin="anonymous">
|
127
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.3/js/bootstrap.min.js" integrity="sha384-ux8v3A6CPtOTqOzMKiuo3d/DomGaaClxFYdCu2HPMBEkf6x2xiDyJ7gkXU0MWwaD" crossorigin="anonymous"></script>
|
128
|
+
</head>
|
129
|
+
<body>
|
130
|
+
|
131
|
+
<div class="jumbotron text-center">
|
132
|
+
<h1>Build Metrics</h1>
|
133
|
+
<p>Build server data</p>
|
134
|
+
</div>
|
135
|
+
|
136
|
+
<div class="container-fluid">
|
137
|
+
<div class="row">
|
138
|
+
<div class="col-sm-4">
|
139
|
+
<img class="img-fluid" src="code_coverage.png" alt="Code Coverage">
|
140
|
+
</div>
|
141
|
+
<div class="col-sm-4">
|
142
|
+
<img class="img-fluid" src="build_times.png" alt="Build Times">
|
143
|
+
</div>
|
144
|
+
<div class="col-sm-4">
|
145
|
+
<img class="img-fluid" src="daily_builds.png" alt="Daily Builds">
|
146
|
+
</div>
|
147
|
+
</div>
|
148
|
+
<div class="row">
|
149
|
+
<div class="col-sm-4">
|
150
|
+
<img class="img-fluid" src="lines_of_code.png" alt="Lines of Code">
|
151
|
+
</div>
|
152
|
+
<div class="col-sm-4">
|
153
|
+
<img class="img-fluid" src="localization_data.png" alt="Localization Data">
|
154
|
+
</div>
|
155
|
+
<div class="col-sm-4">
|
156
|
+
<img class="img-fluid" src="warning_count.png" alt="Warning Count">
|
157
|
+
</div>
|
158
|
+
</div>
|
159
|
+
</div>
|
160
|
+
|
161
|
+
</body>
|
162
|
+
</html>
|
163
|
+
)
|
164
|
+
request.respond 200, html
|
165
|
+
return
|
166
|
+
elsif
|
167
|
+
png_file_name = File.join(Config.hud_image_dir, $1)
|
168
|
+
|
169
|
+
if File.exist?(png_file_name)
|
170
|
+
request.respond Reel::Response.new(200, {"content-type" => "image/png"}, File.open(png_file_name))
|
171
|
+
return
|
172
|
+
else
|
173
|
+
request.response 404, "Image not found"
|
174
|
+
return
|
175
|
+
end
|
176
|
+
else
|
177
|
+
request.response 404, "Path not found"
|
178
|
+
return
|
97
179
|
end
|
98
180
|
else
|
99
|
-
|
181
|
+
request.respond 404, "Path not found"
|
182
|
+
return
|
100
183
|
end
|
101
184
|
end
|
102
185
|
end
|
103
186
|
|
187
|
+
def forwarded_for(request)
|
188
|
+
addr = request.headers["X-Forwarded-For"]
|
189
|
+
|
190
|
+
if addr.start_with?("192.30.252")
|
191
|
+
return "github.com (#{addr})"
|
192
|
+
else
|
193
|
+
return "unknown (#{addr})"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
104
197
|
def verify_signature(payload_body, gh_signature)
|
105
198
|
signature = 'sha1=' + OpenSSL::HMAC.hexdigest(
|
106
199
|
OpenSSL::Digest.new('sha1'), Config.github_webhook_secret_token, payload_body)
|
data/lib/build_buddy/slacker.rb
CHANGED
@@ -10,7 +10,7 @@ module BuildBuddy
|
|
10
10
|
include Celluloid::Internals::Logger
|
11
11
|
|
12
12
|
def initialize()
|
13
|
-
@rt_client = Slack::RealTime::Client.new
|
13
|
+
@rt_client = Slack::RealTime::Client.new(websocket_ping: 3)
|
14
14
|
@rt_client.on :hello do
|
15
15
|
self.on_slack_hello()
|
16
16
|
end
|
@@ -21,29 +21,36 @@ module BuildBuddy
|
|
21
21
|
sub_error = error['error']
|
22
22
|
error "Slack error #{sub_error['code']} - #{sub_error['msg']}}"
|
23
23
|
end
|
24
|
-
@rt_client.on :
|
25
|
-
|
24
|
+
@rt_client.on :closed do |event|
|
25
|
+
info "Slack connection was closed"
|
26
|
+
self.terminate
|
26
27
|
end
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
|
29
|
+
begin
|
30
|
+
@rt_client.start_async
|
31
|
+
rescue
|
32
|
+
info "Unable to connect to Slack"
|
33
|
+
self.terminate
|
34
|
+
end
|
35
|
+
|
36
|
+
@build_channel_id = nil
|
30
37
|
end
|
31
38
|
|
32
|
-
def self.
|
39
|
+
def self.extract_build_flags(message)
|
33
40
|
flags = []
|
34
41
|
unless message.nil?
|
35
42
|
message.split(',').each do |s|
|
36
|
-
flags.push(s.lstrip.rstrip.gsub(' ', '_').to_sym)
|
43
|
+
flags.push(s.lstrip.rstrip.downcase.gsub(' ', '_').to_sym)
|
37
44
|
end
|
38
45
|
end
|
39
46
|
flags
|
40
47
|
end
|
41
48
|
|
42
|
-
def do_build(message,
|
49
|
+
def do_build(message, is_from_slack_channel, slack_user_name)
|
43
50
|
response = ''
|
44
51
|
sender_is_a_builder = (Config.slack_builders.nil? ? true : Config.slack_builders.include?('@' + slack_user_name))
|
45
52
|
unless sender_is_a_builder
|
46
|
-
if
|
53
|
+
if is_from_slack_channel
|
47
54
|
response = "I'm sorry @#{slack_user_name} you are not on my list of allowed builders."
|
48
55
|
else
|
49
56
|
response = "I'm sorry but you are not on my list of allowed builders."
|
@@ -53,15 +60,16 @@ module BuildBuddy
|
|
53
60
|
|
54
61
|
case message
|
55
62
|
when /^master(?: with )?(?<flags>.*)?/i
|
56
|
-
flags = Slacker.
|
63
|
+
flags = Slacker.extract_build_flags($~[:flags])
|
57
64
|
response = "OK, I've queued a build of the `master` branch."
|
58
65
|
scheduler.queue_a_build(BuildData.new(
|
59
66
|
:type => :branch,
|
60
67
|
:branch => 'master',
|
61
68
|
:flags => flags,
|
62
|
-
:repo_full_name => Config.github_webhook_repo_full_name
|
69
|
+
:repo_full_name => Config.github_webhook_repo_full_name,
|
70
|
+
:started_by => slack_user_name))
|
63
71
|
when /^(?<version>v\d+\.\d+)(?: with )?(?<flags>.*)?/
|
64
|
-
flags = Slacker.
|
72
|
+
flags = Slacker.extract_build_flags($~[:flags])
|
65
73
|
version = $~[:version]
|
66
74
|
if Config.allowed_build_branches.include?(version)
|
67
75
|
response = "OK, I've queued a build of the `#{version}` branch."
|
@@ -69,101 +77,114 @@ module BuildBuddy
|
|
69
77
|
:type => :branch,
|
70
78
|
:branch => version,
|
71
79
|
:flags => flags,
|
72
|
-
:repo_full_name => Config.github_webhook_repo_full_name
|
80
|
+
:repo_full_name => Config.github_webhook_repo_full_name,
|
81
|
+
:started_by => slack_user_name))
|
73
82
|
else
|
74
83
|
response = "I'm sorry, I am not allowed to build the `#{version}` branch"
|
75
84
|
end
|
76
85
|
else
|
77
|
-
response = "Sorry#{
|
86
|
+
response = "Sorry#{is_from_slack_channel ? ' @' + slack_user_name : ''}, I'm not sure if you want do a `master` or release branch build"
|
78
87
|
end
|
79
88
|
end
|
80
89
|
response
|
81
90
|
end
|
82
91
|
|
83
|
-
def do_stop
|
84
|
-
scheduler = Celluloid::Actor[:scheduler]
|
85
|
-
|
86
|
-
if scheduler.stop_build
|
87
|
-
response = "OK, I stopped the currently running build."
|
88
|
-
else
|
89
|
-
response = "There is no build running to stop."
|
90
|
-
end
|
91
|
-
|
92
|
-
response
|
93
|
-
end
|
94
|
-
|
95
|
-
def do_status
|
96
|
-
scheduler = Celluloid::Actor[:scheduler]
|
97
|
-
build_data = scheduler.active_build
|
98
|
-
queue_length = scheduler.queue_length
|
92
|
+
def do_stop(message, is_from_slack_channel, slack_user_name)
|
99
93
|
response = ''
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
94
|
+
m = message.match(/[0-9abcdef]{24}/)
|
95
|
+
|
96
|
+
unless m.nil?
|
97
|
+
if Celluloid::Actor[:scheduler].stop_build(BSON::ObjectId.from_string(m[0]), slack_user_name)
|
98
|
+
response = "OK#{is_from_slack_channel ? ' @' + slack_user_name : ''}, I stopped the build with identifier #{m[0]}."
|
104
99
|
else
|
105
|
-
response
|
100
|
+
response = "I could not find a queued or active build with that identifier"
|
106
101
|
end
|
107
102
|
else
|
108
|
-
|
109
|
-
when :pull_request
|
110
|
-
response = "There is a pull request build in progress for https://github.com/#{build_data.repo_full_name}/pull/#{build_data.pull_request}."
|
111
|
-
when :branch
|
112
|
-
response = "There is a build of the `#{build_data.branch}` branch of https://github.com/#{build_data.repo_full_name} in progress."
|
113
|
-
end
|
114
|
-
if queue_length == 1
|
115
|
-
response += " There is one build in the queue."
|
116
|
-
elsif queue_length > 1
|
117
|
-
response += " There are #{queue_length} builds in the queue."
|
118
|
-
end
|
103
|
+
response = "You must specify the 24 digit hexadecimal build identifier. It can be an active build or a build in the queue."
|
119
104
|
end
|
105
|
+
|
120
106
|
response
|
121
107
|
end
|
122
108
|
|
123
|
-
def do_help
|
124
|
-
#
|
125
|
-
%Q(Hello#{from_slack_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.
|
109
|
+
def do_help is_from_slack_channel
|
110
|
+
%Q(Hello#{is_from_slack_channel ? " <@#{data['user']}>" : ""}, I'm the *@#{@rt_client.self['name']}* build bot version #{BuildBuddy::VERSION}!
|
126
111
|
|
127
|
-
A pull request build happens when you make a pull request to the
|
112
|
+
I understand types of build - pull requests and branch. A pull request build happens when you make a pull request to the https://github.com/#{Config.github_webhook_repo_full_name} GitHub repository.
|
128
113
|
|
129
|
-
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.
|
114
|
+
For branch builds, 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 in by configuration file.
|
130
115
|
|
131
|
-
I can stop any running build if you ask me to `stop build`, even pull request builds.
|
116
|
+
I can stop any running build if you ask me to `stop build X`, even pull request builds if you give the id X from the `show status` or `show queue` command. I am configured to let the *#{Config.slack_build_channel}* channel know if builds are stopped.
|
132
117
|
|
133
|
-
|
118
|
+
I have lots of `show` commands:
|
134
119
|
|
135
|
-
|
120
|
+
- `show status` and I'll tell you what my status is
|
121
|
+
- `show queue` and I will show you what is in the queue
|
122
|
+
- `show options` to a see a list of build options
|
123
|
+
- `show builds` to see the last 5 builds or `show last N builds` to see a list of the last N builds
|
124
|
+
|
125
|
+
Build metrics and charts are available at #{Config.server_base_uri}/hud/#{Config.hud_secret_token}/index.html
|
136
126
|
)
|
137
127
|
end
|
138
128
|
|
139
|
-
def
|
140
|
-
|
141
|
-
|
142
|
-
case question
|
143
|
-
when /happened/
|
144
|
-
case question
|
145
|
-
when /([0-9]+)/
|
146
|
-
limit = $1.to_i
|
147
|
-
else
|
148
|
-
limit = 5
|
149
|
-
end
|
129
|
+
def do_show(request)
|
130
|
+
request = request.lstrip.rstrip
|
150
131
|
|
151
|
-
|
152
|
-
|
132
|
+
case request
|
133
|
+
when /builds/
|
134
|
+
limit = 5
|
135
|
+
m = request.match(/last ([0-9]+)/)
|
136
|
+
limit = m[1].to_i unless m.nil?
|
137
|
+
build_datas = Celluloid::Actor[:recorder].get_build_data_history(limit)
|
153
138
|
|
154
139
|
if build_datas.count == 0
|
155
140
|
response = "No builds have performed yet"
|
156
141
|
else
|
157
|
-
response =
|
142
|
+
response = ''
|
143
|
+
if build_datas.count < limit
|
144
|
+
response += "There have only been #{build_datas.count} builds:\n"
|
145
|
+
else
|
146
|
+
response += "Here are the last #{build_datas.count} builds:\n"
|
147
|
+
end
|
158
148
|
build_datas.each do |build_data|
|
159
149
|
response += "A "
|
160
150
|
response += case build_data.type
|
161
151
|
when :branch
|
162
152
|
"`#{build_data.branch}` branch build"
|
163
153
|
when :pull_request
|
164
|
-
"pull request
|
154
|
+
"pull request build #{build_data.pull_request_uri}"
|
165
155
|
end
|
166
|
-
response += " at #{build_data.start_time.to_s}. #{Config.server_base_uri + '/log/' + build_data._id.to_s}
|
156
|
+
response += " at #{build_data.start_time.to_s}. #{Config.server_base_uri + '/log/' + build_data._id.to_s}"
|
157
|
+
response += ' ' + build_data.status_verb
|
158
|
+
response += "\n"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
when /status/
|
162
|
+
scheduler = Celluloid::Actor[:scheduler]
|
163
|
+
build_data = scheduler.active_build
|
164
|
+
queue_length = scheduler.queue_length
|
165
|
+
response = ''
|
166
|
+
if build_data.nil?
|
167
|
+
response = "There is currently no build running"
|
168
|
+
if queue_length == 0
|
169
|
+
response += " and no builds in the queue."
|
170
|
+
else
|
171
|
+
response += " and #{queue_length} in the queue."
|
172
|
+
end
|
173
|
+
else
|
174
|
+
case build_data.type
|
175
|
+
when :pull_request
|
176
|
+
response = "There is a pull request build in progress for https://github.com/#{build_data.repo_full_name}/pull/#{build_data.pull_request} (#{build_data._id.to_s})"
|
177
|
+
when :branch
|
178
|
+
response = "There is a build of the `#{build_data.branch}` branch of https://github.com/#{build_data.repo_full_name} in progress (#{build_data._id.to_s})"
|
179
|
+
end
|
180
|
+
unless build_data.started_by.nil?
|
181
|
+
response += build_data.started_by
|
182
|
+
end
|
183
|
+
response += '.'
|
184
|
+
if queue_length == 1
|
185
|
+
response += " There is one build in the queue."
|
186
|
+
elsif queue_length > 1
|
187
|
+
response += " There are #{queue_length} builds in the queue."
|
167
188
|
end
|
168
189
|
end
|
169
190
|
when /options/
|
@@ -171,6 +192,27 @@ Ask me `what happened` to get a list of recent builds and log files and `what op
|
|
171
192
|
- *test channel* to have notifications go to the test channel
|
172
193
|
- *no upload* to not have the build upload
|
173
194
|
)
|
195
|
+
when /queue/
|
196
|
+
response = ''
|
197
|
+
build_datas = Celluloid::Actor[:scheduler].get_build_queue
|
198
|
+
if build_datas.count == 0
|
199
|
+
response = "There are no builds in the queue."
|
200
|
+
else
|
201
|
+
build_datas.each { |build_data|
|
202
|
+
response += "A "
|
203
|
+
response += case build_data.type
|
204
|
+
when :branch
|
205
|
+
"`#{build_data.branch}` branch build"
|
206
|
+
when :pull_request
|
207
|
+
"pull request build #{build_data.pull_request_uri}"
|
208
|
+
end
|
209
|
+
unless build_data.started_by.nil?
|
210
|
+
response += " by #{build_data.started_by}"
|
211
|
+
end
|
212
|
+
response += " (#{build_data._id.to_s})"
|
213
|
+
response += "\n"
|
214
|
+
}
|
215
|
+
end
|
174
216
|
else
|
175
217
|
response = "I'm not sure what to say..."
|
176
218
|
end
|
@@ -189,24 +231,21 @@ Ask me `what happened` to get a list of recent builds and log files and `what op
|
|
189
231
|
map_channel_name_to_id = @rt_client.channels.map {|id, channel| [channel.name, id]}.to_h
|
190
232
|
map_group_name_to_id = @rt_client.groups.map {|id, group| [group.name, id]}.to_h
|
191
233
|
|
192
|
-
@
|
234
|
+
@build_channel_id = Slacker.get_channel_id(Config.slack_build_channel, map_channel_name_to_id, map_group_name_to_id)
|
193
235
|
|
194
|
-
if @
|
236
|
+
if @build_channel_id.nil?
|
195
237
|
error "Unable to identify the build slack channel #{channel}"
|
196
238
|
else
|
197
|
-
info "Slack build notification channel is #{@
|
198
|
-
end
|
199
|
-
|
200
|
-
@test_slack_channel = Slacker.get_channel_id(Config.slack_test_channel, map_channel_name_to_id, map_group_name_to_id)
|
201
|
-
|
202
|
-
if @test_slack_channel.nil?
|
203
|
-
error "Unable to identify the test slack channel #{channel}"
|
204
|
-
else
|
205
|
-
info "Slack test notification channel is #{@test_slack_channel} (#{Config.slack_test_channel})"
|
239
|
+
info "Slack build notification channel is #{@build_channel_id} (#{Config.slack_build_channel})"
|
206
240
|
end
|
207
241
|
end
|
208
242
|
|
209
243
|
def on_slack_data(data)
|
244
|
+
# Don't respond to ephemeral messages from Slack
|
245
|
+
if data['is_ephemeral']
|
246
|
+
return
|
247
|
+
end
|
248
|
+
|
210
249
|
message = data['text']
|
211
250
|
|
212
251
|
# If no message, then there's nothing to do
|
@@ -238,65 +277,50 @@ Ask me `what happened` to get a list of recent builds and log files and `what op
|
|
238
277
|
end
|
239
278
|
|
240
279
|
c = data['channel'][0]
|
241
|
-
|
280
|
+
is_from_slack_channel = (c == 'C' || c == 'G')
|
242
281
|
|
243
|
-
# Don't respond if the message is
|
244
|
-
if
|
282
|
+
# Don't respond if the message is from a channel and our name is not in the message
|
283
|
+
if is_from_slack_channel and !message.match(@rt_client.self['id'])
|
245
284
|
return
|
246
285
|
end
|
247
286
|
|
248
287
|
response = case message
|
249
288
|
when /build (.*)/i
|
250
|
-
do_build $1,
|
251
|
-
when /
|
252
|
-
|
253
|
-
when /
|
254
|
-
|
255
|
-
when /
|
256
|
-
|
257
|
-
when /stop/i
|
258
|
-
do_stop
|
289
|
+
do_build $1, is_from_slack_channel, slack_user_name
|
290
|
+
when /show(.*)/
|
291
|
+
do_show $1
|
292
|
+
when /help/i
|
293
|
+
do_help is_from_slack_channel
|
294
|
+
when /stop(?: build)(.*)/i
|
295
|
+
do_stop $1, is_from_slack_channel, slack_user_name
|
259
296
|
else
|
260
|
-
"Sorry#{
|
297
|
+
"Sorry#{is_from_slack_channel ? ' ' + slack_user_name : ''}, I'm not sure how to respond."
|
261
298
|
end
|
262
299
|
@rt_client.message channel: data['channel'], text: response
|
263
300
|
info "Slack message '#{message}' from #{data['channel']} handled"
|
264
301
|
end
|
265
302
|
|
266
303
|
def notify_channel(build_data)
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
message = "Build #{status_message}"
|
273
|
-
git_state = (build_data.termination_type == :killed ? :failure : build_data.exit_code != 0 ? :error : :success)
|
274
|
-
Celluloid::Actor[:gitter].async.set_status(build_data.repo_full_name, build_data.repo_sha, git_state, message, log_url)
|
275
|
-
info "Pull request build #{status_message}"
|
304
|
+
status_verb = build_data.status_verb
|
305
|
+
|
306
|
+
if build_data.type == :branch
|
307
|
+
message = "A `#{build_data.branch}` branch build #{status_verb}"
|
308
|
+
info "Branch build #{status_verb}"
|
276
309
|
else
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
info "Release branch build #{status_message}"
|
281
|
-
end
|
310
|
+
message = "Pull request `#{build_data.pull_request}` #{status_verb}"
|
311
|
+
info "Pull request build #{status_verb}"
|
312
|
+
end
|
282
313
|
|
283
|
-
|
284
|
-
attach = [
|
285
|
-
:title => build_data.type == :pull_request ? "Pull Request" : "Branch Build",
|
286
|
-
:text => message,
|
287
|
-
:color => build_data.termination_type == :killed ? :warning : build_data.exit_code != 0 ? :danger : :good,
|
288
|
-
]
|
314
|
+
message += ". Log file at #{build_data.server_log_uri}"
|
289
315
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
end
|
299
|
-
end
|
316
|
+
# See https://api.slack.com/docs/attachments for more information about formatting Slack attachments
|
317
|
+
attach = [
|
318
|
+
:title => build_data.type == :pull_request ? "Pull Request" : "Branch Build",
|
319
|
+
:text => message,
|
320
|
+
:color => build_data.termination_type == :killed ? :warning : build_data.exit_code != 0 ? :danger : :good,
|
321
|
+
]
|
322
|
+
|
323
|
+
@rt_client.message(channel: @build_channel_id, text: message, attachments: attach) unless @build_channel_id.nil?
|
300
324
|
end
|
301
325
|
end
|
302
326
|
end
|