bender-bot 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/bender/bot.rb +98 -18
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2eff1d2551be6a4039e117067c97b71a246488bc
|
4
|
+
data.tar.gz: 9b7f0a4415aa65ce54a69c28ee873db38811d706
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be3ff23c1ed7b956262236ccfd94596d88a97ad027dc7c9643accad7a7a60f4dbf808698275700092af2d000bd0a0753a736e2766757842c0573d71456e2071a
|
7
|
+
data.tar.gz: 8436e940e11db1d586ad20fe783a6321dd705be6319141a4b657b06f96fbe0fce6230b155f225a4cdbd7a2e6f6a78986d861ea599fa56e8a5e0c585a7ff9e15a
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/bender/bot.rb
CHANGED
@@ -28,6 +28,16 @@ class BenderBot
|
|
28
28
|
|
29
29
|
JARO = FuzzyStringMatch::JaroWinkler.create :native
|
30
30
|
|
31
|
+
CLOSE_TRANSITIONS = %w[ 21 41 ]
|
32
|
+
|
33
|
+
SEVERITIES = {
|
34
|
+
1 => '10480',
|
35
|
+
2 => '10481',
|
36
|
+
3 => '10482',
|
37
|
+
4 => '10483',
|
38
|
+
5 => '10484'
|
39
|
+
}
|
40
|
+
|
31
41
|
SHOW_FIELDS = {
|
32
42
|
'summary' => 'Summary',
|
33
43
|
'description' => 'Description',
|
@@ -63,23 +73,44 @@ class BenderBot
|
|
63
73
|
'?inc - This help text',
|
64
74
|
'/inc - List open incidents',
|
65
75
|
'/inc NUM - Show incident details',
|
66
|
-
'/inc close NUM - Close an
|
76
|
+
'/inc close NUM - Close an incident',
|
67
77
|
'/inc SEVERITY SUMMARY - File a new incident',
|
68
|
-
'/inc summary - Summarize recent
|
78
|
+
'/inc summary - Summarize recent incidents'
|
69
79
|
].join("\n")
|
70
80
|
|
71
81
|
when /^\s*\/inc\s*$/
|
72
82
|
refresh_incidents
|
73
83
|
|
74
84
|
is = store['incidents'].map do |i|
|
75
|
-
|
76
|
-
|
85
|
+
status = normalize_value i['fields']['status']
|
86
|
+
unless status =~ /done|complete|closed/i
|
87
|
+
'%s: %s' % [ i['num'], i['fields']['summary'] ]
|
88
|
+
end
|
89
|
+
end.compact.join("\n")
|
77
90
|
|
78
91
|
reply is
|
79
92
|
|
80
93
|
when /^\s*\/inc\s+summary\s*$/
|
81
|
-
|
82
|
-
|
94
|
+
refresh_incidents
|
95
|
+
|
96
|
+
severity_field = SHOW_FIELDS.key 'Severity'
|
97
|
+
severities = Hash.new { |h,k| h[k] = [] }
|
98
|
+
|
99
|
+
store['incidents'].each do |i|
|
100
|
+
if recent_incident? i
|
101
|
+
repr = '%s-%s: %s' % [
|
102
|
+
options.jira_project, i['num'], i['fields']['summary']
|
103
|
+
]
|
104
|
+
sev = i['fields'][severity_field]['value']
|
105
|
+
severities[sev] << repr
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
is = severities.keys.sort.map do |sev|
|
110
|
+
"%s:\n%s" % [ sev, severities[sev].join("\n") ]
|
111
|
+
end.join("\n\n")
|
112
|
+
|
113
|
+
reply is
|
83
114
|
|
84
115
|
when /^\s*\/inc\s+(\d+)\s*$/
|
85
116
|
refresh_incidents
|
@@ -96,31 +127,30 @@ class BenderBot
|
|
96
127
|
end
|
97
128
|
end.compact
|
98
129
|
|
99
|
-
reply "%s: %s\n%s" % [
|
130
|
+
reply "%s\n%s: %s\n%s" % [
|
131
|
+
(options.jira_site + '/browse/' + incident['key']),
|
100
132
|
incident['key'],
|
101
133
|
incident['fields']['summary'],
|
102
134
|
i.join("\n")
|
103
135
|
]
|
104
136
|
|
105
137
|
when /^\s*\/inc\s+close\s+(\d+)\s*$/
|
106
|
-
# TODO
|
107
|
-
reply "Sorry, I haven't been programmed for that yet!"
|
108
|
-
|
109
|
-
when /^\s*\/inc\s+(\d+)\s+(.*?)\s*$/
|
110
138
|
refresh_incidents
|
111
139
|
incident = store['incidents'].select { |i| i['num'] == $1 }.first
|
112
|
-
val = incident['fields'][$2]
|
113
|
-
val = val.is_a?(Hash) ? val['name'] : val
|
114
|
-
reply val
|
115
140
|
|
116
|
-
|
141
|
+
reply close_incident(incident)
|
142
|
+
|
143
|
+
when /^\s*\/inc\s+(sev|s|p)?(\d+)\s+(.*?)\s*$/i
|
117
144
|
user = user_where name: sender
|
118
145
|
data = {
|
119
146
|
fields: {
|
120
147
|
project: { key: options.jira_project },
|
121
148
|
issuetype: { name: options.jira_type },
|
122
149
|
reporter: { name: user[:nick] },
|
123
|
-
summary: $
|
150
|
+
summary: $3,
|
151
|
+
SHOW_FIELDS.key('Severity') => {
|
152
|
+
id: SEVERITIES[$2.to_i]
|
153
|
+
}
|
124
154
|
}
|
125
155
|
}
|
126
156
|
|
@@ -160,7 +190,7 @@ private
|
|
160
190
|
def refresh_incidents
|
161
191
|
req_path = '/rest/api/2/search'
|
162
192
|
req_params = QueryParams.encode \
|
163
|
-
jql: "project = #{options.jira_project}
|
193
|
+
jql: "project = #{options.jira_project} ORDER BY created ASC, priority DESC",
|
164
194
|
fields: SHOW_FIELDS.keys.join(','),
|
165
195
|
startAt: 0,
|
166
196
|
maxResults: 1_000_000
|
@@ -193,13 +223,51 @@ private
|
|
193
223
|
req['Accept'] = 'application/json'
|
194
224
|
req.body = data.to_json
|
195
225
|
|
196
|
-
resp
|
226
|
+
resp = http.request req
|
197
227
|
issue = JSON.parse(resp.body)
|
198
228
|
|
199
229
|
return options.jira_site + '/browse/' + issue['key']
|
200
230
|
end
|
201
231
|
|
202
232
|
|
233
|
+
def close_incident incident
|
234
|
+
req_path = '/rest/api/2/issue/%s/transitions?expand=transitions.fields' % [
|
235
|
+
incident['key']
|
236
|
+
]
|
237
|
+
uri = URI(options.jira_site + req_path)
|
238
|
+
http = Net::HTTP.new uri.hostname, uri.port
|
239
|
+
|
240
|
+
req = Net::HTTP::Post.new uri
|
241
|
+
req.basic_auth options.jira_user, options.jira_pass
|
242
|
+
req['Content-Type'] = 'application/json'
|
243
|
+
req['Accept'] = 'application/json'
|
244
|
+
|
245
|
+
closed = false
|
246
|
+
CLOSE_TRANSITIONS.each do |tid|
|
247
|
+
req.body = {
|
248
|
+
transition: { id: tid }
|
249
|
+
}.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
|
258
|
+
end
|
259
|
+
|
260
|
+
if closed
|
261
|
+
'Closed: ' + options.jira_site + '/browse/' + incident['key']
|
262
|
+
else
|
263
|
+
[
|
264
|
+
"Failed to close, make sure you've got the ticket filled out",
|
265
|
+
(options.jira_site + '/browse/' + incident['key'])
|
266
|
+
].join("\n")
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
|
203
271
|
def normalize_value val
|
204
272
|
case val
|
205
273
|
when Hash
|
@@ -213,8 +281,20 @@ private
|
|
213
281
|
end
|
214
282
|
end
|
215
283
|
|
284
|
+
|
216
285
|
def normalize_date val
|
217
286
|
Time.parse(val).utc.iso8601(3).sub(/Z$/, 'UTC')
|
218
287
|
end
|
219
288
|
|
289
|
+
|
290
|
+
def recent_incident? i
|
291
|
+
it = Time.parse(i['fields']['created'])
|
292
|
+
Time.now - it < one_day
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
def one_day
|
297
|
+
24 * 60 * 60 # seconds/day
|
298
|
+
end
|
299
|
+
|
220
300
|
end
|