build-buddy 1.11.0 → 1.12.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 +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
|