lita-statuspage 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.rubocop.yml +7 -8
- data/.travis.yml +4 -4
- data/Gemfile +1 -1
- data/README.md +8 -5
- data/Rakefile +2 -2
- data/lib/lita/handlers/statuspage.rb +115 -185
- data/lita-statuspage.gemspec +9 -10
- data/locales/en.yml +44 -0
- data/spec/lita/handlers/statuspage_spec.rb +313 -325
- data/spec/spec_helper.rb +19 -0
- metadata +18 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79269c762a45f49d7289a9bd740576eff2f0ed63
|
4
|
+
data.tar.gz: 218cca7791ea9dbed9a38ea8e805826616e4f7be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a367bde834b533daf0a75caeab2bf15137e2a2c0a9094cb410c2914bd5307cdc93ca6f91cc07eeee726a2484a958dca8a1a6585a70a70bce97ca80843e058c6
|
7
|
+
data.tar.gz: 0eb8b4400b3740db4fe561d545fe724694a0d8eaeb99011a27c85d9c7b21b38ddce51eca9b55c7ff9050b31ab8a9e5554f662a7225d065d4088642003df4312b
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --profile 5
|
data/.rubocop.yml
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
ClassLength:
|
2
|
-
Max:
|
3
|
-
|
4
|
-
CyclomaticComplexity:
|
5
|
-
Max: 10
|
2
|
+
Max: 260
|
6
3
|
|
7
4
|
Documentation:
|
8
|
-
|
5
|
+
Exclude:
|
6
|
+
- lib/lita/handlers/statuspage.rb
|
9
7
|
|
10
8
|
FileName:
|
9
|
+
Exclude:
|
10
|
+
- lib/lita-statuspage.rb
|
11
|
+
|
12
|
+
AbcSize:
|
11
13
|
Enabled: false
|
12
14
|
|
13
15
|
LineLength:
|
14
16
|
Max: 130
|
15
|
-
|
16
|
-
MethodLength:
|
17
|
-
Max: 30
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
# lita-statuspage
|
2
2
|
|
3
|
-
[![Build Status](https://
|
4
|
-
[![
|
5
|
-
[![
|
6
|
-
|
7
|
-
|
3
|
+
[![Build Status](https://img.shields.io/travis/esigler/lita-statuspage/master.svg)](https://travis-ci.org/esigler/lita-statuspage)
|
4
|
+
[![MIT License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://tldrlegal.com/license/mit-license)
|
5
|
+
[![RubyGems :: RMuh Gem Version](http://img.shields.io/gem/v/lita-statuspage.svg)](https://rubygems.org/gems/lita-statuspage)
|
6
|
+
[![Coveralls Coverage](https://img.shields.io/coveralls/esigler/lita-statuspage/master.svg)](https://coveralls.io/r/esigler/lita-statuspage)
|
7
|
+
[![Code Climate](https://img.shields.io/codeclimate/github/esigler/lita-statuspage.svg)](https://codeclimate.com/github/esigler/lita-statuspage)
|
8
|
+
[![Gemnasium](https://img.shields.io/gemnasium/esigler/lita-statuspage.svg)](https://gemnasium.com/esigler/lita-statuspage)
|
9
|
+
|
10
|
+
A [Statuspage.io](http://statuspage.io) plugin for [Lita](https://github.com/jimmycuadra/lita).
|
8
11
|
|
9
12
|
## Installation
|
10
13
|
|
data/Rakefile
CHANGED
@@ -1,19 +1,15 @@
|
|
1
1
|
module Lita
|
2
2
|
module Handlers
|
3
3
|
class Statuspage < Handler
|
4
|
+
config :api_key, required: true
|
5
|
+
config :page_id, required: true
|
6
|
+
|
4
7
|
route(
|
5
8
|
/^(?:statuspage|sp)\sincident\snew\s(.+)$/,
|
6
9
|
:incident_new,
|
7
10
|
command: true,
|
8
11
|
help: {
|
9
|
-
'
|
10
|
-
' status:<status>' => '(Optional) One of: investigating|identified|monitoring' \
|
11
|
-
'|resolved (default: investigating)',
|
12
|
-
' message:"<message>"' => '(Optional) The initial message',
|
13
|
-
' twitter:<state>' => '(Optional) Post the new incident to Twitter, one of: ' \
|
14
|
-
'(true|t|false|f) (default:false)',
|
15
|
-
' impact:<state>' => '(Optional) Override calculated impact value, one of: ' \
|
16
|
-
'(minor|major|critical)'
|
12
|
+
t('help.incident.new.syntax') => t('help.incident.new.desc')
|
17
13
|
}
|
18
14
|
)
|
19
15
|
|
@@ -22,7 +18,7 @@ module Lita
|
|
22
18
|
:incident_update,
|
23
19
|
command: true,
|
24
20
|
help: {
|
25
|
-
'
|
21
|
+
t('help.incident.update.syntax') => t('help.incident.update.desc')
|
26
22
|
}
|
27
23
|
)
|
28
24
|
|
@@ -31,7 +27,7 @@ module Lita
|
|
31
27
|
:incident_list_all,
|
32
28
|
command: true,
|
33
29
|
help: {
|
34
|
-
'
|
30
|
+
t('help.incident.list_all.syntax') => t('help.incident.list_all.desc')
|
35
31
|
}
|
36
32
|
)
|
37
33
|
|
@@ -40,7 +36,7 @@ module Lita
|
|
40
36
|
:incident_list_scheduled,
|
41
37
|
command: true,
|
42
38
|
help: {
|
43
|
-
'
|
39
|
+
t('help.incident.list_sch.syntax') => t('help.incident.list_sch.desc')
|
44
40
|
}
|
45
41
|
)
|
46
42
|
|
@@ -49,7 +45,7 @@ module Lita
|
|
49
45
|
:incident_list_unresolved,
|
50
46
|
command: true,
|
51
47
|
help: {
|
52
|
-
'
|
48
|
+
t('help.incident.list_unr.syntax') => t('help.incident.list_unr.desc')
|
53
49
|
}
|
54
50
|
)
|
55
51
|
|
@@ -58,7 +54,7 @@ module Lita
|
|
58
54
|
:incident_delete_latest,
|
59
55
|
command: true,
|
60
56
|
help: {
|
61
|
-
'
|
57
|
+
t('help.incident.delete_l.syntax') => t('help.incident.delete_l.desc')
|
62
58
|
}
|
63
59
|
)
|
64
60
|
|
@@ -67,7 +63,7 @@ module Lita
|
|
67
63
|
:incident_delete,
|
68
64
|
command: true,
|
69
65
|
help: {
|
70
|
-
'
|
66
|
+
t('help.incident.delete_i.syntax') => t('help.incident.delete_i.desc')
|
71
67
|
}
|
72
68
|
)
|
73
69
|
|
@@ -76,7 +72,7 @@ module Lita
|
|
76
72
|
:component_list,
|
77
73
|
command: true,
|
78
74
|
help: {
|
79
|
-
'
|
75
|
+
t('help.component.list.syntax') => t('help.component.list.desc')
|
80
76
|
}
|
81
77
|
)
|
82
78
|
|
@@ -85,37 +81,14 @@ module Lita
|
|
85
81
|
:component_update,
|
86
82
|
command: true,
|
87
83
|
help: {
|
88
|
-
'
|
84
|
+
t('help.component.update.syntax') => t('help.component.update.desc')
|
89
85
|
}
|
90
86
|
)
|
91
87
|
|
92
|
-
def self.default_config(config)
|
93
|
-
config.api_key = nil
|
94
|
-
config.page_id = nil
|
95
|
-
end
|
96
|
-
|
97
88
|
def incident_new(response)
|
98
89
|
args = parse_args(response.matches[0][0])
|
99
90
|
|
100
|
-
|
101
|
-
response.reply('Can\'t create incident, missing incident name')
|
102
|
-
return
|
103
|
-
end
|
104
|
-
|
105
|
-
if args.key?('status') && !valid_incident_status?(args['status'])
|
106
|
-
response.reply('Can\'t create incident, invalid incident state')
|
107
|
-
return
|
108
|
-
end
|
109
|
-
|
110
|
-
if args.key?('twitter') && !valid_twitter_status?(args['twitter'])
|
111
|
-
response.reply('Can\'t create incident, invalid twitter state')
|
112
|
-
return
|
113
|
-
end
|
114
|
-
|
115
|
-
if args.key?('impact') && !valid_impact_value?(args['impact'])
|
116
|
-
response.reply('Can\'t create incident, invalid impact value')
|
117
|
-
return
|
118
|
-
end
|
91
|
+
return response.reply(t('error.invalid_arguments')) unless valid_args?(args)
|
119
92
|
|
120
93
|
response.reply(create_incident(args))
|
121
94
|
end
|
@@ -123,30 +96,7 @@ module Lita
|
|
123
96
|
def incident_update(response)
|
124
97
|
args = parse_args(response.matches[0][0])
|
125
98
|
|
126
|
-
|
127
|
-
response.reply('Can\'t update incident, missing incident ID')
|
128
|
-
return
|
129
|
-
end
|
130
|
-
|
131
|
-
if args.length < 2
|
132
|
-
response.reply('Can\'t update incident, nothing to update')
|
133
|
-
return
|
134
|
-
end
|
135
|
-
|
136
|
-
if args.key?('status') && !valid_incident_status?(args['status'])
|
137
|
-
response.reply('Can\'t update incident, invalid incident state')
|
138
|
-
return
|
139
|
-
end
|
140
|
-
|
141
|
-
if args.key?('twitter') && !valid_twitter_status?(args['twitter'])
|
142
|
-
response.reply('Can\'t update incident, invalid twitter state')
|
143
|
-
return
|
144
|
-
end
|
145
|
-
|
146
|
-
if args.key?('impact') && !valid_impact_value?(args['impact'])
|
147
|
-
response.reply('Can\'t update incident, invalid impact value')
|
148
|
-
return
|
149
|
-
end
|
99
|
+
return response.reply(t('error.invalid_arguments')) unless valid_args?(args)
|
150
100
|
|
151
101
|
response.reply(update_incident(args['id'], args))
|
152
102
|
end
|
@@ -171,11 +121,10 @@ module Lita
|
|
171
121
|
|
172
122
|
def incident_delete_latest(response)
|
173
123
|
incident = latest_incident
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
end
|
124
|
+
|
125
|
+
return response.reply(t('incident.not_found')) unless incident
|
126
|
+
|
127
|
+
response.reply(delete_incident(incident['id']))
|
179
128
|
end
|
180
129
|
|
181
130
|
def incident_delete(response)
|
@@ -185,148 +134,118 @@ module Lita
|
|
185
134
|
|
186
135
|
def component_list(response)
|
187
136
|
components = api_request('get', 'components')
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
response.reply('No components to list')
|
195
|
-
end
|
196
|
-
else
|
197
|
-
response.reply('Error fetching components')
|
137
|
+
|
138
|
+
return response.reply(t('error.api_request')) if components.nil?
|
139
|
+
return response.reply(t('component.none')) if components.count == 0
|
140
|
+
|
141
|
+
components.each do |component|
|
142
|
+
response.reply(format_component(component))
|
198
143
|
end
|
199
144
|
end
|
200
145
|
|
201
146
|
def component_update(response)
|
202
147
|
args = parse_args(response.matches[0][0])
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
request_args['component[status]'] = args['status']
|
210
|
-
else
|
211
|
-
response.reply('Invalid status to use in updates')
|
212
|
-
return
|
213
|
-
end
|
214
|
-
else
|
215
|
-
request_args['component[status]='] = ''
|
216
|
-
end
|
217
|
-
|
218
|
-
if args.key?('id')
|
219
|
-
response.reply(update_component(args['id'], request_args))
|
220
|
-
elsif args.key?('name')
|
221
|
-
component = component(args['name'])
|
222
|
-
response.reply(update_component(component['id'], request_args))
|
223
|
-
else
|
224
|
-
response.reply('Need an identifier for the component')
|
225
|
-
end
|
226
|
-
end
|
148
|
+
c_id = identify_component(args)
|
149
|
+
|
150
|
+
return response.reply(t('component.need_identifier')) unless c_id
|
151
|
+
return response.reply(t('component.invalid_status')) unless valid_component_status?(args['status'])
|
152
|
+
|
153
|
+
response.reply(update_component(c_id, 'component[status]' => args['status']))
|
227
154
|
end
|
228
155
|
|
229
156
|
private
|
230
157
|
|
231
158
|
def incident(id)
|
232
159
|
incidents = api_request('get', 'incidents')
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
160
|
+
return nil unless incidents && incidents.count > 0
|
161
|
+
|
162
|
+
incidents.each do |incident|
|
163
|
+
return incident if incident['id'] == id
|
237
164
|
end
|
165
|
+
|
238
166
|
nil
|
239
167
|
end
|
240
168
|
|
241
169
|
def latest_incident
|
242
170
|
incidents = api_request('get', 'incidents')
|
243
171
|
return nil unless incidents && incidents.count > 0
|
172
|
+
|
244
173
|
incidents.first
|
245
174
|
end
|
246
175
|
|
247
176
|
def list_incidents(resource)
|
248
177
|
incidents = api_request('get', resource)
|
178
|
+
return [t('error.api_request')] unless incidents
|
179
|
+
|
249
180
|
response = []
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
response.push("#{format_incident(incident)}")
|
254
|
-
end
|
255
|
-
else
|
256
|
-
response = ['Error fetching incidents']
|
181
|
+
response = ['No incidents to list'] unless incidents.count > 0
|
182
|
+
incidents.each do |incident|
|
183
|
+
response.push("#{format_incident(incident)}")
|
257
184
|
end
|
185
|
+
|
258
186
|
response
|
259
187
|
end
|
260
188
|
|
261
189
|
def create_incident(args)
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
else
|
272
|
-
'Error creating incident'
|
273
|
-
end
|
190
|
+
api_args = {}
|
191
|
+
api_args['incident[name]'] = args['name']
|
192
|
+
api_args['incident[status]'] = args['status'] if args.key?('status')
|
193
|
+
api_args['incident[wants_twitter_update]'] = args['twitter'] if args.key?('twitter')
|
194
|
+
api_args['incident[message]'] = args['message'] if args.key?('message')
|
195
|
+
api_args['incident[impact_override]'] = args['impact'] if args.key?('impact')
|
196
|
+
|
197
|
+
result = api_request('post', 'incidents.json', api_args)
|
198
|
+
result ? t('incident.created', id: result['id']) : t('error.api_request')
|
274
199
|
end
|
275
200
|
|
201
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
276
202
|
def update_incident(id, args)
|
277
|
-
incident
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
else
|
288
|
-
'Error updating incident'
|
289
|
-
end
|
290
|
-
else
|
291
|
-
'Can\'t update incident, does not exist'
|
292
|
-
end
|
203
|
+
return t('incident.not_found') unless incident(id)
|
204
|
+
|
205
|
+
api_args = {}
|
206
|
+
api_args['incident[status]'] = args['status'] if args.key?('status')
|
207
|
+
api_args['incident[wants_twitter_update]'] = args['twitter'] if args.key?('twitter')
|
208
|
+
api_args['incident[message]'] = args['message'] if args.key?('message')
|
209
|
+
api_args['incident[impact_override]'] = args['impact'] if args.key?('impact')
|
210
|
+
|
211
|
+
result = api_request('patch', "incidents/#{id}.json", api_args)
|
212
|
+
result ? t('incident.updated', id: id) : t('error.api_request')
|
293
213
|
end
|
214
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
294
215
|
|
295
216
|
def delete_incident(id)
|
296
217
|
incident = incident(id)
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
else
|
302
|
-
'Error deleting incident'
|
303
|
-
end
|
304
|
-
else
|
305
|
-
'Incident not found'
|
306
|
-
end
|
218
|
+
return t('incident.not_found') unless incident
|
219
|
+
|
220
|
+
result = api_request('delete', "incidents/#{id}.json")
|
221
|
+
result ? t('incident.deleted', id: id) : t('error.api_request')
|
307
222
|
end
|
308
223
|
|
309
224
|
def component(identifier)
|
310
225
|
components = api_request('get', 'components')
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
end
|
226
|
+
return unless components && components.count > 0
|
227
|
+
components.each do |component|
|
228
|
+
return component if component['id'] == identifier ||
|
229
|
+
component['name'] == identifier
|
316
230
|
end
|
317
231
|
end
|
318
232
|
|
319
233
|
def update_component(id, args)
|
320
234
|
component = component(id)
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
235
|
+
return t('component.not_found') unless component
|
236
|
+
|
237
|
+
result = api_request('patch', "components/#{id}.json", args)
|
238
|
+
result ? t('component.updated', id: id) : t('error.api_request')
|
239
|
+
end
|
240
|
+
|
241
|
+
def identify_component(args)
|
242
|
+
return nil unless args.key?('name') || args.key?('id')
|
243
|
+
|
244
|
+
if args.key?('id')
|
245
|
+
return args['id']
|
246
|
+
elsif args.key?('name')
|
247
|
+
component = component(args['name'])
|
248
|
+
return component['id']
|
330
249
|
end
|
331
250
|
end
|
332
251
|
|
@@ -363,9 +282,31 @@ module Lita
|
|
363
282
|
end
|
364
283
|
|
365
284
|
def valid_component_status?(status)
|
366
|
-
%w(operational
|
285
|
+
%w(operational
|
286
|
+
degraded_performance
|
287
|
+
partial_outage
|
288
|
+
major_outage).include?(status)
|
367
289
|
end
|
368
290
|
|
291
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
292
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
293
|
+
def valid_args?(args)
|
294
|
+
return false unless args.key?('name') || args.key?('id')
|
295
|
+
|
296
|
+
return false if args.key?('status') &&
|
297
|
+
!valid_incident_status?(args['status'])
|
298
|
+
|
299
|
+
return false if args.key?('twitter') &&
|
300
|
+
!valid_twitter_status?(args['twitter'])
|
301
|
+
|
302
|
+
return false if args.key?('impact') &&
|
303
|
+
!valid_impact_value?(args['impact'])
|
304
|
+
|
305
|
+
true
|
306
|
+
end
|
307
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
308
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
309
|
+
|
369
310
|
def parse_args(string)
|
370
311
|
results = {}
|
371
312
|
# TODO: Error handling on parse errors
|
@@ -378,30 +319,19 @@ module Lita
|
|
378
319
|
end
|
379
320
|
|
380
321
|
def api_request(method, component, args = {})
|
381
|
-
|
382
|
-
Lita.config.handlers.statuspage.page_id.nil?
|
383
|
-
Lita.logger.error('Missing API key or Page ID for Statuspage')
|
384
|
-
fail 'Missing config'
|
385
|
-
end
|
386
|
-
|
387
|
-
url = "https://api.statuspage.io/v1/pages/" \
|
388
|
-
"#{Lita.config.handlers.statuspage.page_id}" \
|
389
|
-
"/#{component}"
|
322
|
+
url = "https://api.statuspage.io/v1/pages/#{config.page_id}/#{component}"
|
390
323
|
|
391
324
|
http_response = http.send(method) do |req|
|
392
325
|
req.url url, args
|
393
|
-
req.headers['Authorization'] =
|
394
|
-
"OAuth #{Lita.config.handlers.statuspage.api_key}"
|
326
|
+
req.headers['Authorization'] = "OAuth #{config.api_key}"
|
395
327
|
end
|
396
328
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
else
|
401
|
-
Lita.logger.error("HTTP #{method} for #{url} with #{args} returned #{http_response.status}")
|
402
|
-
Lita.logger.error(http_response.body)
|
403
|
-
nil
|
329
|
+
unless http_response.status == 200 || http_response.status == 201
|
330
|
+
Lita.logger.error("#{method} for #{url} with #{args}: #{http_response.status}")
|
331
|
+
return nil
|
404
332
|
end
|
333
|
+
|
334
|
+
MultiJson.load(http_response.body)
|
405
335
|
end
|
406
336
|
end
|
407
337
|
|