bender-bot 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/bender/bot.rb +152 -52
  4. data/lib/bender/main.rb +1 -2
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2eff1d2551be6a4039e117067c97b71a246488bc
4
- data.tar.gz: 9b7f0a4415aa65ce54a69c28ee873db38811d706
3
+ metadata.gz: 268fd0e2852e1f26a640003d74b3b6bd7ed12700
4
+ data.tar.gz: 107352d30d4f117cc3d99b1110105db9a557c357
5
5
  SHA512:
6
- metadata.gz: be3ff23c1ed7b956262236ccfd94596d88a97ad027dc7c9643accad7a7a60f4dbf808698275700092af2d000bd0a0753a736e2766757842c0573d71456e2071a
7
- data.tar.gz: 8436e940e11db1d586ad20fe783a6321dd705be6319141a4b657b06f96fbe0fce6230b155f225a4cdbd7a2e6f6a78986d861ea599fa56e8a5e0c585a7ff9e15a
6
+ metadata.gz: c7bc07efab94683ef5825319cef8fd436f24e24f60440982d8f7ffda57d2d6fb6a24de70cd3ecfae5f03413266e348426b486dd9c3f1535c7213f418757ce92d
7
+ data.tar.gz: bf6b12223f0fe6262079e021b144389d8a80559e6932bb5603c50fc1747c0d0c215d7607b3748ba6404750d5b1c7ac53db9fc9c505004fa6ec78b606040ce91c
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -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 - This help text',
79
+ '?inc - Display this help text',
74
80
  '/inc - List open incidents',
75
- '/inc NUM - Show incident details',
76
- '/inc close NUM - Close an incident',
77
- '/inc SEVERITY SUMMARY - File a new incident',
78
- '/inc summary - Summarize recent incidents'
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: %s' % [ i['num'], i['fields']['summary'] ]
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
- severity_field = SHOW_FIELDS.key 'Severity'
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
- repr = '%s-%s: %s' % [
102
- options.jira_project, i['num'], i['fields']['summary']
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
- is = severities.keys.sort.map do |sev|
110
- "%s:\n%s" % [ sev, severities[sev].join("\n") ]
111
- end.join("\n\n")
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
- reply is
148
+ if severities.empty?
149
+ reply 'No recent incidents! Woohoo!'
114
150
 
115
- when /^\s*\/inc\s+(\d+)\s*$/
116
- refresh_incidents
117
- incident = store['incidents'].select { |i| i['num'] == $1 }.first
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
- fields = SHOW_FIELDS.keys - %w[ summary ]
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
- reply "%s\n%s: %s\n%s" % [
131
- (options.jira_site + '/browse/' + incident['key']),
132
- incident['key'],
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
- when /^\s*\/inc\s+close\s+(\d+)\s*$/
138
- refresh_incidents
139
- incident = store['incidents'].select { |i| i['num'] == $1 }.first
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
- reply close_incident(incident)
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
- when /^\s*\/inc\s+(sev|s|p)?(\d+)\s+(.*?)\s*$/i
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
- return options.jira_site + '/browse/' + issue['key']
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
- resp = http.request req
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
- if closed
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
- "Failed to close, make sure you've got the ticket filled out",
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(3).sub(/Z$/, 'UTC')
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
@@ -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.0
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-14 00:00:00.000000000 Z
11
+ date: 2015-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor