bender-bot 0.1.0 → 0.1.1
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/VERSION +1 -1
- data/lib/bender/bot.rb +152 -52
- data/lib/bender/main.rb +1 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 268fd0e2852e1f26a640003d74b3b6bd7ed12700
|
4
|
+
data.tar.gz: 107352d30d4f117cc3d99b1110105db9a557c357
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7bc07efab94683ef5825319cef8fd436f24e24f60440982d8f7ffda57d2d6fb6a24de70cd3ecfae5f03413266e348426b486dd9c3f1535c7213f418757ce92d
|
7
|
+
data.tar.gz: bf6b12223f0fe6262079e021b144389d8a80559e6932bb5603c50fc1747c0d0c215d7607b3748ba6404750d5b1c7ac53db9fc9c505004fa6ec78b606040ce91c
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/lib/bender/bot.rb
CHANGED
@@ -30,6 +30,8 @@ class BenderBot
|
|
30
30
|
|
31
31
|
CLOSE_TRANSITIONS = %w[ 21 41 ]
|
32
32
|
|
33
|
+
CLOSE_STATE = /done/i
|
34
|
+
|
33
35
|
SEVERITIES = {
|
34
36
|
1 => '10480',
|
35
37
|
2 => '10481',
|
@@ -54,6 +56,9 @@ class BenderBot
|
|
54
56
|
|
55
57
|
|
56
58
|
def handle time, sender, message
|
59
|
+
severity_field = SHOW_FIELDS.key 'Severity'
|
60
|
+
severities = Hash.new { |h,k| h[k] = [] }
|
61
|
+
|
57
62
|
case message
|
58
63
|
|
59
64
|
|
@@ -68,79 +73,127 @@ class BenderBot
|
|
68
73
|
u = user_where(name: $1) || user_where(nick: $1)
|
69
74
|
reply '%s: %s (%s)' % [ u[:nick], u[:name], u[:email] ]
|
70
75
|
|
76
|
+
# ?inc - This help text
|
71
77
|
when /^\s*\?inc\s*$/
|
72
78
|
reply [
|
73
|
-
'?inc -
|
79
|
+
'?inc - Display this help text',
|
74
80
|
'/inc - List open incidents',
|
75
|
-
'/inc
|
76
|
-
'/inc close
|
77
|
-
'/inc SEVERITY
|
78
|
-
'/inc summary - Summarize
|
81
|
+
'/inc [INCIDENT_NUMBER] - Display incident details',
|
82
|
+
'/inc close [INCIDENT_NUMBER] - Close an incident',
|
83
|
+
'/inc open [SEVERITY=1,2,3,4,5] [SUMMARY_TEXT] - Open a new incident',
|
84
|
+
'/inc summary - Summarize incidents from past 24 hours (open or closed)',
|
85
|
+
'/inc comment [INCIDENT_NUMBER] [COMMENT_TEXT] - Add a comment to an incident'
|
79
86
|
].join("\n")
|
80
87
|
|
88
|
+
# /inc - List open incidents
|
81
89
|
when /^\s*\/inc\s*$/
|
82
90
|
refresh_incidents
|
83
91
|
|
84
|
-
is = store['incidents'].map do |i|
|
92
|
+
is = store['incidents'].reverse.map do |i|
|
85
93
|
status = normalize_value i['fields']['status']
|
86
94
|
unless status =~ /done|complete|closed/i
|
87
|
-
'%s
|
95
|
+
'%s-%s (%s - %s) [%s]: %s' % [
|
96
|
+
options.jira_project,
|
97
|
+
i['num'],
|
98
|
+
short_severity(i['fields'][severity_field]['value']),
|
99
|
+
normalize_value(i['fields']['status']),
|
100
|
+
friendly_date(i['fields']['created']),
|
101
|
+
i['fields']['summary']
|
102
|
+
]
|
88
103
|
end
|
89
104
|
end.compact.join("\n")
|
90
105
|
|
106
|
+
is = 'No open incidents at the moment!' if is.empty?
|
107
|
+
|
91
108
|
reply is
|
92
109
|
|
110
|
+
# /inc summary - Summarize recent incidents
|
93
111
|
when /^\s*\/inc\s+summary\s*$/
|
94
112
|
refresh_incidents
|
95
113
|
|
96
|
-
|
97
|
-
severities = Hash.new { |h,k| h[k] = [] }
|
114
|
+
statuses = Hash.new { |h,k| h[k] = 0 }
|
98
115
|
|
99
|
-
store['incidents'].each do |i|
|
116
|
+
store['incidents'].reverse.each do |i|
|
100
117
|
if recent_incident? i
|
101
|
-
|
102
|
-
|
118
|
+
status = normalize_value(i['fields']['status'])
|
119
|
+
|
120
|
+
repr = '%s-%s (%s) [%s]: %s' % [
|
121
|
+
options.jira_project,
|
122
|
+
i['num'],
|
123
|
+
status,
|
124
|
+
friendly_date(i['fields']['created']),
|
125
|
+
i['fields']['summary']
|
103
126
|
]
|
127
|
+
|
104
128
|
sev = i['fields'][severity_field]['value']
|
105
129
|
severities[sev] << repr
|
130
|
+
statuses[status] += 1
|
106
131
|
end
|
107
132
|
end
|
108
133
|
|
109
|
-
|
110
|
-
|
111
|
-
|
134
|
+
summary = []
|
135
|
+
summary << 'By Status:'
|
136
|
+
statuses.each do |status, size|
|
137
|
+
summary << '%s: %d ticket(s)' % [ status, size ]
|
138
|
+
end
|
139
|
+
summary << ''
|
140
|
+
summary << 'By Severity:'
|
141
|
+
severities.keys.sort.each do |severity|
|
142
|
+
summary << '%s: %d ticket(s)' % [
|
143
|
+
short_severity(severity),
|
144
|
+
severities[severity].size
|
145
|
+
]
|
146
|
+
end
|
112
147
|
|
113
|
-
|
148
|
+
if severities.empty?
|
149
|
+
reply 'No recent incidents! Woohoo!'
|
114
150
|
|
115
|
-
|
116
|
-
|
117
|
-
|
151
|
+
else
|
152
|
+
is = severities.keys.sort.map do |sev|
|
153
|
+
"%s:\n%s" % [ sev, severities[sev].join("\n") ]
|
154
|
+
end.join("\n\n")
|
118
155
|
|
119
|
-
|
156
|
+
reply(summary.join("\n") + "\n\n" + is)
|
157
|
+
end
|
120
158
|
|
121
|
-
i = fields.map do |f|
|
122
|
-
val = incident['fields'][f]
|
123
|
-
if val
|
124
|
-
key = SHOW_FIELDS[f]
|
125
|
-
val = normalize_value val
|
126
|
-
'%s: %s' % [ key, val ]
|
127
|
-
end
|
128
|
-
end.compact
|
129
159
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
incident['fields']['summary'],
|
134
|
-
i.join("\n")
|
135
|
-
]
|
160
|
+
# /inc NUM - Show incident details
|
161
|
+
when /^\s*\/inc\s+(\d+)\s*$/
|
162
|
+
incident = select_incident $1
|
136
163
|
|
137
|
-
|
138
|
-
|
139
|
-
|
164
|
+
if incident.nil?
|
165
|
+
reply 'Sorry, no such incident!'
|
166
|
+
else
|
167
|
+
fields = SHOW_FIELDS.keys - %w[ summary ]
|
168
|
+
|
169
|
+
i = fields.map do |f|
|
170
|
+
val = incident['fields'][f]
|
171
|
+
if val
|
172
|
+
key = SHOW_FIELDS[f]
|
173
|
+
val = normalize_value val
|
174
|
+
'%s: %s' % [ key, val ]
|
175
|
+
end
|
176
|
+
end.compact
|
177
|
+
|
178
|
+
reply "%s\n%s: %s\n%s" % [
|
179
|
+
(options.jira_site + '/browse/' + incident['key']),
|
180
|
+
incident['key'],
|
181
|
+
incident['fields']['summary'],
|
182
|
+
i.join("\n")
|
183
|
+
]
|
184
|
+
end
|
140
185
|
|
141
|
-
|
186
|
+
# /inc close NUM - Close an incident
|
187
|
+
when /^\s*\/inc\s+close\s+(\d+)\s*$/
|
188
|
+
incident = select_incident $1
|
189
|
+
if incident
|
190
|
+
reply close_incident(incident)
|
191
|
+
else
|
192
|
+
reply 'Sorry, no such incident!'
|
193
|
+
end
|
142
194
|
|
143
|
-
|
195
|
+
# /inc open SEVERITY SUMMARY - File a new incident
|
196
|
+
when /^\s*\/inc\s+open\s+(severity|sev|s|p)?(\d+)\s+(.*?)\s*$/i
|
144
197
|
user = user_where name: sender
|
145
198
|
data = {
|
146
199
|
fields: {
|
@@ -155,6 +208,15 @@ class BenderBot
|
|
155
208
|
}
|
156
209
|
|
157
210
|
reply file_incident(data)
|
211
|
+
|
212
|
+
|
213
|
+
# /inc comment [INCIDENT_NUMBER] [COMMENT_TEXT]
|
214
|
+
when /^\s*\/inc\s+comment\s+(\d+)\s+(.*?)\s*$/i
|
215
|
+
incident = select_incident $1
|
216
|
+
comment = $2
|
217
|
+
user = user_where name: sender
|
218
|
+
|
219
|
+
reply comment_on_incident(incident, comment, user)
|
158
220
|
end
|
159
221
|
|
160
222
|
return true
|
@@ -226,7 +288,11 @@ private
|
|
226
288
|
resp = http.request req
|
227
289
|
issue = JSON.parse(resp.body)
|
228
290
|
|
229
|
-
|
291
|
+
if issue.has_key? 'key'
|
292
|
+
options.jira_site + '/browse/' + issue['key']
|
293
|
+
else
|
294
|
+
"Sorry, I couldn't file that!"
|
295
|
+
end
|
230
296
|
end
|
231
297
|
|
232
298
|
|
@@ -242,26 +308,44 @@ private
|
|
242
308
|
req['Content-Type'] = 'application/json'
|
243
309
|
req['Accept'] = 'application/json'
|
244
310
|
|
245
|
-
closed = false
|
246
311
|
CLOSE_TRANSITIONS.each do |tid|
|
247
312
|
req.body = {
|
248
313
|
transition: { id: tid }
|
249
314
|
}.to_json
|
250
|
-
|
251
|
-
case resp
|
252
|
-
when Net::HTTPBadRequest
|
253
|
-
next
|
254
|
-
else
|
255
|
-
closed = true
|
256
|
-
break
|
257
|
-
end
|
315
|
+
http.request req
|
258
316
|
end
|
259
317
|
|
260
|
-
|
318
|
+
incident = select_incident incident['key'].split('-',2).last
|
319
|
+
status = normalize_value incident['fields']['status']
|
320
|
+
|
321
|
+
if status =~ CLOSE_STATE
|
261
322
|
'Closed: ' + options.jira_site + '/browse/' + incident['key']
|
262
323
|
else
|
263
324
|
[
|
264
|
-
|
325
|
+
'Failed to close automatically, you might try yourself',
|
326
|
+
(options.jira_site + '/browse/' + incident['key'])
|
327
|
+
].join("\n")
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
|
332
|
+
def comment_on_incident incident, comment, user
|
333
|
+
req_path = '/rest/api/2/issue/%s/comment' % incident['key']
|
334
|
+
uri = URI(options.jira_site + req_path)
|
335
|
+
http = Net::HTTP.new uri.hostname, uri.port
|
336
|
+
|
337
|
+
req = Net::HTTP::Post.new uri
|
338
|
+
req.basic_auth options.jira_user, options.jira_pass
|
339
|
+
req['Content-Type'] = 'application/json'
|
340
|
+
req['Accept'] = 'application/json'
|
341
|
+
req.body = { body: '_[~%s]_ says: %s' % [ user[:nick], comment ] }.to_json
|
342
|
+
|
343
|
+
case http.request(req)
|
344
|
+
when Net::HTTPCreated
|
345
|
+
'Added: ' + options.jira_site + '/browse/' + incident['key']
|
346
|
+
else
|
347
|
+
[
|
348
|
+
'Sorry, I had trouble adding your comment',
|
265
349
|
(options.jira_site + '/browse/' + incident['key'])
|
266
350
|
].join("\n")
|
267
351
|
end
|
@@ -283,7 +367,12 @@ private
|
|
283
367
|
|
284
368
|
|
285
369
|
def normalize_date val
|
286
|
-
Time.parse(val).utc.iso8601(
|
370
|
+
Time.parse(val).utc.iso8601(0).sub(/Z$/, 'UTC')
|
371
|
+
end
|
372
|
+
|
373
|
+
|
374
|
+
def friendly_date val
|
375
|
+
Time.parse(val).strftime('%Y-%m-%d %H:%M %Z')
|
287
376
|
end
|
288
377
|
|
289
378
|
|
@@ -297,4 +386,15 @@ private
|
|
297
386
|
24 * 60 * 60 # seconds/day
|
298
387
|
end
|
299
388
|
|
389
|
+
|
390
|
+
def select_incident num, refresh=true
|
391
|
+
refresh_incidents if refresh
|
392
|
+
store['incidents'].select { |i| i['num'] == num }.first
|
393
|
+
end
|
394
|
+
|
395
|
+
|
396
|
+
def short_severity s
|
397
|
+
s.split(' - ', 2).first
|
398
|
+
end
|
399
|
+
|
300
400
|
end
|
data/lib/bender/main.rb
CHANGED
@@ -153,7 +153,6 @@ module Bender
|
|
153
153
|
Thread.new do
|
154
154
|
loop do
|
155
155
|
resp = http.request req
|
156
|
-
|
157
156
|
users = JSON.parse(resp.body).inject({}) do |h, user|
|
158
157
|
h[user['key']] = {
|
159
158
|
nick: user['key'],
|
@@ -189,4 +188,4 @@ module Bender
|
|
189
188
|
|
190
189
|
|
191
190
|
end
|
192
|
-
end
|
191
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bender-bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Clemmer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|