stoplight 2.1.3 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +48 -16
  3. data/lib/stoplight/color.rb +4 -4
  4. data/lib/stoplight/data_store/base.rb +1 -1
  5. data/lib/stoplight/data_store/memory.rb +1 -1
  6. data/lib/stoplight/data_store/redis.rb +23 -25
  7. data/lib/stoplight/data_store.rb +1 -1
  8. data/lib/stoplight/default.rb +3 -3
  9. data/lib/stoplight/error.rb +1 -1
  10. data/lib/stoplight/failure.rb +11 -7
  11. data/lib/stoplight/light/runnable.rb +7 -5
  12. data/lib/stoplight/light.rb +1 -1
  13. data/lib/stoplight/notifier/base.rb +1 -1
  14. data/lib/stoplight/notifier/bugsnag.rb +1 -1
  15. data/lib/stoplight/notifier/generic.rb +1 -1
  16. data/lib/stoplight/notifier/hip_chat.rb +1 -1
  17. data/lib/stoplight/notifier/honeybadger.rb +2 -2
  18. data/lib/stoplight/notifier/io.rb +1 -1
  19. data/lib/stoplight/notifier/logger.rb +1 -1
  20. data/lib/stoplight/notifier/pagerduty.rb +21 -0
  21. data/lib/stoplight/notifier/raven.rb +2 -2
  22. data/lib/stoplight/notifier/rollbar.rb +39 -0
  23. data/lib/stoplight/notifier/slack.rb +1 -1
  24. data/lib/stoplight/notifier.rb +1 -1
  25. data/lib/stoplight/state.rb +4 -4
  26. data/lib/stoplight/version.rb +2 -2
  27. data/lib/stoplight.rb +3 -1
  28. data/spec/spec_helper.rb +2 -3
  29. data/spec/stoplight/color_spec.rb +1 -1
  30. data/spec/stoplight/data_store/base_spec.rb +1 -1
  31. data/spec/stoplight/data_store/memory_spec.rb +1 -1
  32. data/spec/stoplight/data_store/redis_spec.rb +1 -1
  33. data/spec/stoplight/data_store_spec.rb +1 -1
  34. data/spec/stoplight/default_spec.rb +2 -2
  35. data/spec/stoplight/error_spec.rb +1 -1
  36. data/spec/stoplight/failure_spec.rb +6 -1
  37. data/spec/stoplight/light/runnable_spec.rb +7 -9
  38. data/spec/stoplight/light_spec.rb +5 -5
  39. data/spec/stoplight/notifier/base_spec.rb +1 -1
  40. data/spec/stoplight/notifier/bugsnag_spec.rb +2 -4
  41. data/spec/stoplight/notifier/generic_spec.rb +1 -1
  42. data/spec/stoplight/notifier/hip_chat_spec.rb +2 -3
  43. data/spec/stoplight/notifier/honeybadger_spec.rb +1 -1
  44. data/spec/stoplight/notifier/io_spec.rb +1 -1
  45. data/spec/stoplight/notifier/logger_spec.rb +1 -1
  46. data/spec/stoplight/notifier/pagerduty_spec.rb +40 -0
  47. data/spec/stoplight/notifier/raven_spec.rb +1 -1
  48. data/spec/stoplight/notifier/rollbar_spec.rb +90 -0
  49. data/spec/stoplight/notifier/slack_spec.rb +2 -3
  50. data/spec/stoplight/notifier_spec.rb +1 -1
  51. data/spec/stoplight/state_spec.rb +1 -1
  52. data/spec/stoplight/version_spec.rb +1 -1
  53. data/spec/stoplight_spec.rb +1 -1
  54. metadata +80 -47
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e73b740e1d020caa3c2231d358358f7f1405d339
4
- data.tar.gz: f228a34259327f769ee5a43630815ee31ec754ee
2
+ SHA256:
3
+ metadata.gz: 2f7c163955f261ad3eeca89a851a06a15f5734d78d045695297f29c143532a58
4
+ data.tar.gz: 9ff3e5911bf7e9f198c714ce1eb0f10c6ba09834e96a8c8c2d16dd3e184ed0ce
5
5
  SHA512:
6
- metadata.gz: ef7a7ec7291ffc27d4b12c2900e52927abe9b9faf93e26f5086959742e57c69c4b8d05a880e66eba7439193686983bd516f429d1c4e6eb61067b86d5870c9f9d
7
- data.tar.gz: 68ef1c8e9583434ae5da043aa0c7ef3f5e0a23a9b9bef40ac58bdffac57fa83de4d9d148e3bfbf68bda3caaf8f831cd10a5d28882952a533655a47fb3b7f21f2
6
+ metadata.gz: 5e42cd0050cdbf9440e80d68d70091e6c22c574c64cf06a29aa9dca320f5f4915dca48e5582ebf18db757fde4ad295c20af05bc6a879695d726afa65ff50dea8
7
+ data.tar.gz: a5088d9ba81a5578cbc078d0671c601fd13738f07f6a67dd12936df3e8a7927053314538d50c1e65ce6913607e9764ff09d6c05f931c4be8984e2e6744399288
data/README.md CHANGED
@@ -4,7 +4,6 @@
4
4
  [![Build badge][]][build]
5
5
  [![Coverage badge][]][coverage]
6
6
  [![Climate badge][]][climate]
7
- [![Dependencies badge][]][dependencies]
8
7
 
9
8
  Stoplight is traffic control for code. It's an implementation of the circuit
10
9
  breaker pattern in Ruby.
@@ -32,6 +31,8 @@ Check out [stoplight-admin][] for controlling your stoplights.
32
31
  - [HipChat](#hipchat)
33
32
  - [Honeybadger](#honeybadger)
34
33
  - [Logger](#logger)
34
+ - [Pagerduty](#pagerduty)
35
+ - [Rollbar](#rollbar)
35
36
  - [Sentry](#sentry)
36
37
  - [Slack](#slack)
37
38
  - [Rails](#rails-1)
@@ -204,7 +205,7 @@ The default threshold is `3`.
204
205
  ### Custom cool off time
205
206
 
206
207
  Stoplights will automatically attempt to recover after a certain amount of
207
- time. A light in the red state for longer than the cool of period will
208
+ time. A light in the red state for longer than the cool off period will
208
209
  transition to the yellow state. This cool off time is customizable.
209
210
 
210
211
  ``` rb
@@ -356,6 +357,36 @@ Stoplight::Light.default_notifiers += [notifier]
356
357
  # => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::Logger:...>]
357
358
  ```
358
359
 
360
+ #### Pagerduty
361
+
362
+ Make sure you have [the Pagerduty gem][] (`~> 2.1`) installed before configuring
363
+ Stoplight.
364
+
365
+ ``` rb
366
+ require 'pagerduty'
367
+ # => true
368
+ pagerduty = Pagerduty.new('http://www.example.com/webhook-url')
369
+ # => #<Pagerduty:...>
370
+ notifier = Stoplight::Notifier::Pagerduty.new(pagerduty)
371
+ # => #<Stoplight::Notifier::Pagerduty:...>
372
+ Stoplight::Light.default_notifiers += [notifier]
373
+ # => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::Pagerduty:...>]
374
+ ```
375
+
376
+ #### Rollbar
377
+
378
+ Make sure you have [the Rollbar gem][] (`~> 2.0`) installed before configuring
379
+ Stoplight.
380
+
381
+ ``` rb
382
+ require 'rollbar'
383
+ # => true
384
+ notifier = Stoplight::Notifier::Rollbar.new(Rollbar)
385
+ # => #<Stoplight::Notifier::Rollbar:...>
386
+ Stoplight::Light.default_notifiers += [notifier]
387
+ # => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::Rollbar:...>]
388
+ ```
389
+
359
390
  #### Sentry
360
391
 
361
392
  Make sure you have [the Sentry gem][] (`~> 1.2`) installed before configuring
@@ -463,24 +494,22 @@ stoplight = Stoplight("test-#{rand}") { ... }
463
494
 
464
495
  ## Credits
465
496
 
466
- Stoplight is brought to you by [@camdez][] and [@tfausak][] from [@OrgSync][].
467
- A [complete list of contributors][] is available on GitHub. We were inspired by
468
- Martin Fowler's [CircuitBreaker][] article.
497
+ Stoplight is brought to you by [@camdez][] and [@tfausak][] from [@OrgSync][]. [@bolshakov][] is the current
498
+ maintainer of the gem. A [complete list of contributors][] is available on GitHub. We were inspired by
499
+ Martin Fowler's [CircuitBreaker][] article.
469
500
 
470
501
  Stoplight is licensed under [the MIT License][].
471
502
 
472
- [Stoplight]: https://github.com/orgsync/stoplight
503
+ [Stoplight]: https://github.com/bolshakov/stoplight
473
504
  [Version badge]: https://img.shields.io/gem/v/stoplight.svg?label=version
474
505
  [version]: https://rubygems.org/gems/stoplight
475
- [Build badge]: https://img.shields.io/travis/orgsync/stoplight/master.svg?label=build
476
- [build]: https://travis-ci.org/orgsync/stoplight
477
- [Coverage badge]: https://img.shields.io/coveralls/orgsync/stoplight/master.svg?label=coverage
478
- [coverage]: https://coveralls.io/r/orgsync/stoplight
479
- [Climate badge]: https://img.shields.io/codeclimate/github/orgsync/stoplight.svg?label=climate
480
- [climate]: https://codeclimate.com/github/orgsync/stoplight
481
- [Dependencies badge]: https://img.shields.io/gemnasium/orgsync/stoplight.svg?label=dependencies
482
- [dependencies]: https://gemnasium.com/orgsync/stoplight
483
- [stoplight-admin]: https://github.com/orgsync/stoplight-admin
506
+ [Build badge]: https://github.com/bolshakov/stoplight/workflows/Specs/badge.svg
507
+ [build]: https://github.com/bolshakov/stoplight/actions?query=branch%3Amaster
508
+ [Coverage badge]: https://img.shields.io/coveralls/bolshakov/stoplight/master.svg?label=coverage
509
+ [coverage]: https://coveralls.io/r/bolshakov/stoplight
510
+ [Climate badge]: https://api.codeclimate.com/v1/badges/3451c2d281ffa345441a/maintainability
511
+ [climate]: https://codeclimate.com/github/bolshakov/stoplight
512
+ [stoplight-admin]: https://github.com/bolshakov/stoplight-admin
484
513
  [Semantic Versioning]: http://semver.org/spec/v2.0.0.html
485
514
  [the change log]: CHANGELOG.md
486
515
  [the notifiers section]: #notifiers
@@ -490,11 +519,14 @@ Stoplight is licensed under [the MIT License][].
490
519
  [the HipChat gem]: https://rubygems.org/gems/hipchat
491
520
  [the Honeybadger gem]: https://rubygems.org/gems/honeybadger
492
521
  [the Logger class]: http://ruby-doc.org/stdlib-2.2.3/libdoc/logger/rdoc/Logger.html
522
+ [the Rollbar gem]: https://rubygems.org/gems/rollbar
493
523
  [the Sentry gem]: https://rubygems.org/gems/sentry-raven
494
524
  [the Slack gem]: https://rubygems.org/gems/slack-notifier
525
+ [the Pagerduty gem]: https://rubygems.org/gems/pagerduty
495
526
  [@camdez]: https://github.com/camdez
496
527
  [@tfausak]: https://github.com/tfausak
497
528
  [@orgsync]: https://github.com/OrgSync
498
- [complete list of contributors]: https://github.com/orgsync/stoplight/graphs/contributors
529
+ [@bolshakov]: https://github.com/bolshakov
530
+ [complete list of contributors]: https://github.com/bolshakov/stoplight/graphs/contributors
499
531
  [CircuitBreaker]: http://martinfowler.com/bliki/CircuitBreaker.html
500
532
  [the MIT license]: LICENSE.md
@@ -1,9 +1,9 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Color
5
- GREEN = 'green'.freeze
6
- YELLOW = 'yellow'.freeze
7
- RED = 'red'.freeze
5
+ GREEN = 'green'
6
+ YELLOW = 'yellow'
7
+ RED = 'red'
8
8
  end
9
9
  end
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module DataStore
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'monitor'
4
4
 
@@ -1,11 +1,11 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module DataStore
5
5
  # @see Base
6
6
  class Redis < Base
7
- KEY_PREFIX = 'stoplight'.freeze
8
- KEY_SEPARATOR = ':'.freeze
7
+ KEY_PREFIX = 'stoplight'
8
+ KEY_SEPARATOR = ':'
9
9
 
10
10
  # @param redis [::Redis]
11
11
  def initialize(redis)
@@ -25,9 +25,9 @@ module Stoplight
25
25
  end
26
26
 
27
27
  def get_all(light)
28
- failures, state = @redis.multi do
29
- query_failures(light)
30
- @redis.hget(states_key, light.name)
28
+ failures, state = @redis.multi do |transaction|
29
+ query_failures(light, transaction: transaction)
30
+ transaction.hget(states_key, light.name)
31
31
  end
32
32
 
33
33
  [
@@ -41,18 +41,18 @@ module Stoplight
41
41
  end
42
42
 
43
43
  def record_failure(light, failure)
44
- size, = @redis.multi do
45
- @redis.lpush(failures_key(light), failure.to_json)
46
- @redis.ltrim(failures_key(light), 0, light.threshold - 1)
44
+ size, = @redis.multi do |transaction|
45
+ transaction.lpush(failures_key(light), failure.to_json)
46
+ transaction.ltrim(failures_key(light), 0, light.threshold - 1)
47
47
  end
48
48
 
49
49
  size
50
50
  end
51
51
 
52
52
  def clear_failures(light)
53
- failures, = @redis.multi do
54
- query_failures(light)
55
- @redis.del(failures_key(light))
53
+ failures, = @redis.multi do |transaction|
54
+ query_failures(light, transaction: transaction)
55
+ transaction.del(failures_key(light))
56
56
  end
57
57
 
58
58
  normalize_failures(failures, light.error_notifier)
@@ -68,9 +68,9 @@ module Stoplight
68
68
  end
69
69
 
70
70
  def clear_state(light)
71
- state, = @redis.multi do
72
- query_state(light)
73
- @redis.hdel(states_key, light.name)
71
+ state, = @redis.multi do |transaction|
72
+ query_state(light, transaction: transaction)
73
+ transaction.hdel(states_key, light.name)
74
74
  end
75
75
 
76
76
  normalize_state(state)
@@ -78,23 +78,21 @@ module Stoplight
78
78
 
79
79
  private
80
80
 
81
- def query_failures(light)
82
- @redis.lrange(failures_key(light), 0, -1)
81
+ def query_failures(light, transaction: @redis)
82
+ transaction.lrange(failures_key(light), 0, -1)
83
83
  end
84
84
 
85
85
  def normalize_failures(failures, error_notifier)
86
86
  failures.map do |json|
87
- begin
88
- Failure.from_json(json)
89
- rescue => error
90
- error_notifier.call(error)
91
- Failure.from_error(error)
92
- end
87
+ Failure.from_json(json)
88
+ rescue StandardError => e
89
+ error_notifier.call(e)
90
+ Failure.from_error(e)
93
91
  end
94
92
  end
95
93
 
96
- def query_state(light)
97
- @redis.hget(states_key, light.name)
94
+ def query_state(light, transaction: @redis)
95
+ transaction.hget(states_key, light.name)
98
96
  end
99
97
 
100
98
  def normalize_state(state)
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module DataStore # rubocop:disable Style/Documentation
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Default
@@ -6,9 +6,9 @@ module Stoplight
6
6
 
7
7
  DATA_STORE = DataStore::Memory.new
8
8
 
9
- ERROR_HANDLER = -> (error, handler) { handler.call(error) }
9
+ ERROR_HANDLER = ->(error, handler) { handler.call(error) }
10
10
 
11
- ERROR_NOTIFIER = -> (error) { warn error }
11
+ ERROR_NOTIFIER = ->(error) { warn error }
12
12
 
13
13
  FALLBACK = nil
14
14
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Error
@@ -1,11 +1,11 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
4
  require 'time'
5
5
 
6
6
  module Stoplight
7
7
  class Failure # rubocop:disable Style/Documentation
8
- TIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%N%:z'.freeze
8
+ TIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%N%:z'
9
9
 
10
10
  # @return [String]
11
11
  attr_reader :error_class
@@ -52,14 +52,18 @@ module Stoplight
52
52
  time == other.time
53
53
  end
54
54
 
55
+ # @param options [Object, nil]
55
56
  # @return [String]
56
- def to_json
57
+ def to_json(options = nil)
57
58
  JSON.generate(
58
- error: {
59
- class: error_class,
60
- message: error_message
59
+ {
60
+ error: {
61
+ class: error_class,
62
+ message: error_message
63
+ },
64
+ time: time.strftime(TIME_FORMAT)
61
65
  },
62
- time: time.strftime(TIME_FORMAT)
66
+ options
63
67
  )
64
68
  end
65
69
  end
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  class Light
@@ -44,23 +44,25 @@ module Stoplight
44
44
 
45
45
  def run_red
46
46
  raise Error::RedLight, name unless fallback
47
+
47
48
  fallback.call(nil)
48
49
  end
49
50
 
50
51
  def run_code(on_success, on_failure)
51
52
  result = code.call
52
53
  failures = clear_failures
53
- on_success.call(failures) if on_success
54
+ on_success&.call(failures)
54
55
  result
55
- rescue Exception => error # rubocop:disable Lint/RescueException
56
- handle_error(error, on_failure)
56
+ rescue Exception => e # rubocop:disable Lint/RescueException
57
+ handle_error(e, on_failure)
57
58
  end
58
59
 
59
60
  def handle_error(error, on_failure)
60
61
  error_handler.call(error, Error::HANDLER)
61
62
  size = record_failure(error)
62
- on_failure.call(size, error) if on_failure
63
+ on_failure&.call(size, error)
63
64
  raise error unless fallback
65
+
64
66
  fallback.call(error)
65
67
  end
66
68
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  class Light # rubocop:disable Style/Documentation
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Notifier
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Notifier
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Notifier
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Notifier
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Notifier
@@ -34,7 +34,7 @@ module Stoplight
34
34
  h = options.merge(
35
35
  api_key: api_key,
36
36
  error_message: message,
37
- backtrace: (error.backtrace if error)
37
+ backtrace: error&.backtrace
38
38
  )
39
39
  ::Honeybadger.notify(h)
40
40
  message
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Notifier
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Notifier
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Notifier
5
+ # @see Base
6
+ class Pagerduty < Base
7
+ include Generic
8
+
9
+ # @return [::Pagerduty]
10
+ def pagerduty
11
+ @object
12
+ end
13
+
14
+ private
15
+
16
+ def put(message)
17
+ pagerduty.trigger(message)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Notifier
@@ -30,7 +30,7 @@ module Stoplight
30
30
 
31
31
  h = options.merge(
32
32
  configuration: configuration,
33
- backtrace: (error.backtrace if error)
33
+ backtrace: error&.backtrace
34
34
  )
35
35
  ::Raven.capture_message(message, h)
36
36
  message
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Notifier
5
+ # @see Base
6
+ class Rollbar < Base
7
+ DEFAULT_OPTIONS = {
8
+ severity: 'info'
9
+ }.freeze
10
+
11
+ StoplightStatusChange = Class.new(Error::Base)
12
+
13
+ # @return [Proc]
14
+ attr_reader :formatter
15
+ # @return [::Rollbar]
16
+ attr_reader :rollbar
17
+ # @return [Hash{Symbol => Object}]
18
+ attr_reader :options
19
+
20
+ # @param rollbar [::Rollbar]
21
+ # @param formatter [Proc, nil]
22
+ # @param options [Hash{Symbol => Object}]
23
+ # @option options [String] :severity
24
+ def initialize(rollbar, formatter = nil, options = {})
25
+ @rollbar = rollbar
26
+ @formatter = formatter || Default::FORMATTER
27
+ @options = DEFAULT_OPTIONS.merge(options)
28
+ end
29
+
30
+ def notify(light, from_color, to_color, error)
31
+ formatter.call(light, from_color, to_color, error).tap do |message|
32
+ severity = options.fetch(:severity)
33
+ exception = StoplightStatusChange.new(message)
34
+ rollbar.__send__(severity, exception)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Notifier
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module Notifier # rubocop:disable Style/Documentation
@@ -1,9 +1,9 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
4
  module State
5
- UNLOCKED = 'unlocked'.freeze
6
- LOCKED_GREEN = 'locked_green'.freeze
7
- LOCKED_RED = 'locked_red'.freeze
5
+ UNLOCKED = 'unlocked'
6
+ LOCKED_GREEN = 'locked_green'
7
+ LOCKED_RED = 'locked_red'
8
8
  end
9
9
  end
@@ -1,5 +1,5 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
- VERSION = Gem::Version.new('2.1.3')
4
+ VERSION = Gem::Version.new('3.0.0')
5
5
  end
data/lib/stoplight.rb CHANGED
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Stoplight # rubocop:disable Style/Documentation
4
4
  end
@@ -24,7 +24,9 @@ require 'stoplight/notifier/hip_chat'
24
24
  require 'stoplight/notifier/honeybadger'
25
25
  require 'stoplight/notifier/io'
26
26
  require 'stoplight/notifier/logger'
27
+ require 'stoplight/notifier/pagerduty'
27
28
  require 'stoplight/notifier/raven'
29
+ require 'stoplight/notifier/rollbar'
28
30
  require 'stoplight/notifier/slack'
29
31
 
30
32
  require 'stoplight/default'
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,6 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require 'coveralls'
4
- Coveralls.wear!
3
+ require 'simplecov'
5
4
 
6
5
  require 'stoplight'
7
6
  require 'timecop'
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
  require 'fakeredis'
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -74,7 +74,7 @@ RSpec.describe Stoplight::Default do
74
74
 
75
75
  describe '::THRESHOLD' do
76
76
  it 'is an integer' do
77
- expect(Stoplight::Default::THRESHOLD).to be_a(Fixnum)
77
+ expect(Stoplight::Default::THRESHOLD).to be_a(Integer)
78
78
  end
79
79
  end
80
80
  end
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -89,6 +89,11 @@ RSpec.describe Stoplight::Failure do
89
89
  expect(described_class.new(error_class, error_message, time).to_json)
90
90
  .to eql(json)
91
91
  end
92
+
93
+ it 'generates JSON with options' do
94
+ expect(described_class.new(error_class, error_message, time).to_json({}))
95
+ .to eql(json)
96
+ end
92
97
  end
93
98
 
94
99
  describe '::TIME_FORMAT' do
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
  require 'stringio'
@@ -8,7 +8,7 @@ RSpec.describe Stoplight::Light::Runnable do
8
8
 
9
9
  let(:code) { -> { code_result } }
10
10
  let(:code_result) { random_string }
11
- let(:fallback) { -> (_) { fallback_result } }
11
+ let(:fallback) { ->(_) { fallback_result } }
12
12
  let(:fallback_result) { random_string }
13
13
  let(:name) { random_string }
14
14
 
@@ -123,12 +123,10 @@ RSpec.describe Stoplight::Light::Runnable do
123
123
 
124
124
  context 'with an error handler' do
125
125
  let(:result) do
126
- begin
127
- subject.run
128
- expect(false).to be(true)
129
- rescue error.class
130
- expect(true).to be(true)
131
- end
126
+ subject.run
127
+ expect(false).to be(true)
128
+ rescue error.class
129
+ expect(true).to be(true)
132
130
  end
133
131
 
134
132
  it 'records the failure when the handler does nothing' do
@@ -171,7 +169,7 @@ RSpec.describe Stoplight::Light::Runnable do
171
169
 
172
170
  context 'when the data store is failing' do
173
171
  let(:data_store) { Object.new }
174
- let(:error_notifier) { -> (_) {} }
172
+ let(:error_notifier) { ->(_) {} }
175
173
 
176
174
  before do
177
175
  subject
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
  require 'stringio'
@@ -42,7 +42,7 @@ RSpec.describe Stoplight::Light do
42
42
  after { described_class.default_error_notifier = @default_error_notifier }
43
43
 
44
44
  it 'sets the error notifier' do
45
- default_error_notifier = -> (_) {}
45
+ default_error_notifier = ->(_) {}
46
46
  described_class.default_error_notifier = default_error_notifier
47
47
  expect(described_class.default_error_notifier)
48
48
  .to eql(default_error_notifier)
@@ -140,7 +140,7 @@ RSpec.describe Stoplight::Light do
140
140
 
141
141
  describe '#with_error_handler' do
142
142
  it 'sets the error handler' do
143
- error_handler = -> (_, _) {}
143
+ error_handler = ->(_, _) {}
144
144
  light.with_error_handler(&error_handler)
145
145
  expect(light.error_handler).to eql(error_handler)
146
146
  end
@@ -148,7 +148,7 @@ RSpec.describe Stoplight::Light do
148
148
 
149
149
  describe '#with_error_notifier' do
150
150
  it 'sets the error notifier' do
151
- error_notifier = -> (_) {}
151
+ error_notifier = ->(_) {}
152
152
  light.with_error_notifier(&error_notifier)
153
153
  expect(light.error_notifier).to eql(error_notifier)
154
154
  end
@@ -156,7 +156,7 @@ RSpec.describe Stoplight::Light do
156
156
 
157
157
  describe '#with_fallback' do
158
158
  it 'sets the fallback' do
159
- fallback = -> (_) {}
159
+ fallback = ->(_) {}
160
160
  light.with_fallback(&fallback)
161
161
  expect(light.fallback).to eql(fallback)
162
162
  end
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -7,8 +7,6 @@ module Bugsnag
7
7
  end
8
8
 
9
9
  RSpec.describe Stoplight::Notifier::Bugsnag do
10
- StoplightStatusChange = Stoplight::Notifier::Bugsnag::StoplightStatusChange
11
-
12
10
  it 'is a class' do
13
11
  expect(described_class).to be_a(Class)
14
12
  end
@@ -65,7 +63,7 @@ RSpec.describe Stoplight::Notifier::Bugsnag do
65
63
  end
66
64
 
67
65
  before do
68
- status_change = StoplightStatusChange.new(message)
66
+ status_change = described_class::StoplightStatusChange.new(message)
69
67
  expect(bugsnag).to receive(:notify).with(status_change, severity: 'info')
70
68
  end
71
69
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,12 +1,11 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
5
  # require 'hipchat'
6
6
  module HipChat
7
7
  class Client
8
- def initialize(*)
9
- end
8
+ def initialize(*); end
10
9
  end
11
10
  end
12
11
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
  require 'stringio'
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
  require 'logger'
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'pagerduty'
5
+
6
+ RSpec.describe Stoplight::Notifier::Pagerduty do
7
+ it_behaves_like 'a generic notifier'
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 '#pagerduty' do
18
+ it 'reads Pagerduty client' do
19
+ pagerduty = Pagerduty.new('WEBHOOK_URL')
20
+ expect(described_class.new(pagerduty).pagerduty).to eql(pagerduty)
21
+ end
22
+ end
23
+
24
+ describe '#notify' do
25
+ let(:light) { Stoplight::Light.new(name, &code) }
26
+ let(:name) { ('a'..'z').to_a.shuffle.join }
27
+ let(:code) { -> {} }
28
+ let(:from_color) { Stoplight::Color::GREEN }
29
+ let(:to_color) { Stoplight::Color::RED }
30
+ let(:notifier) { described_class.new(pagerduty) }
31
+ let(:pagerduty) { double(Pagerduty).as_null_object }
32
+
33
+ it 'pings Pagerduty' do
34
+ error = nil
35
+ message = notifier.formatter.call(light, from_color, to_color, error)
36
+ expect(pagerduty).to receive(:trigger).with(message)
37
+ notifier.notify(light, from_color, to_color, error)
38
+ end
39
+ end
40
+ end
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ # require 'rollbar'
6
+ module Rollbar
7
+ end
8
+
9
+ RSpec.describe Stoplight::Notifier::Rollbar do
10
+ it 'is a class' do
11
+ expect(described_class).to be_a(Class)
12
+ end
13
+
14
+ it 'is a subclass of Base' do
15
+ expect(described_class).to be < Stoplight::Notifier::Base
16
+ end
17
+
18
+ describe '#formatter' do
19
+ it 'is initially the default' do
20
+ expect(described_class.new(nil, nil).formatter)
21
+ .to eql(Stoplight::Default::FORMATTER)
22
+ end
23
+
24
+ it 'reads the formatter' do
25
+ formatter = proc {}
26
+ expect(described_class.new(nil, formatter).formatter)
27
+ .to eql(formatter)
28
+ end
29
+ end
30
+
31
+ describe '#options' do
32
+ it 'is initially the default' do
33
+ expect(described_class.new(nil, nil).options)
34
+ .to eql(Stoplight::Notifier::Rollbar::DEFAULT_OPTIONS)
35
+ end
36
+
37
+ it 'reads the options' do
38
+ options = { key: :value }
39
+ expect(described_class.new(nil, nil, options).options)
40
+ .to eql(Stoplight::Notifier::Rollbar::DEFAULT_OPTIONS.merge(options))
41
+ end
42
+ end
43
+
44
+ describe '#rollbar' do
45
+ it 'reads the Rollbar client' do
46
+ client = Rollbar
47
+ expect(described_class.new(client, nil).rollbar)
48
+ .to eql(client)
49
+ end
50
+ end
51
+
52
+ describe '#notify' do
53
+ let(:light) { Stoplight::Light.new(name, &code) }
54
+ let(:name) { ('a'..'z').to_a.shuffle.join }
55
+ let(:code) { -> {} }
56
+ let(:from_color) { Stoplight::Color::GREEN }
57
+ let(:to_color) { Stoplight::Color::RED }
58
+ let(:notifier) { described_class.new(rollbar) }
59
+ let(:rollbar) { Rollbar }
60
+
61
+ subject(:result) do
62
+ notifier.notify(light, from_color, to_color, error)
63
+ end
64
+
65
+ before do
66
+ status_change = described_class::StoplightStatusChange.new(message)
67
+ expect(rollbar).to receive(:info).with(status_change)
68
+ end
69
+
70
+ context 'when no error given' do
71
+ let(:error) { nil }
72
+
73
+ it 'logs message' do
74
+ expect(result).to eq(message)
75
+ end
76
+ end
77
+
78
+ context 'when message with an error given' do
79
+ let(:error) { ZeroDivisionError.new('divided by 0') }
80
+
81
+ it 'logs message' do
82
+ expect(result).to eq(message)
83
+ end
84
+ end
85
+
86
+ def message
87
+ notifier.formatter.call(light, from_color, to_color, error)
88
+ end
89
+ end
90
+ end
@@ -1,12 +1,11 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
5
  # require 'slack-notifier'
6
6
  module Slack
7
7
  class Notifier
8
- def initialize(*)
9
- end
8
+ def initialize(*); end
10
9
  end
11
10
  end
12
11
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stoplight
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.3
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Desautels
8
8
  - Taylor Fausak
9
9
  - Justin Steffy
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-04-01 00:00:00.000000000 Z
13
+ date: 2022-02-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: benchmark-ips
@@ -40,20 +40,6 @@ dependencies:
40
40
  - - "~>"
41
41
  - !ruby/object:Gem::Version
42
42
  version: '4.0'
43
- - !ruby/object:Gem::Dependency
44
- name: coveralls
45
- requirement: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - "~>"
48
- - !ruby/object:Gem::Version
49
- version: '0.8'
50
- type: :development
51
- prerelease: false
52
- version_requirements: !ruby/object:Gem::Requirement
53
- requirements:
54
- - - "~>"
55
- - !ruby/object:Gem::Version
56
- version: '0.8'
57
43
  - !ruby/object:Gem::Dependency
58
44
  name: fakeredis
59
45
  requirement: !ruby/object:Gem::Requirement
@@ -97,33 +83,33 @@ dependencies:
97
83
  - !ruby/object:Gem::Version
98
84
  version: '2.5'
99
85
  - !ruby/object:Gem::Dependency
100
- name: sentry-raven
86
+ name: pagerduty
101
87
  requirement: !ruby/object:Gem::Requirement
102
88
  requirements:
103
89
  - - "~>"
104
90
  - !ruby/object:Gem::Version
105
- version: '1.2'
91
+ version: 2.1.1
106
92
  type: :development
107
93
  prerelease: false
108
94
  version_requirements: !ruby/object:Gem::Requirement
109
95
  requirements:
110
96
  - - "~>"
111
97
  - !ruby/object:Gem::Version
112
- version: '1.2'
98
+ version: 2.1.1
113
99
  - !ruby/object:Gem::Dependency
114
100
  name: rake
115
101
  requirement: !ruby/object:Gem::Requirement
116
102
  requirements:
117
103
  - - "~>"
118
104
  - !ruby/object:Gem::Version
119
- version: '11.1'
105
+ version: '13.0'
120
106
  type: :development
121
107
  prerelease: false
122
108
  version_requirements: !ruby/object:Gem::Requirement
123
109
  requirements:
124
110
  - - "~>"
125
111
  - !ruby/object:Gem::Version
126
- version: '11.1'
112
+ version: '13.0'
127
113
  - !ruby/object:Gem::Dependency
128
114
  name: redis
129
115
  requirement: !ruby/object:Gem::Requirement
@@ -158,14 +144,56 @@ dependencies:
158
144
  requirements:
159
145
  - - "~>"
160
146
  - !ruby/object:Gem::Version
161
- version: 0.40.0
147
+ version: 1.0.0
148
+ type: :development
149
+ prerelease: false
150
+ version_requirements: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - "~>"
153
+ - !ruby/object:Gem::Version
154
+ version: 1.0.0
155
+ - !ruby/object:Gem::Dependency
156
+ name: sentry-raven
157
+ requirement: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - "~>"
160
+ - !ruby/object:Gem::Version
161
+ version: '1.2'
162
+ type: :development
163
+ prerelease: false
164
+ version_requirements: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - "~>"
167
+ - !ruby/object:Gem::Version
168
+ version: '1.2'
169
+ - !ruby/object:Gem::Dependency
170
+ name: simplecov
171
+ requirement: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - "~>"
174
+ - !ruby/object:Gem::Version
175
+ version: '0.21'
176
+ type: :development
177
+ prerelease: false
178
+ version_requirements: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - "~>"
181
+ - !ruby/object:Gem::Version
182
+ version: '0.21'
183
+ - !ruby/object:Gem::Dependency
184
+ name: simplecov-lcov
185
+ requirement: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '0.8'
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.40.0
196
+ version: '0.8'
169
197
  - !ruby/object:Gem::Dependency
170
198
  name: slack-notifier
171
199
  requirement: !ruby/object:Gem::Requirement
@@ -225,7 +253,9 @@ files:
225
253
  - lib/stoplight/notifier/honeybadger.rb
226
254
  - lib/stoplight/notifier/io.rb
227
255
  - lib/stoplight/notifier/logger.rb
256
+ - lib/stoplight/notifier/pagerduty.rb
228
257
  - lib/stoplight/notifier/raven.rb
258
+ - lib/stoplight/notifier/rollbar.rb
229
259
  - lib/stoplight/notifier/slack.rb
230
260
  - lib/stoplight/state.rb
231
261
  - lib/stoplight/version.rb
@@ -247,17 +277,19 @@ files:
247
277
  - spec/stoplight/notifier/honeybadger_spec.rb
248
278
  - spec/stoplight/notifier/io_spec.rb
249
279
  - spec/stoplight/notifier/logger_spec.rb
280
+ - spec/stoplight/notifier/pagerduty_spec.rb
250
281
  - spec/stoplight/notifier/raven_spec.rb
282
+ - spec/stoplight/notifier/rollbar_spec.rb
251
283
  - spec/stoplight/notifier/slack_spec.rb
252
284
  - spec/stoplight/notifier_spec.rb
253
285
  - spec/stoplight/state_spec.rb
254
286
  - spec/stoplight/version_spec.rb
255
287
  - spec/stoplight_spec.rb
256
- homepage: https://github.com/orgsync/stoplight
288
+ homepage: https://github.com/bolshakov/stoplight
257
289
  licenses:
258
290
  - MIT
259
291
  metadata: {}
260
- post_install_message:
292
+ post_install_message:
261
293
  rdoc_options: []
262
294
  require_paths:
263
295
  - lib
@@ -265,40 +297,41 @@ required_ruby_version: !ruby/object:Gem::Requirement
265
297
  requirements:
266
298
  - - ">="
267
299
  - !ruby/object:Gem::Version
268
- version: '2.1'
300
+ version: '2.6'
269
301
  required_rubygems_version: !ruby/object:Gem::Requirement
270
302
  requirements:
271
303
  - - ">="
272
304
  - !ruby/object:Gem::Version
273
305
  version: '0'
274
306
  requirements: []
275
- rubyforge_project:
276
- rubygems_version: 2.5.2
277
- signing_key:
307
+ rubygems_version: 3.2.3
308
+ signing_key:
278
309
  specification_version: 4
279
310
  summary: Traffic control for code.
280
311
  test_files:
281
312
  - spec/spec_helper.rb
282
- - spec/stoplight_spec.rb
313
+ - spec/stoplight/color_spec.rb
314
+ - spec/stoplight/data_store/base_spec.rb
315
+ - spec/stoplight/data_store/memory_spec.rb
316
+ - spec/stoplight/data_store/redis_spec.rb
317
+ - spec/stoplight/data_store_spec.rb
318
+ - spec/stoplight/default_spec.rb
283
319
  - spec/stoplight/error_spec.rb
284
320
  - spec/stoplight/failure_spec.rb
285
- - spec/stoplight/notifier/raven_spec.rb
286
- - spec/stoplight/notifier/io_spec.rb
287
- - spec/stoplight/notifier/logger_spec.rb
288
- - spec/stoplight/notifier/honeybadger_spec.rb
289
- - spec/stoplight/notifier/generic_spec.rb
290
- - spec/stoplight/notifier/slack_spec.rb
321
+ - spec/stoplight/light/runnable_spec.rb
322
+ - spec/stoplight/light_spec.rb
291
323
  - spec/stoplight/notifier/base_spec.rb
292
324
  - spec/stoplight/notifier/bugsnag_spec.rb
325
+ - spec/stoplight/notifier/generic_spec.rb
293
326
  - spec/stoplight/notifier/hip_chat_spec.rb
294
- - spec/stoplight/version_spec.rb
295
- - spec/stoplight/state_spec.rb
327
+ - spec/stoplight/notifier/honeybadger_spec.rb
328
+ - spec/stoplight/notifier/io_spec.rb
329
+ - spec/stoplight/notifier/logger_spec.rb
330
+ - spec/stoplight/notifier/pagerduty_spec.rb
331
+ - spec/stoplight/notifier/raven_spec.rb
332
+ - spec/stoplight/notifier/rollbar_spec.rb
333
+ - spec/stoplight/notifier/slack_spec.rb
296
334
  - spec/stoplight/notifier_spec.rb
297
- - spec/stoplight/color_spec.rb
298
- - spec/stoplight/default_spec.rb
299
- - spec/stoplight/data_store_spec.rb
300
- - spec/stoplight/data_store/memory_spec.rb
301
- - spec/stoplight/data_store/redis_spec.rb
302
- - spec/stoplight/data_store/base_spec.rb
303
- - spec/stoplight/light/runnable_spec.rb
304
- - spec/stoplight/light_spec.rb
335
+ - spec/stoplight/state_spec.rb
336
+ - spec/stoplight/version_spec.rb
337
+ - spec/stoplight_spec.rb