bender-bot 0.0.3 → 0.1.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/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
|