lita-statuspage 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 +7 -0
- data/.gitignore +18 -0
- data/.rubocop.yml +17 -0
- data/.travis.yml +8 -0
- data/CONTRIBUTING.md +9 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/README.md +88 -0
- data/Rakefile +8 -0
- data/lib/lita-statuspage.rb +10 -0
- data/lib/lita/handlers/statuspage.rb +403 -0
- data/lita-statuspage.gemspec +26 -0
- data/locales/en.yml +4 -0
- data/spec/files/component_update.json +1 -0
- data/spec/files/components.json +1 -0
- data/spec/files/incident_deleted.json +1 -0
- data/spec/files/incident_new.json +1 -0
- data/spec/files/incident_updated.json +1 -0
- data/spec/files/incidents.json +1 -0
- data/spec/files/incidents_scheduled.json +1 -0
- data/spec/files/incidents_unresolved.json +1 -0
- data/spec/files/incidents_update.json +1 -0
- data/spec/lita/handlers/statuspage_spec.rb +358 -0
- data/spec/spec_helper.rb +10 -0
- metadata +191 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0f12e1170e61e7e7ad6e4b72fe16873083d2162f
|
4
|
+
data.tar.gz: 2dbfd05ac2b3370142a543fd0415a1852694db6d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c7a0db84d67ab9c655c0cf4a46a5dfd36d392beb76f59d72d57a615b0f13cfb8a9ffd3c3591933c896afd43254ca5b1570198897b87bf67f1bfce7e039edb643
|
7
|
+
data.tar.gz: 6ede61840a2aa080797894fbb7638fd4c30594a40375f1f1678c20864fc25fa4a8ff28580e77a2a5800e7403ea9cd7463b7950703caead04a4dd47c9cccd46c4
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Pull requests are awesome! Pull requests with tests are even more awesome!
|
2
|
+
|
3
|
+
## Quick steps
|
4
|
+
|
5
|
+
1. Fork the repo.
|
6
|
+
2. Run the tests: `bundle && rake`
|
7
|
+
3. Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, it needs a test!
|
8
|
+
4. Make the test pass.
|
9
|
+
5. Push to your fork and submit a pull request.
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2014 Eric Sigler
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# lita-statuspage
|
2
|
+
|
3
|
+
[](https://travis-ci.org/esigler/lita-statuspage)
|
4
|
+
[](https://codeclimate.com/github/esigler/lita-statuspage)
|
5
|
+
[](https://coveralls.io/r/esigler/lita-statuspage?branch=master)
|
6
|
+
|
7
|
+
Statuspage.io (http://statuspage.io) handler for updating incidents, service status, etc.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add lita-statuspage to your Lita instance's Gemfile:
|
12
|
+
|
13
|
+
``` ruby
|
14
|
+
gem "lita-statuspage"
|
15
|
+
```
|
16
|
+
|
17
|
+
## Configuration
|
18
|
+
|
19
|
+
You'll need to get an API key and your Page ID, instructions for how to do so are here:
|
20
|
+
http://doers.statuspage.io/api/authentication/
|
21
|
+
|
22
|
+
Add the following variable to your Lita config file:
|
23
|
+
|
24
|
+
``` ruby
|
25
|
+
config.handlers.statuspage.api_key = '_your_key_here_'
|
26
|
+
config.handlers.statuspage.page_id = '_your_page_id_here_'
|
27
|
+
```
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
### Incidents
|
32
|
+
|
33
|
+
#### Create
|
34
|
+
|
35
|
+
```
|
36
|
+
Lita statuspage incident new name:"<name>" - Create a new realtime incident
|
37
|
+
status:<status> - (Optional) One of: investigating|identified|monitoring|resolved (default: investigating)
|
38
|
+
message:"<message>" - (Optional) The initial message
|
39
|
+
twitter:<state> - (Optional) Post the new incident to Twitter, one of (true|t|false|f) (default:false)
|
40
|
+
impact:<state> - (Optional) Override calculated impact value, one of: (minor|major|critical)
|
41
|
+
```
|
42
|
+
|
43
|
+
#### Update
|
44
|
+
|
45
|
+
```
|
46
|
+
Lita statuspage incident update id:<id> - Update an incident
|
47
|
+
status:<status> - (Optional) One of (investigating|identified|monitoring|resolved) (if realtime) or (scheduled|in_progress|verifying|completed) (if scheduled)
|
48
|
+
message:"<message>" - (Optional) The body of the new incident update that will be created
|
49
|
+
twitter:<state> - (Optional) Post the new incident update to twitter, one of: (true|t|false|f) (default:false)
|
50
|
+
impact:<state> - (Optional) Override calculated impact value, one of (minor|major|critical)
|
51
|
+
```
|
52
|
+
|
53
|
+
**NOTE:** If either of status or message is modified, a new incident update will be generated. You should update both of these attributes at the same time to avoid two separate incident updates being generated.
|
54
|
+
|
55
|
+
#### List
|
56
|
+
|
57
|
+
```
|
58
|
+
Lita statuspage incident list all - List all incidents
|
59
|
+
Lita statuspage incident list scheduled - List scheduled incidents
|
60
|
+
Lita statuspage incident list unresolved - List unresolved incidents
|
61
|
+
```
|
62
|
+
|
63
|
+
#### Delete
|
64
|
+
|
65
|
+
```
|
66
|
+
Lita statuspage incident delete latest - Delete latest incident
|
67
|
+
Lita statuspage incident delete id:<id> - Delete a specific incident
|
68
|
+
```
|
69
|
+
|
70
|
+
|
71
|
+
### Components
|
72
|
+
|
73
|
+
#### List
|
74
|
+
|
75
|
+
```
|
76
|
+
Lita statuspage component list all - Lists all components
|
77
|
+
```
|
78
|
+
|
79
|
+
#### Update
|
80
|
+
|
81
|
+
```
|
82
|
+
Lita statuspage component update (id:<id>|name:"<name>") - Updates the component
|
83
|
+
status:<status> - One of (operational|degraded_performance|partial_outage|major_outage|none)
|
84
|
+
```
|
85
|
+
|
86
|
+
## License
|
87
|
+
|
88
|
+
[MIT](http://opensource.org/licenses/MIT)
|
data/Rakefile
ADDED
@@ -0,0 +1,403 @@
|
|
1
|
+
module Lita
|
2
|
+
module Handlers
|
3
|
+
class Statuspage < Handler
|
4
|
+
route(
|
5
|
+
/^statuspage\sincident\snew\s(.+)$/,
|
6
|
+
:incident_new,
|
7
|
+
command: true,
|
8
|
+
help: {
|
9
|
+
'statuspage incident new (...)' => 'Create a new realtime incident'
|
10
|
+
}
|
11
|
+
)
|
12
|
+
|
13
|
+
route(
|
14
|
+
/^statuspage\sincident\supdate\s(.+)$/,
|
15
|
+
:incident_update,
|
16
|
+
command: true,
|
17
|
+
help: {
|
18
|
+
'statuspage incident update (...)' => 'Update an incident'
|
19
|
+
}
|
20
|
+
)
|
21
|
+
|
22
|
+
route(
|
23
|
+
/^statuspage\sincident\slist(\sall)?$/,
|
24
|
+
:incident_list_all,
|
25
|
+
command: true,
|
26
|
+
help: {
|
27
|
+
'statuspage incident list all' => 'List all incidents'
|
28
|
+
}
|
29
|
+
)
|
30
|
+
|
31
|
+
route(
|
32
|
+
/^statuspage\sincident\slist\sscheduled$/,
|
33
|
+
:incident_list_scheduled,
|
34
|
+
command: true,
|
35
|
+
help: {
|
36
|
+
'statuspage incident list scheduled' => 'List scheduled incidents'
|
37
|
+
}
|
38
|
+
)
|
39
|
+
|
40
|
+
route(
|
41
|
+
/^statuspage\sincident\slist\sunresolved$/,
|
42
|
+
:incident_list_unresolved,
|
43
|
+
command: true,
|
44
|
+
help: {
|
45
|
+
'statuspage incident list unresolved' => 'List unresolved incidents'
|
46
|
+
}
|
47
|
+
)
|
48
|
+
|
49
|
+
route(
|
50
|
+
/^statuspage\sincident\sdelete\slatest$/,
|
51
|
+
:incident_delete_latest,
|
52
|
+
command: true,
|
53
|
+
help: {
|
54
|
+
'statuspage incident delete latest' => 'Delete latest incident'
|
55
|
+
}
|
56
|
+
)
|
57
|
+
|
58
|
+
route(
|
59
|
+
/^statuspage\sincident\sdelete\sid:(\w+)$/,
|
60
|
+
:incident_delete,
|
61
|
+
command: true,
|
62
|
+
help: {
|
63
|
+
'statuspage incident delete id:<id>' => 'Delete a specific incident'
|
64
|
+
}
|
65
|
+
)
|
66
|
+
|
67
|
+
route(
|
68
|
+
/^statuspage\scomponent\slist(\sall)?$/,
|
69
|
+
:component_list,
|
70
|
+
command: true,
|
71
|
+
help: {
|
72
|
+
'statuspage component list' => 'Lists all components'
|
73
|
+
}
|
74
|
+
)
|
75
|
+
|
76
|
+
route(
|
77
|
+
/^statuspage\scomponent\supdate\s(.+)$/,
|
78
|
+
:component_update,
|
79
|
+
command: true,
|
80
|
+
help: {
|
81
|
+
'statuspage component update' => 'Updates the component'
|
82
|
+
}
|
83
|
+
)
|
84
|
+
|
85
|
+
def self.default_config(config)
|
86
|
+
config.api_key = nil
|
87
|
+
config.page_id = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
def incident_new(response)
|
91
|
+
args = parse_args(response.matches[0][0])
|
92
|
+
|
93
|
+
unless args.key?('name')
|
94
|
+
response.reply('Can\'t create incident, missing incident name')
|
95
|
+
return
|
96
|
+
end
|
97
|
+
|
98
|
+
if args.key?('status') && !valid_incident_status?(args['status'])
|
99
|
+
response.reply('Can\'t create incident, invalid incident state')
|
100
|
+
return
|
101
|
+
end
|
102
|
+
|
103
|
+
if args.key?('twitter') && !valid_twitter_status?(args['twitter'])
|
104
|
+
response.reply('Can\'t create incident, invalid twitter state')
|
105
|
+
return
|
106
|
+
end
|
107
|
+
|
108
|
+
if args.key?('impact') && !valid_impact_value?(args['impact'])
|
109
|
+
response.reply('Can\'t create incident, invalid impact value')
|
110
|
+
return
|
111
|
+
end
|
112
|
+
|
113
|
+
response.reply(create_incident(args))
|
114
|
+
end
|
115
|
+
|
116
|
+
def incident_update(response)
|
117
|
+
args = parse_args(response.matches[0][0])
|
118
|
+
|
119
|
+
unless args.key?('id')
|
120
|
+
response.reply('Can\'t update incident, missing incident ID')
|
121
|
+
return
|
122
|
+
end
|
123
|
+
|
124
|
+
if args.length < 2
|
125
|
+
response.reply('Can\'t update incident, nothing to update')
|
126
|
+
return
|
127
|
+
end
|
128
|
+
|
129
|
+
if args.key?('status') && !valid_incident_status?(args['status'])
|
130
|
+
response.reply('Can\'t update incident, invalid incident state')
|
131
|
+
return
|
132
|
+
end
|
133
|
+
|
134
|
+
if args.key?('twitter') && !valid_twitter_status?(args['twitter'])
|
135
|
+
response.reply('Can\'t update incident, invalid twitter state')
|
136
|
+
return
|
137
|
+
end
|
138
|
+
|
139
|
+
if args.key?('impact') && !valid_impact_value?(args['impact'])
|
140
|
+
response.reply('Can\'t update incident, invalid impact value')
|
141
|
+
return
|
142
|
+
end
|
143
|
+
|
144
|
+
response.reply(update_incident(args['id'], args))
|
145
|
+
end
|
146
|
+
|
147
|
+
def incident_list_all(response)
|
148
|
+
list_incidents('incidents.json').each do |msg|
|
149
|
+
response.reply(msg)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def incident_list_scheduled(response)
|
154
|
+
list_incidents('incidents/scheduled.json').each do |msg|
|
155
|
+
response.reply(msg)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def incident_list_unresolved(response)
|
160
|
+
list_incidents('incidents/unresolved.json').each do |msg|
|
161
|
+
response.reply(msg)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def incident_delete_latest(response)
|
166
|
+
incident = latest_incident
|
167
|
+
if incident
|
168
|
+
response.reply(delete_incident(incident['id']))
|
169
|
+
else
|
170
|
+
response.reply('No latest incident found')
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def incident_delete(response)
|
175
|
+
incident_id = response.matches[0][0]
|
176
|
+
response.reply(delete_incident(incident_id))
|
177
|
+
end
|
178
|
+
|
179
|
+
def component_list(response)
|
180
|
+
components = api_request('get', 'components')
|
181
|
+
if components
|
182
|
+
if components.count > 0
|
183
|
+
components.each do |component|
|
184
|
+
response.reply(format_component(component))
|
185
|
+
end
|
186
|
+
else
|
187
|
+
response.reply('No components to list')
|
188
|
+
end
|
189
|
+
else
|
190
|
+
response.reply('Error fetching components')
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def component_update(response)
|
195
|
+
args = parse_args(response.matches[0][0])
|
196
|
+
request_args = {}
|
197
|
+
if !args.key?('name') && !args.key?('id')
|
198
|
+
response.reply('Need an identifier for the component')
|
199
|
+
else
|
200
|
+
if args.key?('status')
|
201
|
+
if valid_component_status?(args['status'])
|
202
|
+
request_args['component[status]'] = args['status']
|
203
|
+
else
|
204
|
+
response.reply('Invalid status to use in updates')
|
205
|
+
return
|
206
|
+
end
|
207
|
+
else
|
208
|
+
request_args['component[status]='] = ''
|
209
|
+
end
|
210
|
+
|
211
|
+
if args.key?('id')
|
212
|
+
response.reply(update_component(args['id'], request_args))
|
213
|
+
elsif args.key?('name')
|
214
|
+
component = component(args['name'])
|
215
|
+
response.reply(update_component(component['id'], request_args))
|
216
|
+
else
|
217
|
+
response.reply('Need an identifier for the component')
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
def incident(id)
|
225
|
+
incidents = api_request('get', 'incidents')
|
226
|
+
if incidents && incidents.count > 0
|
227
|
+
incidents.each do |incident|
|
228
|
+
return incident if incident['id'] == id
|
229
|
+
end
|
230
|
+
end
|
231
|
+
nil
|
232
|
+
end
|
233
|
+
|
234
|
+
def latest_incident
|
235
|
+
incidents = api_request('get', 'incidents')
|
236
|
+
return nil unless incidents && incidents.count > 0
|
237
|
+
incidents.first
|
238
|
+
end
|
239
|
+
|
240
|
+
def list_incidents(resource)
|
241
|
+
incidents = api_request('get', resource)
|
242
|
+
response = []
|
243
|
+
if incidents
|
244
|
+
response = ['No incidents to list'] unless incidents.count > 0
|
245
|
+
incidents.each do |incident|
|
246
|
+
response.push("#{format_incident(incident)}")
|
247
|
+
end
|
248
|
+
else
|
249
|
+
response = ['Error fetching incidents']
|
250
|
+
end
|
251
|
+
response
|
252
|
+
end
|
253
|
+
|
254
|
+
def create_incident(args)
|
255
|
+
request_args = {}
|
256
|
+
request_args['incident[name]'] = args['name']
|
257
|
+
request_args['incident[status]'] = args['status'] if args.key?('status')
|
258
|
+
request_args['incident[wants_twitter_update]'] = args['twitter'] if args.key?('twitter')
|
259
|
+
request_args['incident[message]'] = args['message'] if args.key?('message')
|
260
|
+
request_args['incident[impact_override]'] = args['impact'] if args.key?('impact')
|
261
|
+
result = api_request('post', 'incidents.json', request_args)
|
262
|
+
if result
|
263
|
+
"Incident #{result['id']} created"
|
264
|
+
else
|
265
|
+
'Error creating incident'
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def update_incident(id, args)
|
270
|
+
incident = incident(id)
|
271
|
+
if incident
|
272
|
+
request_args = {}
|
273
|
+
request_args['incident[status]'] = args['status'] if args.key?('status')
|
274
|
+
request_args['incident[wants_twitter_update]'] = args['twitter'] if args.key?('twitter')
|
275
|
+
request_args['incident[message]'] = args['message'] if args.key?('message')
|
276
|
+
request_args['incident[impact_override]'] = args['impact'] if args.key?('impact')
|
277
|
+
result = api_request('patch', "incidents/#{id}.json", request_args)
|
278
|
+
if result
|
279
|
+
"Incident #{id} updated"
|
280
|
+
else
|
281
|
+
'Error updating incident'
|
282
|
+
end
|
283
|
+
else
|
284
|
+
'Can\'t update incident, does not exist'
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def delete_incident(id)
|
289
|
+
incident = incident(id)
|
290
|
+
if incident
|
291
|
+
result = api_request('delete', "incidents/#{id}.json")
|
292
|
+
if result
|
293
|
+
"Incident #{id} deleted"
|
294
|
+
else
|
295
|
+
'Error deleting incident'
|
296
|
+
end
|
297
|
+
else
|
298
|
+
'Incident not found'
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def component(identifier)
|
303
|
+
components = api_request('get', 'components')
|
304
|
+
if components && components.count > 0
|
305
|
+
components.each do |component|
|
306
|
+
return component if component['id'] == identifier ||
|
307
|
+
component['name'] == identifier
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def update_component(id, args)
|
313
|
+
component = component(id)
|
314
|
+
if component
|
315
|
+
result = api_request('patch', "components/#{id}.json", args)
|
316
|
+
if result
|
317
|
+
"Component #{id} updated"
|
318
|
+
else
|
319
|
+
'Error updating component'
|
320
|
+
end
|
321
|
+
else
|
322
|
+
'Component not found'
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def format_incident(incident)
|
327
|
+
name = incident['name']
|
328
|
+
id = incident['id']
|
329
|
+
status = incident['status']
|
330
|
+
created = Date.parse(incident['created_at'])
|
331
|
+
"#{name} (" \
|
332
|
+
"created: #{created.strftime('%Y-%m-%d')}, " \
|
333
|
+
"status: #{status}, " \
|
334
|
+
"id:#{id})"
|
335
|
+
end
|
336
|
+
|
337
|
+
def format_component(component)
|
338
|
+
name = component['name']
|
339
|
+
id = component['id']
|
340
|
+
status = component['status']
|
341
|
+
"#{name} (" \
|
342
|
+
"status: #{status}, " \
|
343
|
+
"id:#{id})"
|
344
|
+
end
|
345
|
+
|
346
|
+
def valid_incident_status?(status)
|
347
|
+
%w(investigating identified monitoring resolved).include?(status)
|
348
|
+
end
|
349
|
+
|
350
|
+
def valid_twitter_status?(status)
|
351
|
+
%w(true t false f).include?(status)
|
352
|
+
end
|
353
|
+
|
354
|
+
def valid_impact_value?(value)
|
355
|
+
%w(minor major critical).include?(value)
|
356
|
+
end
|
357
|
+
|
358
|
+
def valid_component_status?(status)
|
359
|
+
%w(operational degraded_performance partial_outage major_outage).include?(status)
|
360
|
+
end
|
361
|
+
|
362
|
+
def parse_args(string)
|
363
|
+
results = {}
|
364
|
+
# TODO: Error handling on parse errors
|
365
|
+
arg_pairs = Shellwords.split(string)
|
366
|
+
arg_pairs.each do |pair|
|
367
|
+
keyval = pair.split(':', 2)
|
368
|
+
results[keyval[0]] = keyval[1]
|
369
|
+
end
|
370
|
+
results
|
371
|
+
end
|
372
|
+
|
373
|
+
def api_request(method, component, args = {})
|
374
|
+
if Lita.config.handlers.statuspage.api_key.nil? ||
|
375
|
+
Lita.config.handlers.statuspage.page_id.nil?
|
376
|
+
Lita.logger.error('Missing API key or Page ID for Statuspage')
|
377
|
+
fail 'Missing config'
|
378
|
+
end
|
379
|
+
|
380
|
+
url = "https://api.statuspage.io/v1/pages/" \
|
381
|
+
"#{Lita.config.handlers.statuspage.page_id}" \
|
382
|
+
"/#{component}"
|
383
|
+
|
384
|
+
http_response = http.send(method) do |req|
|
385
|
+
req.url url, args
|
386
|
+
req.headers['Authorization'] =
|
387
|
+
"OAuth #{Lita.config.handlers.statuspage.api_key}"
|
388
|
+
end
|
389
|
+
|
390
|
+
if http_response.status == 200 ||
|
391
|
+
http_response.status == 201
|
392
|
+
MultiJson.load(http_response.body)
|
393
|
+
else
|
394
|
+
Lita.logger.error("HTTP #{method} for #{url} with #{args} returned #{http_response.status}")
|
395
|
+
Lita.logger.error(http_response.body)
|
396
|
+
nil
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
Lita.register_handler(Statuspage)
|
402
|
+
end
|
403
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = 'lita-statuspage'
|
3
|
+
spec.version = '0.1.0'
|
4
|
+
spec.authors = ['Eric Sigler']
|
5
|
+
spec.email = ['me@esigler.com']
|
6
|
+
spec.description = %q{A Lita handler to interact with Statuspage.io}
|
7
|
+
spec.summary = %q{A Lita handler to interact with Statuspage.io}
|
8
|
+
spec.homepage = 'https://github.com/esigler/lita-statuspage'
|
9
|
+
spec.license = 'MIT'
|
10
|
+
spec.metadata = { 'lita_plugin_type' => 'handler' }
|
11
|
+
|
12
|
+
spec.files = `git ls-files`.split($/)
|
13
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
14
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
15
|
+
spec.require_paths = ['lib']
|
16
|
+
|
17
|
+
spec.add_runtime_dependency 'lita', '>= 3.0'
|
18
|
+
spec.add_runtime_dependency 'multi_json'
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
21
|
+
spec.add_development_dependency 'rake'
|
22
|
+
spec.add_development_dependency 'rspec', '>= 3.0.0.beta2'
|
23
|
+
spec.add_development_dependency 'simplecov'
|
24
|
+
spec.add_development_dependency 'coveralls'
|
25
|
+
spec.add_development_dependency 'rubocop'
|
26
|
+
end
|
data/locales/en.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"status":"major_outage","name":"Management Portal (example)","created_at":"2014-03-23T18:11:33.099Z","updated_at":"2014-03-31T01:43:50.931Z","position":2,"description":null,"id":"v6z6tpldcw85","page_id":"g229z91sc3ff"}
|
@@ -0,0 +1 @@
|
|
1
|
+
[{"status":"operational","name":"API (example)","created_at":"2014-03-23T18:11:33.082Z","updated_at":"2014-03-23T18:11:33.082Z","position":1,"description":null,"id":"rdfbrztshlr2","page_id":"g229z91sc3ff"},{"status":"operational","name":"Management Portal (example)","created_at":"2014-03-23T18:11:33.099Z","updated_at":"2014-03-23T18:11:33.099Z","position":2,"description":null,"id":"v6z6tpldcw85","page_id":"g229z91sc3ff"}]
|
@@ -0,0 +1 @@
|
|
1
|
+
{"name":"Unresolved incident","status":"investigating","created_at":"2014-03-30T22:47:14.362Z","updated_at":"2014-03-30T22:47:15.718Z","monitoring_at":null,"resolved_at":null,"impact":"none","shortlink":"http://stspg.io/MUB","postmortem_ignored":false,"postmortem_body":null,"postmortem_body_last_updated_at":null,"postmortem_published_at":null,"postmortem_notified_subscribers":false,"postmortem_notified_twitter":false,"backfilled":false,"scheduled_for":null,"scheduled_until":null,"scheduled_remind_prior":false,"scheduled_reminded_at":null,"impact_override":null,"scheduled_auto_in_progress":false,"scheduled_auto_completed":false,"id":"2ttv50n0n8zj","page_id":"g229z91sc3ff","incident_updates":[]}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"name":"lp0 on fire","status":"investigating","created_at":"2014-03-31T23:39:43.169Z","updated_at":"2014-03-31T23:39:44.397Z","monitoring_at":null,"resolved_at":null,"impact":"none","shortlink":"http://stspg.io/MZJ","postmortem_ignored":false,"postmortem_body":null,"postmortem_body_last_updated_at":null,"postmortem_published_at":null,"postmortem_notified_subscribers":false,"postmortem_notified_twitter":false,"backfilled":false,"scheduled_for":null,"scheduled_until":null,"scheduled_remind_prior":false,"scheduled_reminded_at":null,"impact_override":null,"scheduled_auto_in_progress":false,"scheduled_auto_completed":false,"id":"b0m7dz4tzpl3","page_id":"g229z91sc3ff","incident_updates":[{"status":"investigating","body":"We are currently investigating this issue.","created_at":"2014-03-31T23:39:44.395Z","wants_twitter_update":false,"twitter_updated_at":null,"updated_at":"2014-03-31T23:39:44.395Z","display_at":"2014-03-31T23:39:44.395Z","id":"gc9bndsygg42","incident_id":"b0m7dz4tzpl3"}]}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"name":"lp0 on fire","status":"investigating","created_at":"2014-03-31T23:39:43.169Z","updated_at":"2014-04-01T00:16:11.095Z","monitoring_at":null,"resolved_at":null,"impact":"none","shortlink":"http://stspg.io/MZJ","postmortem_ignored":false,"postmortem_body":null,"postmortem_body_last_updated_at":null,"postmortem_published_at":null,"postmortem_notified_subscribers":false,"postmortem_notified_twitter":false,"backfilled":false,"scheduled_for":null,"scheduled_until":null,"scheduled_remind_prior":false,"scheduled_reminded_at":null,"impact_override":null,"scheduled_auto_in_progress":false,"scheduled_auto_completed":false,"id":"b0m7dz4tzpl3","page_id":"g229z91sc3ff","incident_updates":[{"status":"investigating","body":"Howdy","created_at":"2014-04-01T00:16:11.084Z","wants_twitter_update":false,"twitter_updated_at":null,"updated_at":"2014-04-01T00:16:11.084Z","display_at":"2014-04-01T00:16:11.084Z","id":"kxbqvtqxdl6m","incident_id":"b0m7dz4tzpl3"},{"status":"investigating","body":"We are currently investigating this issue.","created_at":"2014-03-31T23:39:44.395Z","wants_twitter_update":false,"twitter_updated_at":null,"updated_at":"2014-03-31T23:39:44.395Z","display_at":"2014-03-31T23:39:44.395Z","id":"gc9bndsygg42","incident_id":"b0m7dz4tzpl3"}]}
|
@@ -0,0 +1 @@
|
|
1
|
+
[{"name":"Test Incident","status":"resolved","created_at":"2014-03-24T23:01:40.312Z","updated_at":"2014-03-24T23:01:53.944Z","monitoring_at":null,"resolved_at":"2014-03-24T23:01:41.529Z","impact":"none","shortlink":"http://stspg.io/M1A","postmortem_ignored":true,"postmortem_body":null,"postmortem_body_last_updated_at":null,"postmortem_published_at":null,"postmortem_notified_subscribers":false,"postmortem_notified_twitter":false,"backfilled":false,"scheduled_for":null,"scheduled_until":null,"scheduled_remind_prior":false,"scheduled_reminded_at":null,"impact_override":null,"scheduled_auto_in_progress":false,"scheduled_auto_completed":false,"id":"td9ftgzcyz4m","page_id":"g229z91sc3ff","incident_updates":[{"status":"resolved","body":"Just checking!","created_at":"2014-03-24T23:01:41.529Z","wants_twitter_update":false,"twitter_updated_at":null,"updated_at":"2014-03-24T23:01:41.529Z","display_at":"2014-03-24T23:01:41.529Z","id":"c0n0qt5rmct9","incident_id":"td9ftgzcyz4m"}]}]
|
@@ -0,0 +1 @@
|
|
1
|
+
[{"name":"Test Maintenance","status":"scheduled","created_at":"2014-03-30T22:44:33.573Z","updated_at":"2014-03-30T22:44:34.927Z","monitoring_at":null,"resolved_at":null,"impact":"none","shortlink":"http://stspg.io/MU9","postmortem_ignored":true,"postmortem_body":null,"postmortem_body_last_updated_at":null,"postmortem_published_at":null,"postmortem_notified_subscribers":false,"postmortem_notified_twitter":false,"backfilled":false,"scheduled_for":"2014-03-31T00:00:00.000Z","scheduled_until":"2014-04-01T00:00:00.000Z","scheduled_remind_prior":false,"scheduled_reminded_at":null,"impact_override":null,"scheduled_auto_in_progress":false,"scheduled_auto_completed":false,"id":"3tzsm37ryws0","page_id":"g229z91sc3ff","incident_updates":[{"status":"scheduled","body":"Some details","created_at":"2014-03-30T22:44:34.926Z","wants_twitter_update":false,"twitter_updated_at":null,"updated_at":"2014-03-30T22:44:34.926Z","display_at":"2014-03-30T22:44:34.926Z","id":"cb1wstkgn1zh","incident_id":"3tzsm37ryws0"}]}]
|
@@ -0,0 +1 @@
|
|
1
|
+
[{"name":"Unresolved incident","status":"investigating","created_at":"2014-03-30T22:47:14.362Z","updated_at":"2014-03-30T22:47:15.718Z","monitoring_at":null,"resolved_at":null,"impact":"none","shortlink":"http://stspg.io/MUB","postmortem_ignored":false,"postmortem_body":null,"postmortem_body_last_updated_at":null,"postmortem_published_at":null,"postmortem_notified_subscribers":false,"postmortem_notified_twitter":false,"backfilled":false,"scheduled_for":null,"scheduled_until":null,"scheduled_remind_prior":false,"scheduled_reminded_at":null,"impact_override":null,"scheduled_auto_in_progress":false,"scheduled_auto_completed":false,"id":"2ttv50n0n8zj","page_id":"g229z91sc3ff","incident_updates":[{"status":"investigating","body":"The server is on fire.","created_at":"2014-03-30T22:47:15.716Z","wants_twitter_update":false,"twitter_updated_at":null,"updated_at":"2014-03-30T22:47:15.716Z","display_at":"2014-03-30T22:47:15.716Z","id":"s913j9324v4t","incident_id":"2ttv50n0n8zj"}]}]
|
@@ -0,0 +1 @@
|
|
1
|
+
[{"name":"lp0 on fire","status":"investigating","created_at":"2014-03-31T23:39:43.169Z","updated_at":"2014-03-31T23:39:44.397Z","monitoring_at":null,"resolved_at":null,"impact":"none","shortlink":"http://stspg.io/MZJ","postmortem_ignored":false,"postmortem_body":null,"postmortem_body_last_updated_at":null,"postmortem_published_at":null,"postmortem_notified_subscribers":false,"postmortem_notified_twitter":false,"backfilled":false,"scheduled_for":null,"scheduled_until":null,"scheduled_remind_prior":false,"scheduled_reminded_at":null,"impact_override":null,"scheduled_auto_in_progress":false,"scheduled_auto_completed":false,"id":"b0m7dz4tzpl3","page_id":"g229z91sc3ff","incident_updates":[{"status":"investigating","body":"We are currently investigating this issue.","created_at":"2014-03-31T23:39:44.395Z","wants_twitter_update":false,"twitter_updated_at":null,"updated_at":"2014-03-31T23:39:44.395Z","display_at":"2014-03-31T23:39:44.395Z","id":"gc9bndsygg42","incident_id":"b0m7dz4tzpl3"}]}]
|
@@ -0,0 +1,358 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Lita::Handlers::Statuspage, lita_handler: true do
|
4
|
+
let(:incidents) do
|
5
|
+
File.read('spec/files/incidents.json')
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:incidents_empty) do
|
9
|
+
'[]'
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:incidents_scheduled) do
|
13
|
+
File.read('spec/files/incidents_scheduled.json')
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:incidents_unresolved) do
|
17
|
+
File.read('spec/files/incidents_unresolved.json')
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:incidents_updated) do
|
21
|
+
File.read('spec/files/incidents_update.json')
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:incident_new) do
|
25
|
+
File.read('spec/files/incident_new.json')
|
26
|
+
end
|
27
|
+
|
28
|
+
let(:incident_deleted) do
|
29
|
+
File.read('spec/files/incident_deleted.json')
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:incident_updated) do
|
33
|
+
File.read('spec/files/incident_updated.json')
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:components) do
|
37
|
+
File.read('spec/files/components.json')
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:components_empty) do
|
41
|
+
'[]'
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:component_update) do
|
45
|
+
File.read('spec/files/component_update.json')
|
46
|
+
end
|
47
|
+
|
48
|
+
it { routes_command('statuspage incident new name:"foo"').to(:incident_new) }
|
49
|
+
it { routes_command('statuspage incident update latest').to(:incident_update) }
|
50
|
+
it { routes_command('statuspage incident list').to(:incident_list_all) }
|
51
|
+
it { routes_command('statuspage incident list all').to(:incident_list_all) }
|
52
|
+
it { routes_command('statuspage incident list scheduled').to(:incident_list_scheduled) }
|
53
|
+
it { routes_command('statuspage incident list unresolved').to(:incident_list_unresolved) }
|
54
|
+
it { routes_command('statuspage incident delete latest').to(:incident_delete_latest) }
|
55
|
+
it { routes_command('statuspage incident delete id:omgwtfbbq').to(:incident_delete) }
|
56
|
+
it { routes_command('statuspage component list').to(:component_list) }
|
57
|
+
it { routes_command('statuspage component list all').to(:component_list) }
|
58
|
+
it { routes_command('statuspage component update latest').to(:component_update) }
|
59
|
+
|
60
|
+
describe '.default_config' do
|
61
|
+
it 'sets api_key to nil' do
|
62
|
+
expect(Lita.config.handlers.statuspage.api_key).to be_nil
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'sets page_id to nil' do
|
66
|
+
expect(Lita.config.handlers.statuspage.page_id).to be_nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'without valid config' do
|
71
|
+
it 'should error out on any command' do
|
72
|
+
expect { send_command('statuspage incident list all') }.to raise_error('Missing config')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'with valid config' do
|
77
|
+
before do
|
78
|
+
Lita.config.handlers.statuspage.api_key = 'foo'
|
79
|
+
Lita.config.handlers.statuspage.page_id = 'bar'
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#incident_new' do
|
83
|
+
it 'shows an ack when the incident is created' do
|
84
|
+
response = double('Faraday::Response', status: 201, body: incident_new)
|
85
|
+
allow_any_instance_of(Faraday::Connection).to receive(:post).and_return(response)
|
86
|
+
send_command('statuspage incident new name:"lp0 on fire"')
|
87
|
+
expect(replies.last).to eq('Incident b0m7dz4tzpl3 created')
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'shows a warning if the incident does not have a required name' do
|
91
|
+
send_command('statuspage incident new status:investigating')
|
92
|
+
expect(replies.last).to eq('Can\'t create incident, missing incident name')
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'shows a warning if the incident status is not valid' do
|
96
|
+
send_command('statuspage incident new name:"It dun broke" status:ignoring')
|
97
|
+
expect(replies.last).to eq('Can\'t create incident, invalid incident state')
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'shows a warning if the twitter status is not valid' do
|
101
|
+
send_command('statuspage incident new name:"It dun broke" twitter:lavender')
|
102
|
+
expect(replies.last).to eq('Can\'t create incident, invalid twitter state')
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'shows a warning if the impact value is not valid' do
|
106
|
+
send_command('statuspage incident new name:"It dun broke" impact:apocalypse')
|
107
|
+
expect(replies.last).to eq('Can\'t create incident, invalid impact value')
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'shows an error if there was an issue creating the incident' do
|
111
|
+
response = double('Faraday::Response', status: 500, body: '')
|
112
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
113
|
+
send_command('statuspage incident new name:"It dun broke"')
|
114
|
+
expect(replies.last).to eq('Error creating incident')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#incident_update' do
|
119
|
+
it 'shows an ack when the incident is updated' do
|
120
|
+
get_response = double('Faraday::Response', status: 200, body: incidents_updated)
|
121
|
+
patch_response = double('Faraday::Response', status: 200, body: incident_updated)
|
122
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(get_response)
|
123
|
+
allow_any_instance_of(Faraday::Connection).to receive(:patch).and_return(patch_response)
|
124
|
+
send_command('statuspage incident update id:b0m7dz4tzpl3 message:"Howdy"')
|
125
|
+
expect(replies.last).to eq('Incident b0m7dz4tzpl3 updated')
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'shows a warning if the incident does not exist' do
|
129
|
+
response = double('Faraday::Response', status: 200, body: incidents)
|
130
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
131
|
+
send_command('statuspage incident update id:b0m7dz4tzpl3 message:"Howdy"')
|
132
|
+
expect(replies.last).to eq('Can\'t update incident, does not exist')
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'shows a warning if there is nothing to update' do
|
136
|
+
send_command('statuspage incident update id:b0m7dz4tzpl3')
|
137
|
+
expect(replies.last).to eq('Can\'t update incident, nothing to update')
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'shows a warning if the incident does not have an id' do
|
141
|
+
send_command('statuspage incident update status:investigating')
|
142
|
+
expect(replies.last).to eq('Can\'t update incident, missing incident ID')
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'shows a warning if the incident status is not valid' do
|
146
|
+
send_command('statuspage incident update id:b0m7dz4tzpl3 status:running_away')
|
147
|
+
expect(replies.last).to eq('Can\'t update incident, invalid incident state')
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'shows a warning if the twitter status is not valid' do
|
151
|
+
send_command('statuspage incident update id:b0m7dz4tzpl3 twitter:magenta')
|
152
|
+
expect(replies.last).to eq('Can\'t update incident, invalid twitter state')
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'shows a warning if the impact value is not valid' do
|
156
|
+
send_command('statuspage incident update id:b0m7dz4tzpl3 impact:ragnarok')
|
157
|
+
expect(replies.last).to eq('Can\'t update incident, invalid impact value')
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'shows an error if there was an issue updating the incident' do
|
161
|
+
get_response = double('Faraday::Response', status: 200, body: incidents_updated)
|
162
|
+
patch_response = double('Faraday::Response', status: 500, body: '')
|
163
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(get_response)
|
164
|
+
allow_any_instance_of(Faraday::Connection).to receive(:patch).and_return(patch_response)
|
165
|
+
send_command('statuspage incident update id:b0m7dz4tzpl3 message:"Howdy"')
|
166
|
+
expect(replies.last).to eq('Error updating incident')
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '#incident_list_all' do
|
171
|
+
it 'shows a list of incidents if there are any' do
|
172
|
+
response = double('Faraday::Response', status: 200, body: incidents)
|
173
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
174
|
+
send_command('statuspage incident list all')
|
175
|
+
expect(replies.last).to eq('Test Incident (created: 2014-03-24, ' \
|
176
|
+
'status: resolved, id:td9ftgzcyz4m)')
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'shows a warning if there arent any' do
|
180
|
+
response = double('Faraday::Response', status: 200, body: incidents_empty)
|
181
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
182
|
+
send_command('statuspage incident list all')
|
183
|
+
expect(replies.last).to eq('No incidents to list')
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'shows an error if there was an issue fetching the incidents' do
|
187
|
+
response = double('Faraday::Response', status: 500, body: '')
|
188
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
189
|
+
send_command('statuspage incident list all')
|
190
|
+
expect(replies.last).to eq('Error fetching incidents')
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe '#incident_list_scheduled' do
|
195
|
+
it 'shows a list of incidents if there are any' do
|
196
|
+
response = double('Faraday::Response', status: 200, body: incidents_scheduled)
|
197
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
198
|
+
send_command('statuspage incident list scheduled')
|
199
|
+
expect(replies.last).to eq('Test Maintenance (created: 2014-03-30, ' \
|
200
|
+
'status: scheduled, id:3tzsm37ryws0)')
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'shows a warning if there arent any' do
|
204
|
+
response = double('Faraday::Response', status: 200, body: incidents_empty)
|
205
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
206
|
+
send_command('statuspage incident list scheduled')
|
207
|
+
expect(replies.last).to eq('No incidents to list')
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'shows an error if there was an issue fetching the incidents' do
|
211
|
+
response = double('Faraday::Response', status: 500, body: '')
|
212
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
213
|
+
send_command('statuspage incident list scheduled')
|
214
|
+
expect(replies.last).to eq('Error fetching incidents')
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe '#incident_list_unresolved' do
|
219
|
+
it 'shows a list of incidents if there are any' do
|
220
|
+
response = double('Faraday::Response', status: 200, body: incidents_unresolved)
|
221
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
222
|
+
send_command('statuspage incident list unresolved')
|
223
|
+
expect(replies.last).to eq('Unresolved incident (created: 2014-03-30, ' \
|
224
|
+
'status: investigating, id:2ttv50n0n8zj)')
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'shows a warning if there arent any' do
|
228
|
+
response = double('Faraday::Response', status: 200, body: incidents_empty)
|
229
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
230
|
+
send_command('statuspage incident list scheduled')
|
231
|
+
expect(replies.last).to eq('No incidents to list')
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'shows an error if there was an issue fetching the incidents' do
|
235
|
+
response = double('Faraday::Response', status: 500, body: '')
|
236
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
237
|
+
send_command('statuspage incident list scheduled')
|
238
|
+
expect(replies.last).to eq('Error fetching incidents')
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
describe '#incident_delete_latest' do
|
243
|
+
it 'shows an ack if the incident was deleted' do
|
244
|
+
get_response = double('Faraday::Response', status: 200, body: incidents_unresolved)
|
245
|
+
delete_response = double('Faraday::Response', status: 200, body: incident_deleted)
|
246
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(get_response)
|
247
|
+
allow_any_instance_of(Faraday::Connection).to receive(:delete).and_return(delete_response)
|
248
|
+
send_command('statuspage incident delete latest')
|
249
|
+
expect(replies.last).to eq('Incident 2ttv50n0n8zj deleted')
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'shows a warning if there wasnt an incident to delete' do
|
253
|
+
response = double('Faraday::Response', status: 404, body: '')
|
254
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
255
|
+
send_command('statuspage incident delete latest')
|
256
|
+
expect(replies.last).to eq('No latest incident found')
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'shows an error if there was an issue deleting the incident' do
|
260
|
+
get_response = double('Faraday::Response', status: 200, body: incidents_unresolved)
|
261
|
+
delete_response = double('Faraday::Response', status: 500, body: '')
|
262
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(get_response)
|
263
|
+
allow_any_instance_of(Faraday::Connection).to receive(:delete).and_return(delete_response)
|
264
|
+
send_command('statuspage incident delete latest')
|
265
|
+
expect(replies.last).to eq('Error deleting incident')
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe '#incident_delete' do
|
270
|
+
it 'shows an ack if the incident was deleted' do
|
271
|
+
get_response = double('Faraday::Response', status: 200, body: incidents_unresolved)
|
272
|
+
delete_response = double('Faraday::Response', status: 200, body: incident_deleted)
|
273
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(get_response)
|
274
|
+
allow_any_instance_of(Faraday::Connection).to receive(:delete).and_return(delete_response)
|
275
|
+
send_command('statuspage incident delete id:2ttv50n0n8zj')
|
276
|
+
expect(replies.last).to eq('Incident 2ttv50n0n8zj deleted')
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'shows a warning if there wasnt an incident to delete' do
|
280
|
+
response = double('Faraday::Response', status: 404, body: '')
|
281
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
282
|
+
send_command('statuspage incident delete id:2ttv50n0n8zj')
|
283
|
+
expect(replies.last).to eq('Incident not found')
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'shows an error if there was an issue deleting the incident' do
|
287
|
+
get_response = double('Faraday::Response', status: 200, body: incidents_unresolved)
|
288
|
+
delete_response = double('Faraday::Response', status: 500, body: '')
|
289
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(get_response)
|
290
|
+
allow_any_instance_of(Faraday::Connection).to receive(:delete).and_return(delete_response)
|
291
|
+
send_command('statuspage incident delete id:2ttv50n0n8zj')
|
292
|
+
expect(replies.last).to eq('Error deleting incident')
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe '#component_list' do
|
297
|
+
it 'shows a list of components if there are any' do
|
298
|
+
response = double('Faraday::Response', status: 200, body: components)
|
299
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
300
|
+
send_command('statuspage component list')
|
301
|
+
expect(replies.last).to eq('Management Portal (example) (status: operational, id:v6z6tpldcw85)')
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'shows a warning if there arent any' do
|
305
|
+
response = double('Faraday::Response', status: 200, body: components_empty)
|
306
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
307
|
+
send_command('statuspage component list')
|
308
|
+
expect(replies.last).to eq('No components to list')
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'shows an error if there was an issue fetching the components' do
|
312
|
+
response = double('Faraday::Response', status: 500, body: '')
|
313
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(response)
|
314
|
+
send_command('statuspage component list')
|
315
|
+
expect(replies.last).to eq('Error fetching components')
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
describe '#component_update' do
|
320
|
+
it 'shows an ack if the component is updated via id' do
|
321
|
+
get_response = double('Faraday::Response', status: 200, body: components)
|
322
|
+
patch_response = double('Faraday::Response', status: 200, body: component_update)
|
323
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(get_response)
|
324
|
+
allow_any_instance_of(Faraday::Connection).to receive(:patch).and_return(patch_response)
|
325
|
+
send_command('statuspage component update id:v6z6tpldcw85 status:major_outage')
|
326
|
+
expect(replies.last).to eq('Component v6z6tpldcw85 updated')
|
327
|
+
end
|
328
|
+
|
329
|
+
it 'shows an ack if the component is updated via name' do
|
330
|
+
get_response = double('Faraday::Response', status: 200, body: components)
|
331
|
+
patch_response = double('Faraday::Response', status: 200, body: component_update)
|
332
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(get_response)
|
333
|
+
allow_any_instance_of(Faraday::Connection).to receive(:patch).and_return(patch_response)
|
334
|
+
send_command('statuspage component update name:"Management Portal (example)" status:major_outage')
|
335
|
+
expect(replies.last).to eq('Component v6z6tpldcw85 updated')
|
336
|
+
end
|
337
|
+
|
338
|
+
it 'shows a warning if there is no identifier to the component' do
|
339
|
+
send_command('statuspage component update status:major_outage')
|
340
|
+
expect(replies.last).to eq('Need an identifier for the component')
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'shows a warning if the status is invalid' do
|
344
|
+
send_command('statuspage component update id:v6z6tpldcw85 status:big_problem')
|
345
|
+
expect(replies.last).to eq('Invalid status to use in updates')
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'shows an error if there was an issue updating the component' do
|
349
|
+
get_response = double('Faraday::Response', status: 200, body: components)
|
350
|
+
patch_response = double('Faraday::Response', status: 500, body: '')
|
351
|
+
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(get_response)
|
352
|
+
allow_any_instance_of(Faraday::Connection).to receive(:patch).and_return(patch_response)
|
353
|
+
send_command('statuspage component update id:v6z6tpldcw85 status:major_outage')
|
354
|
+
expect(replies.last).to eq('Error updating component')
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
4
|
+
SimpleCov::Formatter::HTMLFormatter,
|
5
|
+
Coveralls::SimpleCov::Formatter
|
6
|
+
]
|
7
|
+
SimpleCov.start { add_filter '/spec/' }
|
8
|
+
|
9
|
+
require 'lita-statuspage'
|
10
|
+
require 'lita/rspec'
|
metadata
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lita-statuspage
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eric Sigler
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: lita
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: multi_json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.0.0.beta2
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.0.0.beta2
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: coveralls
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: A Lita handler to interact with Statuspage.io
|
126
|
+
email:
|
127
|
+
- me@esigler.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".rubocop.yml"
|
134
|
+
- ".travis.yml"
|
135
|
+
- CONTRIBUTING.md
|
136
|
+
- Gemfile
|
137
|
+
- LICENSE
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- lib/lita-statuspage.rb
|
141
|
+
- lib/lita/handlers/statuspage.rb
|
142
|
+
- lita-statuspage.gemspec
|
143
|
+
- locales/en.yml
|
144
|
+
- spec/files/component_update.json
|
145
|
+
- spec/files/components.json
|
146
|
+
- spec/files/incident_deleted.json
|
147
|
+
- spec/files/incident_new.json
|
148
|
+
- spec/files/incident_updated.json
|
149
|
+
- spec/files/incidents.json
|
150
|
+
- spec/files/incidents_scheduled.json
|
151
|
+
- spec/files/incidents_unresolved.json
|
152
|
+
- spec/files/incidents_update.json
|
153
|
+
- spec/lita/handlers/statuspage_spec.rb
|
154
|
+
- spec/spec_helper.rb
|
155
|
+
homepage: https://github.com/esigler/lita-statuspage
|
156
|
+
licenses:
|
157
|
+
- MIT
|
158
|
+
metadata:
|
159
|
+
lita_plugin_type: handler
|
160
|
+
post_install_message:
|
161
|
+
rdoc_options: []
|
162
|
+
require_paths:
|
163
|
+
- lib
|
164
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
requirements: []
|
175
|
+
rubyforge_project:
|
176
|
+
rubygems_version: 2.2.1
|
177
|
+
signing_key:
|
178
|
+
specification_version: 4
|
179
|
+
summary: A Lita handler to interact with Statuspage.io
|
180
|
+
test_files:
|
181
|
+
- spec/files/component_update.json
|
182
|
+
- spec/files/components.json
|
183
|
+
- spec/files/incident_deleted.json
|
184
|
+
- spec/files/incident_new.json
|
185
|
+
- spec/files/incident_updated.json
|
186
|
+
- spec/files/incidents.json
|
187
|
+
- spec/files/incidents_scheduled.json
|
188
|
+
- spec/files/incidents_unresolved.json
|
189
|
+
- spec/files/incidents_update.json
|
190
|
+
- spec/lita/handlers/statuspage_spec.rb
|
191
|
+
- spec/spec_helper.rb
|