stoplight 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +119 -59
- data/lib/stoplight.rb +4 -0
- data/lib/stoplight/notifier/bugsnag.rb +37 -0
- data/lib/stoplight/notifier/honeybadger.rb +43 -0
- data/lib/stoplight/notifier/logger.rb +19 -0
- data/lib/stoplight/version.rb +1 -1
- data/spec/stoplight/notifier/bugsnag_spec.rb +89 -0
- data/spec/stoplight/notifier/honeybadger_spec.rb +74 -0
- data/spec/stoplight/notifier/logger_spec.rb +70 -0
- metadata +49 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d93190b30a8d042b53c5b2cf115a02dc4d2ca890
|
4
|
+
data.tar.gz: 0c4f3b4da7602df759e976eed9d73dfdb87fa7e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efbc488c2ebea3bca686f190d14a06bf48b563b2d1c4d07fc30692901d5d72aa353dd93b2d422d0dac0affe01d3cd16d2ea293b767c70ead80a571810b787190
|
7
|
+
data.tar.gz: 93bd99e0422058fb537555e872baf50513672f9c0035eb6f717dae6157ae049c94ac8d810045a825b3d364dc0014a307f7705adbabcc36b6fb28b252b27ddf17
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
Stoplight uses [Semantic Versioning][1].
|
4
4
|
|
5
|
+
## v1.2.0 (2015-09-11)
|
6
|
+
|
7
|
+
- #78: Added a Bugsnag notifier. Thanks, @bolshakov!
|
8
|
+
- Added a Honeybadger notifier.
|
9
|
+
- #77: Added a logger notifier. Thanks again, @bolshakov!
|
10
|
+
|
5
11
|
## v1.1.1 (2015-07-16)
|
6
12
|
|
7
13
|
- Introduced a generic notifier to reduce duplication between the IO and Slack
|
data/README.md
CHANGED
@@ -12,9 +12,9 @@ breaker pattern in Ruby.
|
|
12
12
|
|
13
13
|
---
|
14
14
|
|
15
|
-
Does your code use unreliable systems, like a flaky database or a
|
16
|
-
|
17
|
-
|
15
|
+
Does your code use unreliable systems, like a flaky database or a spotty web
|
16
|
+
service? Wrap calls to those up in stoplights to prevent them from affecting
|
17
|
+
the rest of your application.
|
18
18
|
|
19
19
|
Check out [stoplight-admin][] for controlling your stoplights.
|
20
20
|
|
@@ -27,8 +27,12 @@ Check out [stoplight-admin][] for controlling your stoplights.
|
|
27
27
|
- [Rails](#rails)
|
28
28
|
- [Setup](#setup)
|
29
29
|
- [Data store](#data-store)
|
30
|
+
- [Redis](#redis)
|
30
31
|
- [Notifiers](#notifiers)
|
32
|
+
- [Bugsnag](#bugsnag)
|
31
33
|
- [HipChat](#hipchat)
|
34
|
+
- [Honeybadger](#honeybadger)
|
35
|
+
- [Logger](#logger)
|
32
36
|
- [Slack](#slack)
|
33
37
|
- [Rails](#rails-1)
|
34
38
|
- [Advanced usage](#advanced-usage)
|
@@ -64,9 +68,9 @@ light = Stoplight('example-1') { 22.0 / 7 }
|
|
64
68
|
# => #<Stoplight::Light:...>
|
65
69
|
```
|
66
70
|
|
67
|
-
Then you can run it and it will return the result of calling the
|
68
|
-
|
69
|
-
|
71
|
+
Then you can run it and it will return the result of calling the block. This is
|
72
|
+
the green state. (The green state corresponds to the closed state for circuit
|
73
|
+
breakers.)
|
70
74
|
|
71
75
|
``` rb
|
72
76
|
light.run
|
@@ -75,19 +79,19 @@ light.color
|
|
75
79
|
# => "green"
|
76
80
|
```
|
77
81
|
|
78
|
-
If everything goes well, you shouldn't even be able to tell that
|
79
|
-
|
80
|
-
|
82
|
+
If everything goes well, you shouldn't even be able to tell that you're using a
|
83
|
+
stoplight. That's not very interesting though, so let's create a failing
|
84
|
+
stoplight:
|
81
85
|
|
82
86
|
``` rb
|
83
87
|
light = Stoplight('example-2') { 1 / 0 }
|
84
88
|
# => #<Stoplight::Light:...>
|
85
89
|
```
|
86
90
|
|
87
|
-
Now when you run it, the error will be recorded and passed through.
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
+
Now when you run it, the error will be recorded and passed through. After
|
92
|
+
running it a few times, the stoplight will stop trying and fail fast. This is
|
93
|
+
the red state. (The red state corresponds to the open state for circuit
|
94
|
+
breakers.)
|
91
95
|
|
92
96
|
``` rb
|
93
97
|
light.run
|
@@ -103,23 +107,21 @@ light.color
|
|
103
107
|
# => "red"
|
104
108
|
```
|
105
109
|
|
106
|
-
When the stoplight changes from green to red, it will notify every
|
107
|
-
|
108
|
-
about notifiers.
|
110
|
+
When the stoplight changes from green to red, it will notify every configured
|
111
|
+
notifier. See [the notifiers section][] to learn more about notifiers.
|
109
112
|
|
110
|
-
The stoplight will move into the yellow state after being in the
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
to green.
|
113
|
+
The stoplight will move into the yellow state after being in the red state for
|
114
|
+
a while. (The yellow state corresponds to the half open state for circuit
|
115
|
+
breakers.) To configure how long it takes to switch into the yellow state,
|
116
|
+
check out [the timeout section][] When stoplights are yellow, they will try
|
117
|
+
to run their code. If it fails, they'll switch back to red. If it succeeds,
|
118
|
+
they'll switch to green.
|
117
119
|
|
118
120
|
### Custom errors
|
119
121
|
|
120
|
-
Some errors shouldn't cause your stoplight to move into the red
|
121
|
-
|
122
|
-
|
122
|
+
Some errors shouldn't cause your stoplight to move into the red state. Usually
|
123
|
+
these are handled elsewhere in your stack and don't represent real failures. A
|
124
|
+
good example is `ActiveRecord::RecordNotFound`.
|
123
125
|
|
124
126
|
``` rb
|
125
127
|
light = Stoplight('example-3') { User.find(123) }
|
@@ -140,10 +142,10 @@ The following errors are always allowed: `NoMemoryError`, `ScriptError`,
|
|
140
142
|
|
141
143
|
### Custom fallback
|
142
144
|
|
143
|
-
By default, stoplights will re-raise errors when they're green.
|
144
|
-
|
145
|
-
|
146
|
-
|
145
|
+
By default, stoplights will re-raise errors when they're green. When they're
|
146
|
+
red, they'll raise a `Stoplight::Error::RedLight` error. You can provide a
|
147
|
+
fallback that will be called in both of these cases. It will be passed the
|
148
|
+
error if the light was green.
|
147
149
|
|
148
150
|
``` rb
|
149
151
|
light = Stoplight('example-4') { 1 / 0 }
|
@@ -166,9 +168,8 @@ light.run
|
|
166
168
|
|
167
169
|
### Custom threshold
|
168
170
|
|
169
|
-
Some bits of code might be allowed to fail more or less frequently
|
170
|
-
|
171
|
-
in seconds.
|
171
|
+
Some bits of code might be allowed to fail more or less frequently than others.
|
172
|
+
You can configure this by setting a custom threshold.
|
172
173
|
|
173
174
|
``` rb
|
174
175
|
light = Stoplight('example-5') { fail }
|
@@ -185,9 +186,9 @@ The default threshold is `3`.
|
|
185
186
|
|
186
187
|
### Custom timeout
|
187
188
|
|
188
|
-
Stoplights will automatically attempt to recover after a certain
|
189
|
-
|
190
|
-
|
189
|
+
Stoplights will automatically attempt to recover after a certain amount of
|
190
|
+
time. A light in the red state for longer than the timeout will transition to
|
191
|
+
the yellow state. This timeout is customizable.
|
191
192
|
|
192
193
|
``` rb
|
193
194
|
light = Stoplight('example-6') { fail }
|
@@ -208,13 +209,15 @@ light.run
|
|
208
209
|
# RuntimeError:
|
209
210
|
```
|
210
211
|
|
211
|
-
The default timeout is `60` seconds.
|
212
|
-
automatic recovery
|
212
|
+
The default timeout is `60` seconds. To disable automatic recovery, set the
|
213
|
+
timeout to `Float::INFINITY`. To make automatic recovery instantaneous, set the
|
214
|
+
timeout to `0` seconds. Note that this is not recommended, as it effectively
|
215
|
+
replaces the red state with yellow.
|
213
216
|
|
214
217
|
### Rails
|
215
218
|
|
216
|
-
Stoplight was designed to wrap Rails actions with minimal effort.
|
217
|
-
|
219
|
+
Stoplight was designed to wrap Rails actions with minimal effort. Here's an
|
220
|
+
example configuration:
|
218
221
|
|
219
222
|
``` rb
|
220
223
|
class ApplicationController < ActionController::Base
|
@@ -247,9 +250,12 @@ Stoplight::Light.default_data_store
|
|
247
250
|
# => #<Stoplight::DataStore::Memory:...>
|
248
251
|
```
|
249
252
|
|
250
|
-
If you want to use a persistent data store, you'll have to set it
|
251
|
-
|
252
|
-
|
253
|
+
If you want to use a persistent data store, you'll have to set it up. Currently
|
254
|
+
the only supported persistent data store is Redis.
|
255
|
+
|
256
|
+
#### Redis
|
257
|
+
|
258
|
+
Make sure you have [the Redis gem][] (`~> 3.2`) installed before configuring
|
253
259
|
Stoplight.
|
254
260
|
|
255
261
|
``` rb
|
@@ -273,11 +279,25 @@ Stoplight::Light.default_notifiers
|
|
273
279
|
```
|
274
280
|
|
275
281
|
If you want to send notifications elsewhere, you'll have to set them up.
|
276
|
-
|
282
|
+
|
283
|
+
#### Bugsnag
|
284
|
+
|
285
|
+
Make sure you have [the Bugsnag gem][] (`~> 2.8`) installed before configuring
|
286
|
+
Stoplight.
|
287
|
+
|
288
|
+
``` rb
|
289
|
+
require 'bugsnag'
|
290
|
+
# => true
|
291
|
+
notifier = Stoplight::Notifier::Bugsnag.new(Bugsnag)
|
292
|
+
# => #<Stoplight::Notifier::Bugsnag:...>
|
293
|
+
Stoplight::Light.default_notifiers += [notifier]
|
294
|
+
# => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::Bugsnag:...>]
|
295
|
+
```
|
277
296
|
|
278
297
|
#### HipChat
|
279
298
|
|
280
|
-
Make sure you have [the HipChat gem][] installed before configuring
|
299
|
+
Make sure you have [the HipChat gem][] (`~> 1.5`) installed before configuring
|
300
|
+
Stoplight.
|
281
301
|
|
282
302
|
``` rb
|
283
303
|
require 'hipchat'
|
@@ -290,9 +310,40 @@ Stoplight::Light.default_notifiers += [notifier]
|
|
290
310
|
# => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::HipChat:...>]
|
291
311
|
```
|
292
312
|
|
313
|
+
#### Honeybadger
|
314
|
+
|
315
|
+
Make sure you have [the Honeybadger gem][] (`~> 2.1`) installed before
|
316
|
+
configuring Stoplight.
|
317
|
+
|
318
|
+
``` rb
|
319
|
+
require 'honeybadger'
|
320
|
+
# => true
|
321
|
+
notifier = Stoplight::Notifier::Honeybadger.new('api key')
|
322
|
+
# => #<Stoplight::Notifier::Honeybadger:...>
|
323
|
+
Stoplight::Light.default_notifiers += [notifier]
|
324
|
+
# => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::Honeybadger:...>]
|
325
|
+
```
|
326
|
+
|
327
|
+
#### Logger
|
328
|
+
|
329
|
+
Stoplight can be configured to use [the Logger class][] from the standard
|
330
|
+
library.
|
331
|
+
|
332
|
+
``` rb
|
333
|
+
require 'logger'
|
334
|
+
# => true
|
335
|
+
logger = Logger.new(STDERR)
|
336
|
+
# => #<Logger:...>
|
337
|
+
notifier = Stoplight::Notifier::Logger.new(logger)
|
338
|
+
# => #<Stoplight::Notifier::Logger:...>
|
339
|
+
Stoplight::Light.default_notifiers += [notifier]
|
340
|
+
# => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::Logger:...>]
|
341
|
+
```
|
342
|
+
|
293
343
|
#### Slack
|
294
344
|
|
295
|
-
Make sure you have [the Slack gem][] installed before configuring
|
345
|
+
Make sure you have [the Slack gem][] (`~> 1.3`) installed before configuring
|
346
|
+
Stoplight.
|
296
347
|
|
297
348
|
``` rb
|
298
349
|
require 'slack-notifier'
|
@@ -307,25 +358,25 @@ Stoplight::Light.default_notifiers += [notifier]
|
|
307
358
|
|
308
359
|
### Rails
|
309
360
|
|
310
|
-
Stoplight is designed to work seamlessly with Rails. If you want
|
311
|
-
|
312
|
-
|
313
|
-
|
361
|
+
Stoplight is designed to work seamlessly with Rails. If you want to use the
|
362
|
+
in-memory data store, you don't need to do anything special. If you want to use
|
363
|
+
a persistent data store, you'll need to configure it. Create an initializer for
|
364
|
+
Stoplight:
|
314
365
|
|
315
366
|
``` rb
|
316
367
|
# config/initializers/stoplight.rb
|
317
368
|
require 'stoplight'
|
318
369
|
Stoplight::Light.default_data_store = Stoplight::DataStore::Redis.new(...)
|
319
|
-
Stoplight::Light.default_notifiers += [Stoplight::Notifier::
|
370
|
+
Stoplight::Light.default_notifiers += [Stoplight::Notifier::Logger.new(Rails.logger)]
|
320
371
|
```
|
321
372
|
|
322
373
|
## Advanced usage
|
323
374
|
|
324
375
|
### Locking
|
325
376
|
|
326
|
-
Although stoplights can operate on their own, occasionally you may
|
327
|
-
|
328
|
-
|
377
|
+
Although stoplights can operate on their own, occasionally you may want to
|
378
|
+
override the default behavior. You can lock a light in either the green or red
|
379
|
+
state using `set_state`.
|
329
380
|
|
330
381
|
``` rb
|
331
382
|
light = Stoplight('example-7') { true }
|
@@ -338,12 +389,18 @@ light.run
|
|
338
389
|
# Stoplight::Error::RedLight: example-7
|
339
390
|
```
|
340
391
|
|
341
|
-
**Code in locked red lights may still run under certain conditions!**
|
342
|
-
|
343
|
-
|
344
|
-
|
392
|
+
**Code in locked red lights may still run under certain conditions!** If you
|
393
|
+
have configured a custom data store and that data store fails, Stoplight will
|
394
|
+
switch over to using a blank in-memory data store. That means you will lose the
|
395
|
+
locked state of any stoplights.
|
396
|
+
|
397
|
+
You can go back to using the default behavior by unlocking the stoplight.
|
398
|
+
|
399
|
+
``` rb
|
400
|
+
light.data_store.set_state(light, Stoplight::State::UNLOCKED)
|
401
|
+
```
|
345
402
|
|
346
|
-
|
403
|
+
### Testing
|
347
404
|
|
348
405
|
Stoplights typically work as expected without modification in test suites.
|
349
406
|
However there are a few things you can do to make them behave better. If your
|
@@ -393,7 +450,10 @@ Stoplight is licensed under [the MIT License][].
|
|
393
450
|
[the notifiers section]: #notifiers
|
394
451
|
[the timeout section]: #custom-timeout
|
395
452
|
[the redis gem]: https://rubygems.org/gems/redis
|
453
|
+
[the bugsnag gem]: https://rubygems.org/gems/bugsnag
|
396
454
|
[the hipchat gem]: https://rubygems.org/gems/hipchat
|
455
|
+
[the honeybadger gem]: https://rubygems.org/gems/honeybadger
|
456
|
+
[the logger class]: http://ruby-doc.org/stdlib-2.2.3/libdoc/logger/rdoc/Logger.html
|
397
457
|
[the slack gem]: https://rubygems.org/gems/slack-notifier
|
398
458
|
[@camdez]: https://github.com/camdez
|
399
459
|
[@tfausak]: https://github.com/tfausak
|
data/lib/stoplight.rb
CHANGED
@@ -18,8 +18,12 @@ require 'stoplight/data_store/redis'
|
|
18
18
|
require 'stoplight/notifier'
|
19
19
|
require 'stoplight/notifier/base'
|
20
20
|
require 'stoplight/notifier/generic'
|
21
|
+
|
22
|
+
require 'stoplight/notifier/bugsnag'
|
21
23
|
require 'stoplight/notifier/hip_chat'
|
24
|
+
require 'stoplight/notifier/honeybadger'
|
22
25
|
require 'stoplight/notifier/io'
|
26
|
+
require 'stoplight/notifier/logger'
|
23
27
|
require 'stoplight/notifier/slack'
|
24
28
|
|
25
29
|
require 'stoplight/default'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Stoplight
|
4
|
+
module Notifier
|
5
|
+
# @see Base
|
6
|
+
class Bugsnag < Base
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
severity: 'info'
|
9
|
+
}
|
10
|
+
|
11
|
+
StoplightStatusChange = Class.new(Error::Base)
|
12
|
+
|
13
|
+
# @return [Proc]
|
14
|
+
attr_reader :formatter
|
15
|
+
# @return [::Bugsnag]
|
16
|
+
attr_reader :bugsnag
|
17
|
+
# @return [Hash{Symbol => Object}]
|
18
|
+
attr_reader :options
|
19
|
+
|
20
|
+
# @param bugsnag [::Bugsnag]
|
21
|
+
# @param formatter [Proc, nil]
|
22
|
+
# @param options [Hash{Symbol => Object}]
|
23
|
+
# @option options [String] :severity
|
24
|
+
def initialize(bugsnag, formatter = nil, options = {})
|
25
|
+
@bugsnag = bugsnag
|
26
|
+
@formatter = formatter || Default::FORMATTER
|
27
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def notify(light, from_color, to_color, error)
|
31
|
+
message = formatter.call(light, from_color, to_color, error)
|
32
|
+
bugsnag.notify(StoplightStatusChange.new(message), options)
|
33
|
+
message
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Stoplight
|
4
|
+
module Notifier
|
5
|
+
# @see Base
|
6
|
+
class Honeybadger < Base
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
parameters: {},
|
9
|
+
session: {},
|
10
|
+
context: {}
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :api_key
|
15
|
+
# @return [Proc]
|
16
|
+
attr_reader :formatter
|
17
|
+
# @return [Hash{Symbol => Object}]
|
18
|
+
attr_reader :options
|
19
|
+
|
20
|
+
# @param api_key [String]
|
21
|
+
# @param formatter [Proc, nil]
|
22
|
+
# @param options [Hash{Symbol => Object}]
|
23
|
+
# @option options [Hash] :parameters
|
24
|
+
# @option options [Hash] :session
|
25
|
+
# @option options [Hash] :context
|
26
|
+
def initialize(api_key, formatter = nil, options = {})
|
27
|
+
@api_key = api_key
|
28
|
+
@formatter = formatter || Default::FORMATTER
|
29
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def notify(light, from_color, to_color, error)
|
33
|
+
message = formatter.call(light, from_color, to_color, error)
|
34
|
+
h = options.merge(
|
35
|
+
api_key: api_key,
|
36
|
+
error_message: message,
|
37
|
+
backtrace: (error.backtrace if error))
|
38
|
+
::Honeybadger.notify(h)
|
39
|
+
message
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/stoplight/version.rb
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'bugsnag'
|
5
|
+
|
6
|
+
RSpec.describe Stoplight::Notifier::Bugsnag do
|
7
|
+
StoplightStatusChange = Stoplight::Notifier::Bugsnag::StoplightStatusChange
|
8
|
+
|
9
|
+
it 'is a class' do
|
10
|
+
expect(described_class).to be_a(Class)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'is a subclass of Base' do
|
14
|
+
expect(described_class).to be < Stoplight::Notifier::Base
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#formatter' do
|
18
|
+
it 'is initially the default' do
|
19
|
+
expect(described_class.new(nil, nil).formatter)
|
20
|
+
.to eql(Stoplight::Default::FORMATTER)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'reads the formatter' do
|
24
|
+
formatter = proc {}
|
25
|
+
expect(described_class.new(nil, formatter).formatter)
|
26
|
+
.to eql(formatter)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#options' do
|
31
|
+
it 'is initially the default' do
|
32
|
+
expect(described_class.new(nil, nil).options)
|
33
|
+
.to eql(Stoplight::Notifier::Bugsnag::DEFAULT_OPTIONS)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'reads the options' do
|
37
|
+
options = { key: :value }
|
38
|
+
expect(described_class.new(nil, nil, options).options)
|
39
|
+
.to eql(Stoplight::Notifier::Bugsnag::DEFAULT_OPTIONS.merge(options))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#bugsnag' do
|
44
|
+
it 'reads the Bugsnag client' do
|
45
|
+
client = ::Bugsnag
|
46
|
+
expect(described_class.new(client, nil).bugsnag)
|
47
|
+
.to eql(client)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#notify' do
|
52
|
+
let(:light) { Stoplight::Light.new(name, &code) }
|
53
|
+
let(:name) { ('a'..'z').to_a.shuffle.join }
|
54
|
+
let(:code) { -> {} }
|
55
|
+
let(:from_color) { Stoplight::Color::GREEN }
|
56
|
+
let(:to_color) { Stoplight::Color::RED }
|
57
|
+
let(:notifier) { described_class.new(bugsnag) }
|
58
|
+
let(:bugsnag) { double(Bugsnag) }
|
59
|
+
|
60
|
+
subject(:result) do
|
61
|
+
notifier.notify(light, from_color, to_color, error)
|
62
|
+
end
|
63
|
+
|
64
|
+
before do
|
65
|
+
status_change = StoplightStatusChange.new(message)
|
66
|
+
expect(bugsnag).to receive(:notify).with(status_change, severity: 'info')
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when no error given' do
|
70
|
+
let(:error) { nil }
|
71
|
+
|
72
|
+
it 'logs message' do
|
73
|
+
expect(result).to eq(message)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when message with an error given' do
|
78
|
+
let(:error) { ZeroDivisionError.new('divided by 0') }
|
79
|
+
|
80
|
+
it 'logs message' do
|
81
|
+
expect(result).to eq(message)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def message
|
86
|
+
notifier.formatter.call(light, from_color, to_color, error)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'honeybadger'
|
3
|
+
|
4
|
+
RSpec.describe Stoplight::Notifier::Honeybadger do
|
5
|
+
it 'is a class' do
|
6
|
+
expect(described_class).to be_a(Class)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'is a subclass of Base' do
|
10
|
+
expect(described_class).to be < Stoplight::Notifier::Base
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#formatter' do
|
14
|
+
it 'is initially the default' do
|
15
|
+
expect(described_class.new(nil).formatter).to eql(
|
16
|
+
Stoplight::Default::FORMATTER)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'reads the formatter' do
|
20
|
+
formatter = proc {}
|
21
|
+
expect(described_class.new(nil, formatter).formatter).to eql(formatter)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#options' do
|
26
|
+
it 'is initially the default' do
|
27
|
+
expect(described_class.new(nil).options).to eql(
|
28
|
+
Stoplight::Notifier::Honeybadger::DEFAULT_OPTIONS)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'reads the options' do
|
32
|
+
options = { key: :value }
|
33
|
+
expect(described_class.new(nil, nil, options).options).to eql(
|
34
|
+
Stoplight::Notifier::Honeybadger::DEFAULT_OPTIONS.merge(options))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#notify' do
|
39
|
+
let(:light) { Stoplight::Light.new(name, &code) }
|
40
|
+
let(:name) { ('a'..'z').to_a.shuffle.join }
|
41
|
+
let(:code) { -> {} }
|
42
|
+
let(:from_color) { Stoplight::Color::GREEN }
|
43
|
+
let(:to_color) { Stoplight::Color::RED }
|
44
|
+
let(:notifier) { described_class.new(api_key) }
|
45
|
+
let(:api_key) { ('a'..'z').to_a.shuffle.join }
|
46
|
+
|
47
|
+
before do
|
48
|
+
allow(Honeybadger).to receive(:notify)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns the message' do
|
52
|
+
error = nil
|
53
|
+
message = notifier.formatter.call(light, from_color, to_color, error)
|
54
|
+
expect(notifier.notify(light, from_color, to_color, error)).to eql(
|
55
|
+
message)
|
56
|
+
expect(Honeybadger).to have_received(:notify).with(
|
57
|
+
hash_including(
|
58
|
+
api_key: api_key,
|
59
|
+
error_message: message))
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns the message with an error' do
|
63
|
+
error = ZeroDivisionError.new('divided by 0')
|
64
|
+
message = notifier.formatter.call(light, from_color, to_color, error)
|
65
|
+
expect(notifier.notify(light, from_color, to_color, error)).to eql(
|
66
|
+
message)
|
67
|
+
expect(Honeybadger).to have_received(:notify).with(
|
68
|
+
hash_including(
|
69
|
+
api_key: api_key,
|
70
|
+
error_message: message,
|
71
|
+
backtrace: error.backtrace))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Stoplight::Notifier::Logger do
|
6
|
+
it 'is a class' do
|
7
|
+
expect(described_class).to be_a(Class)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'is a subclass of Base' do
|
11
|
+
expect(described_class).to be < Stoplight::Notifier::Base
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#formatter' do
|
15
|
+
it 'is initially the default' do
|
16
|
+
expect(described_class.new(nil, nil).formatter)
|
17
|
+
.to eql(Stoplight::Default::FORMATTER)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'reads the formatter' do
|
21
|
+
formatter = proc {}
|
22
|
+
expect(described_class.new(nil, formatter).formatter)
|
23
|
+
.to eql(formatter)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#logger' do
|
28
|
+
it 'reads the logger' do
|
29
|
+
logger = Logger.new(StringIO.new)
|
30
|
+
expect(described_class.new(logger, nil).logger)
|
31
|
+
.to eql(logger)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#notify' do
|
36
|
+
let(:light) { Stoplight::Light.new(name, &code) }
|
37
|
+
let(:name) { ('a'..'z').to_a.shuffle.join }
|
38
|
+
let(:code) { -> {} }
|
39
|
+
let(:from_color) { Stoplight::Color::GREEN }
|
40
|
+
let(:to_color) { Stoplight::Color::RED }
|
41
|
+
let(:notifier) { described_class.new(Logger.new(io)) }
|
42
|
+
let(:io) { StringIO.new }
|
43
|
+
|
44
|
+
before do
|
45
|
+
notifier.notify(light, from_color, to_color, error)
|
46
|
+
end
|
47
|
+
|
48
|
+
subject(:result) { io.string }
|
49
|
+
|
50
|
+
context 'when no error given' do
|
51
|
+
let(:error) { nil }
|
52
|
+
|
53
|
+
it 'logs message' do
|
54
|
+
expect(result).to match(/.+#{message}/)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when message with an error given' do
|
59
|
+
let(:error) { ZeroDivisionError.new('divided by 0') }
|
60
|
+
|
61
|
+
it 'logs message' do
|
62
|
+
expect(result).to match(/.+#{message}/)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def message
|
67
|
+
notifier.formatter.call(light, from_color, to_color, error)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stoplight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cameron Desautels
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-09-11 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: benchmark-ips
|
@@ -18,14 +18,28 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '2.
|
21
|
+
version: '2.3'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '2.
|
28
|
+
version: '2.3'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: bugsnag
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '2.8'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '2.8'
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: coveralls
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,14 +74,14 @@ dependencies:
|
|
60
74
|
requirements:
|
61
75
|
- - "~>"
|
62
76
|
- !ruby/object:Gem::Version
|
63
|
-
version: '2.
|
77
|
+
version: '2.13'
|
64
78
|
type: :development
|
65
79
|
prerelease: false
|
66
80
|
version_requirements: !ruby/object:Gem::Requirement
|
67
81
|
requirements:
|
68
82
|
- - "~>"
|
69
83
|
- !ruby/object:Gem::Version
|
70
|
-
version: '2.
|
84
|
+
version: '2.13'
|
71
85
|
- !ruby/object:Gem::Dependency
|
72
86
|
name: guard-rspec
|
73
87
|
requirement: !ruby/object:Gem::Requirement
|
@@ -110,6 +124,20 @@ dependencies:
|
|
110
124
|
- - "~>"
|
111
125
|
- !ruby/object:Gem::Version
|
112
126
|
version: '1.5'
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: honeybadger
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '2.1'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - "~>"
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '2.1'
|
113
141
|
- !ruby/object:Gem::Dependency
|
114
142
|
name: rake
|
115
143
|
requirement: !ruby/object:Gem::Requirement
|
@@ -158,42 +186,42 @@ dependencies:
|
|
158
186
|
requirements:
|
159
187
|
- - "~>"
|
160
188
|
- !ruby/object:Gem::Version
|
161
|
-
version: '0.
|
189
|
+
version: '0.34'
|
162
190
|
type: :development
|
163
191
|
prerelease: false
|
164
192
|
version_requirements: !ruby/object:Gem::Requirement
|
165
193
|
requirements:
|
166
194
|
- - "~>"
|
167
195
|
- !ruby/object:Gem::Version
|
168
|
-
version: '0.
|
196
|
+
version: '0.34'
|
169
197
|
- !ruby/object:Gem::Dependency
|
170
198
|
name: slack-notifier
|
171
199
|
requirement: !ruby/object:Gem::Requirement
|
172
200
|
requirements:
|
173
201
|
- - "~>"
|
174
202
|
- !ruby/object:Gem::Version
|
175
|
-
version: 1.
|
203
|
+
version: '1.3'
|
176
204
|
type: :development
|
177
205
|
prerelease: false
|
178
206
|
version_requirements: !ruby/object:Gem::Requirement
|
179
207
|
requirements:
|
180
208
|
- - "~>"
|
181
209
|
- !ruby/object:Gem::Version
|
182
|
-
version: 1.
|
210
|
+
version: '1.3'
|
183
211
|
- !ruby/object:Gem::Dependency
|
184
212
|
name: timecop
|
185
213
|
requirement: !ruby/object:Gem::Requirement
|
186
214
|
requirements:
|
187
215
|
- - "~>"
|
188
216
|
- !ruby/object:Gem::Version
|
189
|
-
version: '0.
|
217
|
+
version: '0.8'
|
190
218
|
type: :development
|
191
219
|
prerelease: false
|
192
220
|
version_requirements: !ruby/object:Gem::Requirement
|
193
221
|
requirements:
|
194
222
|
- - "~>"
|
195
223
|
- !ruby/object:Gem::Version
|
196
|
-
version: '0.
|
224
|
+
version: '0.8'
|
197
225
|
- !ruby/object:Gem::Dependency
|
198
226
|
name: yard
|
199
227
|
requirement: !ruby/object:Gem::Requirement
|
@@ -233,9 +261,12 @@ files:
|
|
233
261
|
- lib/stoplight/light/runnable.rb
|
234
262
|
- lib/stoplight/notifier.rb
|
235
263
|
- lib/stoplight/notifier/base.rb
|
264
|
+
- lib/stoplight/notifier/bugsnag.rb
|
236
265
|
- lib/stoplight/notifier/generic.rb
|
237
266
|
- lib/stoplight/notifier/hip_chat.rb
|
267
|
+
- lib/stoplight/notifier/honeybadger.rb
|
238
268
|
- lib/stoplight/notifier/io.rb
|
269
|
+
- lib/stoplight/notifier/logger.rb
|
239
270
|
- lib/stoplight/notifier/slack.rb
|
240
271
|
- lib/stoplight/state.rb
|
241
272
|
- lib/stoplight/version.rb
|
@@ -251,9 +282,12 @@ files:
|
|
251
282
|
- spec/stoplight/light/runnable_spec.rb
|
252
283
|
- spec/stoplight/light_spec.rb
|
253
284
|
- spec/stoplight/notifier/base_spec.rb
|
285
|
+
- spec/stoplight/notifier/bugsnag_spec.rb
|
254
286
|
- spec/stoplight/notifier/generic_spec.rb
|
255
287
|
- spec/stoplight/notifier/hip_chat_spec.rb
|
288
|
+
- spec/stoplight/notifier/honeybadger_spec.rb
|
256
289
|
- spec/stoplight/notifier/io_spec.rb
|
290
|
+
- spec/stoplight/notifier/logger_spec.rb
|
257
291
|
- spec/stoplight/notifier/slack_spec.rb
|
258
292
|
- spec/stoplight/notifier_spec.rb
|
259
293
|
- spec/stoplight/state_spec.rb
|
@@ -296,9 +330,12 @@ test_files:
|
|
296
330
|
- spec/stoplight/light/runnable_spec.rb
|
297
331
|
- spec/stoplight/light_spec.rb
|
298
332
|
- spec/stoplight/notifier/base_spec.rb
|
333
|
+
- spec/stoplight/notifier/bugsnag_spec.rb
|
299
334
|
- spec/stoplight/notifier/generic_spec.rb
|
300
335
|
- spec/stoplight/notifier/hip_chat_spec.rb
|
336
|
+
- spec/stoplight/notifier/honeybadger_spec.rb
|
301
337
|
- spec/stoplight/notifier/io_spec.rb
|
338
|
+
- spec/stoplight/notifier/logger_spec.rb
|
302
339
|
- spec/stoplight/notifier/slack_spec.rb
|
303
340
|
- spec/stoplight/notifier_spec.rb
|
304
341
|
- spec/stoplight/state_spec.rb
|