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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2da543aa5426e5354ed20f5e6d8547190597073d
4
- data.tar.gz: 70aa5cfae4dbeec33fbefcadff88098317ccf0cc
3
+ metadata.gz: d93190b30a8d042b53c5b2cf115a02dc4d2ca890
4
+ data.tar.gz: 0c4f3b4da7602df759e976eed9d73dfdb87fa7e5
5
5
  SHA512:
6
- metadata.gz: 7c022ff3500336be177976073695d9d197800e2ecdcfc9e1a498215f239b69e302b82c475f2ab8f7cfd6be508d20b9d9fd0c1170adfa70de1006de11751013c8
7
- data.tar.gz: 857d9ea2421f83e516f64e6319421100d0bda5992875f023909c474ef78d140a173570a28944abc5865fbf5c2b603a79ce9689acd21013f5fa3e0b6e1c6174a8
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
- spotty web service? Wrap those up with stoplights to prevent them
17
- from affecting the rest of your application.
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
- block. This is the green state. (The green state corresponds to the
69
- closed state for circuit breakers.)
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
- you're using a stoplight. That's not very interesting though. Let's
80
- create a failing stoplight:
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
- After running it a few times, the stoplight will stop trying and
89
- fail fast. This is the red state. (The red state corresponds to the
90
- open state for circuit breakers.)
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
- configured notifier. See [the notifiers section][] to learn more
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
- red state for a while. (The yellow state corresponds to the half
112
- open state for circuit breakers.) To configure how long it takes
113
- to switch into the yellow state, check out [the timeout section][]
114
- When stoplights are yellow, they'll try to run their code. If it
115
- fails, they'll switch back to red. If it succeeds, they'll switch
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
- state. Usually these are handled elsewhere in your stack and don't
122
- represent real failures. A good example is `ActiveRecord::RecordNotFound`.
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
- When they're red, they'll raise a `Stoplight::Error::RedLight`
145
- error. You can provide a fallback that will be called in both of
146
- these cases. It will be passed the error if the light was green.
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
- than others. You can configure this by setting a custom threshold
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
- amount of time. A light in the red state for longer than the timeout
190
- will transition to the yellow state. This timeout is customizable.
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. Set the timeout to `-1` to disable
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
- Here's an example configuration:
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
- up. Currently the only supported persistent data store is Redis.
252
- Make sure you have [the Redis gem][] installed before configuring
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
- Currently the only supported notifiers are HipChat and Slack.
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 Stoplight.
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 Stoplight.
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
- to use the in-memory data store, you don't need to do anything
312
- special. If you want to use a persistent data store, you'll need
313
- to configure it. Create an initializer for Stoplight:
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::HipChat.new(...)]
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
- want to override the default behavior. You can lock a light in
328
- either the green or red state using `set_state`.
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
- If you have configured a custom data store and that data store
343
- fails, Stoplight will switch over to using a blank in-memory data
344
- store. That means you will lose the locked state of any stoplights.
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
- ## Testing
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
@@ -0,0 +1,19 @@
1
+ # coding: utf-8
2
+
3
+ module Stoplight
4
+ module Notifier
5
+ # @see Base
6
+ class Logger < Base
7
+ include Generic
8
+
9
+ # @return [::Logger]
10
+ def logger
11
+ @object
12
+ end
13
+
14
+ def put(message)
15
+ logger.warn(message)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
2
 
3
3
  module Stoplight
4
- VERSION = Gem::Version.new('1.1.1')
4
+ VERSION = Gem::Version.new('1.2.0')
5
5
  end
@@ -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.1.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-07-16 00:00:00.000000000 Z
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.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.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.12'
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.12'
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.32'
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.32'
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.2.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.2.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.7'
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.7'
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