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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b01c5dde801876bc1c207904cd809f701ee23424
4
- data.tar.gz: e150d1e626521658e5062ff5d9170085e6aed973
3
+ metadata.gz: 79269c762a45f49d7289a9bd740576eff2f0ed63
4
+ data.tar.gz: 218cca7791ea9dbed9a38ea8e805826616e4f7be
5
5
  SHA512:
6
- metadata.gz: a39ecbcc04239e4b3960beb39c7e9a6fce42ea9fc8de8168928fdee9911ecf0e40bf3f98291f6e9101f07dc5243bd55e2fbe59ebfd76e8bf573c6e64ea9b8a4f
7
- data.tar.gz: 37e3281f82bed4712d5e9145c8b9c2f911ad4eb2dee0e25487a3474de96980e9502ee88d6e76ba3b6288a69305617d7e0ba3e225ac1a466dd70f2c0bdc9ae462
6
+ metadata.gz: 6a367bde834b533daf0a75caeab2bf15137e2a2c0a9094cb410c2914bd5307cdc93ca6f91cc07eeee726a2484a958dca8a1a6585a70a70bce97ca80843e058c6
7
+ data.tar.gz: 0eb8b4400b3740db4fe561d545fe724694a0d8eaeb99011a27c85d9c7b21b38ddce51eca9b55c7ff9050b31ab8a9e5554f662a7225d065d4088642003df4312b
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --profile 5
@@ -1,17 +1,16 @@
1
1
  ClassLength:
2
- Max: 400
3
-
4
- CyclomaticComplexity:
5
- Max: 10
2
+ Max: 260
6
3
 
7
4
  Documentation:
8
- Enabled: false
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
@@ -1,8 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.0
4
- script: bundle exec rake
5
- before_install:
6
- - gem update --system
3
+ - 2.1
4
+ - 2.2
7
5
  services:
8
6
  - redis-server
7
+ sudo: false
8
+ cache: bundler
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
data/README.md CHANGED
@@ -1,10 +1,13 @@
1
1
  # lita-statuspage
2
2
 
3
- [![Build Status](https://travis-ci.org/esigler/lita-statuspage.png?branch=master)](https://travis-ci.org/esigler/lita-statuspage)
4
- [![Code Climate](https://codeclimate.com/github/esigler/lita-statuspage.png)](https://codeclimate.com/github/esigler/lita-statuspage)
5
- [![Coverage Status](https://coveralls.io/repos/esigler/lita-statuspage/badge.png?branch=master)](https://coveralls.io/r/esigler/lita-statuspage?branch=master)
6
-
7
- Statuspage.io (http://statuspage.io) handler for updating incidents, service status, etc.
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
@@ -3,6 +3,6 @@ require 'rspec/core/rake_task'
3
3
  require 'rubocop/rake_task'
4
4
 
5
5
  RSpec::Core::RakeTask.new(:spec)
6
- Rubocop::RakeTask.new(:rubocop)
6
+ RuboCop::RakeTask.new(:rubocop)
7
7
 
8
- task default: [ :spec, :rubocop ]
8
+ task default: [:spec, :rubocop]
@@ -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
- '(statuspage|sp) incident new name:"<name>"' => 'Create a new realtime incident',
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
- '(statuspage|sp) incident update id:ABC123 (...)' => 'Update an incident (takes same arguments as new)'
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
- '(statuspage|sp) incident list all' => 'List all incidents'
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
- '(statuspage|sp) incident list scheduled' => 'List scheduled incidents'
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
- '(statuspage|sp) incident list unresolved' => 'List unresolved incidents'
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
- '(statuspage|sp) incident delete latest' => 'Delete latest incident'
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
- '(statuspage|sp) incident delete id:<id>' => 'Delete a specific incident'
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
- '(statuspage|sp) component list' => 'Lists all components'
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
- '(statuspage|sp) component update' => 'Updates the component'
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
- unless args.key?('name')
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
- unless args.key?('id')
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
- if incident
175
- response.reply(delete_incident(incident['id']))
176
- else
177
- response.reply('No latest incident found')
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
- if components
189
- if components.count > 0
190
- components.each do |component|
191
- response.reply(format_component(component))
192
- end
193
- else
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
- request_args = {}
204
- if !args.key?('name') && !args.key?('id')
205
- response.reply('Need an identifier for the component')
206
- else
207
- if args.key?('status')
208
- if valid_component_status?(args['status'])
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
- if incidents && incidents.count > 0
234
- incidents.each do |incident|
235
- return incident if incident['id'] == id
236
- end
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
- if incidents
251
- response = ['No incidents to list'] unless incidents.count > 0
252
- incidents.each do |incident|
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
- request_args = {}
263
- request_args['incident[name]'] = args['name']
264
- request_args['incident[status]'] = args['status'] if args.key?('status')
265
- request_args['incident[wants_twitter_update]'] = args['twitter'] if args.key?('twitter')
266
- request_args['incident[message]'] = args['message'] if args.key?('message')
267
- request_args['incident[impact_override]'] = args['impact'] if args.key?('impact')
268
- result = api_request('post', 'incidents.json', request_args)
269
- if result
270
- "Incident #{result['id']} created"
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 = incident(id)
278
- if incident
279
- request_args = {}
280
- request_args['incident[status]'] = args['status'] if args.key?('status')
281
- request_args['incident[wants_twitter_update]'] = args['twitter'] if args.key?('twitter')
282
- request_args['incident[message]'] = args['message'] if args.key?('message')
283
- request_args['incident[impact_override]'] = args['impact'] if args.key?('impact')
284
- result = api_request('patch', "incidents/#{id}.json", request_args)
285
- if result
286
- "Incident #{id} updated"
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
- if incident
298
- result = api_request('delete', "incidents/#{id}.json")
299
- if result
300
- "Incident #{id} deleted"
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
- if components && components.count > 0
312
- components.each do |component|
313
- return component if component['id'] == identifier ||
314
- component['name'] == identifier
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
- if component
322
- result = api_request('patch', "components/#{id}.json", args)
323
- if result
324
- "Component #{id} updated"
325
- else
326
- 'Error updating component'
327
- end
328
- else
329
- 'Component not found'
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 degraded_performance partial_outage major_outage).include?(status)
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
- if Lita.config.handlers.statuspage.api_key.nil? ||
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
- if http_response.status == 200 ||
398
- http_response.status == 201
399
- MultiJson.load(http_response.body)
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