flipper-echo 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d0193b01d3747866567392b00529405385d4b23
4
- data.tar.gz: 03d2d537df9c51aca849cc279245dd39f63835cb
3
+ metadata.gz: 8b2f87cd93693142ff67b6ceeed1444b6f7b012f
4
+ data.tar.gz: 31f38685142d8e670acaf735beaea1432810b873
5
5
  SHA512:
6
- metadata.gz: 361febaf3cf8772c5eb2f723a3896068c00588e9f6e2aaf2003d3a52fb00a65356ba0dd3c94fb70b08767bfacdf3dd209e5f1e649140c95ec3b7b0b35d355982
7
- data.tar.gz: 94c0a649e23ff84a9b9c41fce70c1145c3a24a9222377c073e237c4fae93ceabb7a12f1fa82cfdd4f8594d2a21c89d220e80f11256eb57c01c39b26ad25ea378
6
+ metadata.gz: 5d465bf8cf158efb1f6edb3c57ef6f952d9f6b2667cf39c59a1040884b7cbab83b69f2bd33758bd50187b47604b9385b635e65894bd91dcd92695e61582c59bb
7
+ data.tar.gz: 318e9de9d3ce75c78bd78d2802fecd91eb855f0120b55793428e7a3ee01896f3f56cbf5c004ed5855ba524969a931613f03cf1c4aec1e3faef2113167a0400ed
data/.gitignore CHANGED
@@ -12,4 +12,5 @@
12
12
  *.o
13
13
  *.a
14
14
  mkmf.log
15
+ assets
15
16
  *.gem
data/README.md CHANGED
@@ -1,12 +1,15 @@
1
1
  # Flipper::Echo
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/flipper-echo.svg)](http://badge.fury.io/rb/flipper-echo)
4
+
3
5
  This gem adds a simple callback interface for
4
6
  [Flipper](https://github.com/jnunemaker/flipper) adapter events.
5
7
 
6
8
  For example, when a Flipper feature is changed, you can:
7
9
 
8
- * send a Slack notification
10
+ * send a Slack notification (built-in)
9
11
  * write the change to a database or log file
12
+ * notify a performance monitoring application
10
13
  * send a YO
11
14
 
12
15
  ## Installation
@@ -34,9 +37,9 @@ normally would (any adapter will do), e.g.:
34
37
  FLIPPER = Flipper.new(Flipper::Adapters::Memory.new)
35
38
  ```
36
39
 
37
- Then configure `Flipper::Echo`:
40
+ Then configure this gem in any of the following ways:
38
41
 
39
- #### Option 1: handle event with a proc
42
+ #### Handle event with a proc
40
43
 
41
44
  ```ruby
42
45
  Flipper::Echo.configure do |config|
@@ -50,12 +53,12 @@ Flipper::Echo.configure do |config|
50
53
  end
51
54
  ```
52
55
 
53
- #### Option 2: handle event with a notifier class
56
+ #### Handle event with an object
54
57
 
55
- `Flipper::Echo` can also use any object that has a `notify` method:
58
+ You can provide any Ruby object with a `notify` method:
56
59
 
57
60
  ```ruby
58
- class FlipperNotifier
61
+ class CustomNotifier
59
62
  def notify(event)
60
63
  # Do something with the event...
61
64
  end
@@ -63,10 +66,46 @@ end
63
66
 
64
67
  Flipper::Echo.configure do |config|
65
68
  config.flipper = FLIPPER
66
- config.notifier = FlipperNotifier.new
69
+ config.notifier = CustomNotifier.new
70
+ end
71
+ ```
72
+
73
+ #### Configure multiple notifiers
74
+
75
+ ```ruby
76
+ Flipper::Echo.configure do |config|
77
+ config.flipper = FLIPPER
78
+
79
+ config.notifiers << NewrelicNotifier.new
80
+ config.notifiers << GraphiteNotifier.new
81
+ config.notifiers << Flipper::Echo::Stdout::Notifier.new
82
+ end
83
+ ```
84
+
85
+ ## Built-in notifiers
86
+
87
+ #### Slack
88
+
89
+ First [create a Slack webhook url](https://slack.com/services/new/incoming-webhook),
90
+ then use it in your configuration:
91
+
92
+ ```ruby
93
+ Flipper::Echo.configure do |config|
94
+ config.notifiers << Flipper::Echo::Slack::Notifier.new(
95
+ 'https://hooks.slack.com/your/webhook...', channel: '#eng')
67
96
  end
68
97
  ```
69
98
 
99
+ ![Slack example 1](https://s3-us-west-2.amazonaws.com/mode.production/flipper-echo/prod-search-admins.png)
100
+
101
+ ![Slack example 2](https://s3-us-west-2.amazonaws.com/mode.production/flipper-echo/prod-risky-actors.png)
102
+
103
+ ![Slack example 3](https://s3-us-west-2.amazonaws.com/mode.production/flipper-echo/staging-rolled-out-removed.png)
104
+
105
+ ## Documentation
106
+
107
+ [http://www.rubydoc.info/github/mode/flipper-echo/master](http://www.rubydoc.info/github/mode/flipper-echo/master)
108
+
70
109
  ## Contributing
71
110
 
72
111
  1. Fork it ( https://github.com/mode/flipper-echo/fork )
@@ -74,3 +113,7 @@ end
74
113
  3. Commit your changes (`git commit -am 'Add some feature'`)
75
114
  4. Push to the branch (`git push origin my-new-feature`)
76
115
  5. Create a new Pull Request
116
+
117
+ ## Actual screenshots
118
+
119
+ ![Newrelic example 1](https://s3-us-west-2.amazonaws.com/mode.production/flipper-echo/actual-newrelic-screenshot.png)
data/lib/flipper/echo.rb CHANGED
@@ -2,6 +2,8 @@
2
2
  #
3
3
  require 'flipper/echo/configuration'
4
4
  require 'flipper/echo/event'
5
+ require 'flipper/echo/slack'
6
+ require 'flipper/echo/stdout'
5
7
  require 'flipper/echo/version'
6
8
 
7
9
  # Flipper namespace
@@ -32,7 +34,7 @@ module Flipper
32
34
  def enable(feature, gate, target)
33
35
  super.tap do
34
36
  Flipper::Echo::Event.new(
35
- feature, :enable, gate: gate, target: target).notify
37
+ feature, :enabled, gate: gate, target: target).notify
36
38
  end
37
39
  end
38
40
 
@@ -41,20 +43,20 @@ module Flipper
41
43
  def disable(feature, gate, target)
42
44
  super.tap do
43
45
  Flipper::Echo::Event.new(
44
- feature, :disable, gate: gate, target: target).notify
46
+ feature, :disabled, gate: gate, target: target).notify
45
47
  end
46
48
  end
47
49
 
48
50
  # Notify adapter remove events
49
51
  #
50
52
  def remove(feature)
51
- super.tap { Flipper::Echo::Event.new(feature, :remove).notify }
53
+ super.tap { Flipper::Echo::Event.new(feature, :removed).notify }
52
54
  end
53
55
 
54
56
  # Notify adapter clear events
55
57
  #
56
58
  def clear(feature)
57
- super.tap { Flipper::Echo::Event.new(feature, :clear).notify }
59
+ super.tap { Flipper::Echo::Event.new(feature, :cleared).notify }
58
60
  end
59
61
  end
60
62
  end
@@ -10,7 +10,33 @@ module Flipper
10
10
  # intended behavior.
11
11
  #
12
12
  class Configuration
13
- attr_accessor :notifier
13
+ # All configured notifiers
14
+ #
15
+ # @return [Array]
16
+ #
17
+ def notifiers
18
+ @notifiers ||= []
19
+ end
20
+
21
+ # Convenience method for assigning a single notifier
22
+ #
23
+ # @return [Array] all notifiers
24
+ #
25
+ def notifier=(notifier)
26
+ notifiers << notifier
27
+ end
28
+
29
+ # Optional environment name
30
+ #
31
+ attr_writer :environment
32
+
33
+ # Configured environment name
34
+ #
35
+ # @return [String]
36
+ #
37
+ def environment
38
+ @environment ||= ENV['FLIPPER_ECHO_ENVIRONMENT']
39
+ end
14
40
 
15
41
  # Assign Flipper instance
16
42
  #
@@ -1,5 +1,7 @@
1
1
  # encoding: utf-8
2
2
  #
3
+ require 'flipper'
4
+
3
5
  module Flipper
4
6
  module Echo
5
7
  # Encapsulates relevant information about a Flipper adapter event
@@ -11,7 +13,7 @@ module Flipper
11
13
  #
12
14
  # @param feature [Flipper::Feature] the feature that was changed
13
15
  # @param action [Symbol] the action
14
- # (`:enable`, `:disable`, `:remove` or `:clear`)
16
+ # (`:enabled`, `:disabled`, `:removed` or `:cleared`)
15
17
  # @param options [optional, Hash] hash of options
16
18
  #
17
19
  # @option options [Flipper::Type] :target the event target
@@ -68,10 +70,14 @@ module Flipper
68
70
  # Passes this event to the configured notifier
69
71
  #
70
72
  def notify
71
- if notifier.is_a?(Proc)
72
- notifier.call(self)
73
- elsif notifier.respond_to?(:notify)
74
- notifier.notify(self)
73
+ notifiers.each do |notifier|
74
+ method = if notifier.is_a?(Proc)
75
+ :call
76
+ elsif notifier.respond_to?(:notify)
77
+ :notify
78
+ end
79
+
80
+ notifier.send(method, self) if method
75
81
  end
76
82
  end
77
83
 
@@ -93,8 +99,8 @@ module Flipper
93
99
 
94
100
  private
95
101
 
96
- def notifier
97
- Flipper::Echo.configuration.notifier
102
+ def notifiers
103
+ Flipper::Echo.configuration.notifiers
98
104
  end
99
105
  end
100
106
  end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'flipper/echo/slack/message'
4
+ require 'flipper/echo/slack/notifier'
5
+
6
+ module Flipper
7
+ module Echo
8
+ # Slack notifier add-on module
9
+ #
10
+ module Slack
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+ #
3
+ module Flipper
4
+ module Echo
5
+ module Slack
6
+ # Slack message formatter
7
+ #
8
+ class Message
9
+ attr_reader :event
10
+
11
+ # Construct a new Message instance
12
+ #
13
+ # @param event [Flipper::Echo::Event] the Flipper event
14
+ #
15
+ # @return [Flipper::Echo::Slack::Message] the instance
16
+ #
17
+ def initialize(event)
18
+ @event = event
19
+ end
20
+
21
+ # Build message body
22
+ #
23
+ # @return [String] the message body
24
+ #
25
+ def to_s
26
+ [base, event.action, filters].compact.join(' ')
27
+ end
28
+
29
+ private
30
+
31
+ # @return [String]
32
+ #
33
+ def base
34
+ parts = []
35
+ parts << "[*#{environment}*]" if environment
36
+ parts << "Feature `#{event.feature.name}`"
37
+ parts.join(' ')
38
+ end
39
+
40
+ # @return [String, nil]
41
+ #
42
+ def filters
43
+ if event.group
44
+ "for group `#{event.group.name}`"
45
+ elsif event.actor
46
+ "for actor `#{event.actor.flipper_id}`"
47
+ elsif event.percentage_of_actors
48
+ "for #{event.percentage_of_actors.value}% of actors"
49
+ elsif event.percentage_of_random
50
+ "for #{event.percentage_of_random.value}% of random"
51
+ end
52
+ end
53
+
54
+ # @return [String, nil]
55
+ #
56
+ def environment
57
+ Flipper::Echo.configuration.environment
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,143 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'json'
4
+ require 'net/https'
5
+ require 'uri'
6
+
7
+ module Flipper
8
+ module Echo
9
+ module Slack
10
+ # Customizable Slack webhook notifier
11
+ #
12
+ class Notifier
13
+ attr_reader :webhook_url, :options
14
+
15
+ # Construct a new Notifier instance
16
+ #
17
+ # @param webhook_url [String] the Slack webhook url
18
+ # @param options [optional, Hash] hash of options
19
+ #
20
+ # @option options [String] :username Slack bot username
21
+ # @option options [String] :channel name of Slack channel
22
+ # @option options [String] :icon_url the message icon url
23
+ #
24
+ # @return [Flipper::Echo::Slack::Notifier] the instance
25
+ #
26
+ def initialize(webhook_url, options = {})
27
+ @webhook_url = webhook_url
28
+ @options = self.class.symbolize_keys(options)
29
+ end
30
+
31
+ # Normalized channel name
32
+ #
33
+ # @return [String, nil]
34
+ #
35
+ def channel
36
+ @channel ||= self.class.normalize_channel(options[:channel])
37
+ end
38
+
39
+ # Slack message username
40
+ #
41
+ # @return [String, nil]
42
+ #
43
+ def username
44
+ options.fetch(:username, DEFAULT_USERNAME)
45
+ end
46
+
47
+ # Slack message icon url
48
+ #
49
+ # @return [String, nil]
50
+ #
51
+ def icon_url
52
+ options.fetch(:icon_url, DEFAULT_ICON_URL)
53
+ end
54
+
55
+ # Post notification to Slack webhook url
56
+ #
57
+ # @return [HTTPResponse]
58
+ #
59
+ def notify(event)
60
+ message = Flipper::Echo::Slack::Message.new(event)
61
+
62
+ payload = {
63
+ text: message.to_s,
64
+ channel: channel,
65
+ username: username,
66
+ icon_url: icon_url
67
+ }
68
+
69
+ post(payload)
70
+ end
71
+
72
+ class << self
73
+ # Normalize Slack channel name for API
74
+ #
75
+ # @param name [String] the original name
76
+ #
77
+ # @return [String] the normalized name
78
+ #
79
+ def normalize_channel(name)
80
+ return unless name && name.size > 0
81
+
82
+ name =~ /\A[#@]/ ? name : "##{name}"
83
+ end
84
+
85
+ # Symbolize hash keys
86
+ #
87
+ # @param hash [Hash] the original hash
88
+ #
89
+ # @return [Hash] hash with symbolized keys
90
+ #
91
+ def symbolize_keys(hash)
92
+ hash.each_with_object({}) do |(key, value), result|
93
+ result[key.to_sym] = value
94
+ end
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ DEFAULT_USERNAME = 'Flipper'
101
+
102
+ DEFAULT_ICON_URL =
103
+ 'https://s3-us-west-2.amazonaws.com/mode.production/' \
104
+ 'flipper-echo/flipper-echo-icon-132.png'
105
+
106
+ # @return [Net::HTTP]
107
+ #
108
+ def http
109
+ @http ||= Net::HTTP.new(uri.host, uri.port).tap do |result|
110
+ result.use_ssl = ssl?
111
+ end
112
+ end
113
+
114
+ # @return [URI]
115
+ #
116
+ def uri
117
+ @uri ||= URI.parse(webhook_url)
118
+ end
119
+
120
+ # @return [true, false]
121
+ #
122
+ def ssl?
123
+ uri.scheme == 'https'
124
+ end
125
+
126
+ # @return [HTTPResponse]
127
+ #
128
+ def post(payload)
129
+ request = Net::HTTP::Post.new(uri.request_uri)
130
+ request.set_content_type('application/json')
131
+ request.body = payload.to_json
132
+
133
+ http.request(request).tap do |response|
134
+ unless response.code == '200'
135
+ $stderr.puts 'Unexpected Slack notifier response: ' \
136
+ "#{response.code}"
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'flipper/echo/stdout/notifier'
4
+
5
+ module Flipper
6
+ module Echo
7
+ # A stdout notifier add-on module
8
+ #
9
+ module Stdout
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ #
3
+ module Flipper
4
+ module Echo
5
+ module Stdout
6
+ # Simple stdout notifier intended as a basis for more advanced custom
7
+ # notifiers
8
+ #
9
+ class Notifier
10
+ # Send notification message to stdout
11
+ #
12
+ # @return [nil]
13
+ #
14
+ def notify(event)
15
+ parts = []
16
+ parts << '[Flipper]'
17
+ parts << "Feature \"#{event.feature.name}\""
18
+ parts << event.action
19
+
20
+ target = target_message(event)
21
+
22
+ parts << "for #{target}" if target
23
+
24
+ $stdout.puts(parts.join(' '))
25
+ end
26
+
27
+ private
28
+
29
+ # @return [String, nil]
30
+ #
31
+ def target_message(event)
32
+ if event.group
33
+ "group #{event.group.name}"
34
+ elsif event.actor
35
+ "actor #{event.actor.flipper_id}"
36
+ elsif event.percentage_of_actors
37
+ "#{event.percentage_of_actors.value}% of actors"
38
+ elsif event.percentage_of_random
39
+ "#{event.percentage_of_random.value}% of random"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -4,6 +4,6 @@ module Flipper
4
4
  module Echo
5
5
  # Current gem version
6
6
  #
7
- VERSION = '0.0.1'
7
+ VERSION = '0.0.2'
8
8
  end
9
9
  end
@@ -30,4 +30,16 @@ describe Flipper::Echo::Configuration do
30
30
  configuration.flipper = flipper
31
31
  end
32
32
  end
33
+
34
+ describe '#notifier=' do
35
+ it 'appends notifier' do
36
+ notifier = double(:notifier)
37
+
38
+ expect(configuration.notifiers).to eq([])
39
+
40
+ configuration.notifier = notifier
41
+
42
+ expect(configuration.notifiers).to eq([notifier])
43
+ end
44
+ end
33
45
  end
@@ -123,7 +123,7 @@ describe Flipper::Echo::Event do
123
123
  it 'calls proc' do
124
124
  procedure = proc {}
125
125
 
126
- allow(event).to receive(:notifier).and_return(procedure)
126
+ allow(event).to receive(:notifiers).and_return([procedure])
127
127
 
128
128
  expect(procedure).to receive(:call)
129
129
 
@@ -137,7 +137,7 @@ describe Flipper::Echo::Event do
137
137
  end
138
138
 
139
139
  it 'calls instance method if it exists' do
140
- allow(event).to receive(:notifier).and_return(notifier)
140
+ allow(event).to receive(:notifiers).and_return([notifier])
141
141
 
142
142
  expect(notifier).to receive(:notify)
143
143
 
@@ -160,18 +160,18 @@ describe Flipper::Echo::Event do
160
160
  end
161
161
  end
162
162
 
163
- describe '#notifier' do
163
+ describe '#notifiers' do
164
164
  let :notifier do
165
165
  double(:notifier)
166
166
  end
167
167
 
168
168
  it 'returns notifier from config' do
169
169
  allow(Flipper::Echo.configuration).to(
170
- receive(:notifier).and_return(notifier))
170
+ receive(:notifiers).and_return([notifier]))
171
171
 
172
172
  event = Flipper::Echo::Event.new(feature, action)
173
173
 
174
- expect(event.send(:notifier)).to eq(notifier)
174
+ expect(event.send(:notifiers)).to eq([notifier])
175
175
  end
176
176
  end
177
177
  end
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ describe Flipper::Echo::Slack::Message do
6
+ let :feature do
7
+ double(:feature, name: :experimental)
8
+ end
9
+
10
+ describe '#base' do
11
+ let :event do
12
+ Flipper::Echo::Event.new(feature, :enabled)
13
+ end
14
+
15
+ it 'builds expected string without environment' do
16
+ message = Flipper::Echo::Slack::Message.new(event)
17
+
18
+ expect(message.send(:base)).to eq('Feature `experimental`')
19
+ end
20
+
21
+ it 'builds expected string with environment' do
22
+ message = Flipper::Echo::Slack::Message.new(event)
23
+
24
+ allow(message).to receive(:environment).and_return('staging')
25
+
26
+ expect(message.send(:base)).to eq('[*staging*] Feature `experimental`')
27
+ end
28
+ end
29
+
30
+ describe '#filters' do
31
+ it 'builds group string' do
32
+ event = Flipper::Echo::Event.new(feature, :disabled)
33
+ message = Flipper::Echo::Slack::Message.new(event)
34
+
35
+ group = double(:group, name: 'admins')
36
+ allow(event).to receive(:group).and_return(group)
37
+
38
+ expect(message.send(:filters)).to eq('for group `admins`')
39
+ end
40
+
41
+ it 'builds actor string' do
42
+ event = Flipper::Echo::Event.new(feature, :disabled)
43
+ message = Flipper::Echo::Slack::Message.new(event)
44
+
45
+ actor = double(:actor, flipper_id: 'Actor:1')
46
+ allow(event).to receive(:actor).and_return(actor)
47
+
48
+ expect(message.send(:filters)).to eq('for actor `Actor:1`')
49
+ end
50
+
51
+ it 'builds percentage of actors string' do
52
+ event = Flipper::Echo::Event.new(feature, :disabled)
53
+ message = Flipper::Echo::Slack::Message.new(event)
54
+
55
+ percentage = double(:percentage, value: '10')
56
+ allow(event).to receive(:percentage_of_actors).and_return(percentage)
57
+
58
+ expect(message.send(:filters)).to eq('for 10% of actors')
59
+ end
60
+
61
+ it 'builds percentage of random string' do
62
+ event = Flipper::Echo::Event.new(feature, :disabled)
63
+ message = Flipper::Echo::Slack::Message.new(event)
64
+
65
+ percentage = double(:percentage, value: '10')
66
+ allow(event).to receive(:percentage_of_random).and_return(percentage)
67
+
68
+ expect(message.send(:filters)).to eq('for 10% of random')
69
+ end
70
+ end
71
+
72
+ describe '#environment' do
73
+ it 'returns configured environment' do
74
+ allow(Flipper::Echo.configuration).to(
75
+ receive(:environment).and_return('staging'))
76
+
77
+ message = Flipper::Echo::Slack::Message.new(nil)
78
+
79
+ expect(message.send(:environment)).to eq('staging')
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,126 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ describe Flipper::Echo::Slack::Notifier do
6
+ describe '#channel' do
7
+ it 'is null if options do not include channel' do
8
+ notifier = Flipper::Echo::Slack::Notifier.new('https://hook')
9
+
10
+ expect(notifier.channel).to eq(nil)
11
+ end
12
+
13
+ it 'returns channel from options without prepending' do
14
+ notifier = Flipper::Echo::Slack::Notifier.new(
15
+ 'https://hook', channel: '#custom_channel')
16
+
17
+ expect(notifier.channel).to eq('#custom_channel')
18
+ end
19
+
20
+ it 'returns channel from options with prepending' do
21
+ notifier = Flipper::Echo::Slack::Notifier.new(
22
+ 'https://hook', channel: 'custom_channel')
23
+
24
+ expect(notifier.channel).to eq('#custom_channel')
25
+ end
26
+ end
27
+
28
+ describe '#username' do
29
+ it 'is default if options do not include username' do
30
+ notifier = Flipper::Echo::Slack::Notifier.new('https://hook')
31
+
32
+ expect(notifier.username).to eq('Flipper')
33
+ end
34
+
35
+ it 'returns username from options' do
36
+ notifier = Flipper::Echo::Slack::Notifier.new(
37
+ 'https://hook', username: 'Custom Username')
38
+
39
+ expect(notifier.username).to eq('Custom Username')
40
+ end
41
+ end
42
+
43
+ describe '#icon_url' do
44
+ it 'is default if options do not include url' do
45
+ notifier = Flipper::Echo::Slack::Notifier.new('https://hook')
46
+
47
+ expect(notifier.icon_url).to match(/flipper\-echo\-icon/)
48
+ end
49
+
50
+ it 'returns username from options' do
51
+ notifier = Flipper::Echo::Slack::Notifier.new(
52
+ 'https://hook', icon_url: 'custom-icon')
53
+
54
+ expect(notifier.icon_url).to eq('custom-icon')
55
+ end
56
+ end
57
+
58
+ describe '#notify' do
59
+ let :feature do
60
+ double(:feature, name: :experimental)
61
+ end
62
+
63
+ let :event do
64
+ Flipper::Echo::Event.new(feature, :action)
65
+ end
66
+
67
+ it 'calls notifier with expected options' do
68
+ notifier = Flipper::Echo::Slack::Notifier.new('https://hook')
69
+
70
+ expect(notifier).to receive(:post) do |options|
71
+ expect(options[:text]).to match(/experimental/)
72
+ end
73
+
74
+ notifier.notify(event)
75
+ end
76
+ end
77
+
78
+ describe '#post' do
79
+ it 'posts expected json payload' do
80
+ notifier = Flipper::Echo::Slack::Notifier.new('https://hook')
81
+
82
+ expect(notifier.send(:http)).to receive(:request) do |request|
83
+ expect(request.body).to eq('{"foo":"bar"}')
84
+ expect(request.content_type).to eq('application/json')
85
+
86
+ double(:response, code: '200')
87
+ end
88
+
89
+ notifier.send(:post, foo: 'bar')
90
+ end
91
+
92
+ it 'prints unexpected api response to stderr' do
93
+ notifier = Flipper::Echo::Slack::Notifier.new('https://hook')
94
+
95
+ expect(notifier.send(:http)).to(
96
+ receive(:request).and_return(double(:response, code: '404')))
97
+
98
+ expect { notifier.send(:post, foo: 'bar') }.to output.to_stderr
99
+ end
100
+ end
101
+
102
+ describe '.normalize_channel' do
103
+ it 'is nil for blank name' do
104
+ expect(Flipper::Echo::Slack::Notifier.normalize_channel(nil)).to eq(nil)
105
+ expect(Flipper::Echo::Slack::Notifier.normalize_channel('')).to eq(nil)
106
+ end
107
+
108
+ it 'preserves name including number sign' do
109
+ result = Flipper::Echo::Slack::Notifier.normalize_channel('#channel_name')
110
+
111
+ expect(result).to eq('#channel_name')
112
+ end
113
+
114
+ it 'prepends number sign if necessary' do
115
+ result = Flipper::Echo::Slack::Notifier.normalize_channel('channel_name')
116
+
117
+ expect(result).to eq('#channel_name')
118
+ end
119
+
120
+ it 'preserves at sign' do
121
+ result = Flipper::Echo::Slack::Notifier.normalize_channel('@channel_name')
122
+
123
+ expect(result).to eq('@channel_name')
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ describe Flipper::Echo::Stdout::Notifier do
6
+ let :feature do
7
+ double(:feature, name: :experimental)
8
+ end
9
+
10
+ let :event do
11
+ Flipper::Echo::Event.new(feature, :enabled)
12
+ end
13
+
14
+ let :notifier do
15
+ Flipper::Echo::Stdout::Notifier.new
16
+ end
17
+
18
+ describe '#notify' do
19
+ it 'sends message to stdout' do
20
+ expect { notifier.notify(event) }.to output.to_stdout
21
+ end
22
+ end
23
+
24
+ describe '#target_message' do
25
+ it 'builds group message' do
26
+ allow(event).to receive(:group).and_return(double(:group, name: :admins))
27
+
28
+ expect(notifier.send(:target_message, event)).to eq('group admins')
29
+ end
30
+
31
+ it 'builds actor message' do
32
+ allow(event).to(
33
+ receive(:actor).and_return(double(:actor, flipper_id: 'id')))
34
+
35
+ expect(notifier.send(:target_message, event)).to eq('actor id')
36
+ end
37
+
38
+ it 'builds percentage of actors message' do
39
+ allow(event).to(
40
+ receive(:percentage_of_actors).and_return(double(:actors, value: 15)))
41
+
42
+ expect(notifier.send(:target_message, event)).to eq('15% of actors')
43
+ end
44
+
45
+ it 'builds percentage of random message' do
46
+ allow(event).to(
47
+ receive(:percentage_of_random).and_return(double(:random, value: 15)))
48
+
49
+ expect(notifier.send(:target_message, event)).to eq('15% of random')
50
+ end
51
+ end
52
+ end
@@ -43,7 +43,7 @@ describe Flipper::Echo do
43
43
  describe '#enable' do
44
44
  it 'enables feature' do
45
45
  expect_any_instance_of(Flipper::Echo::Event).to receive(:notify) do |e|
46
- expect(e.action).to eq(:enable)
46
+ expect(e.action).to eq(:enabled)
47
47
  end
48
48
 
49
49
  adapter.enable(feature, gate, target)
@@ -53,7 +53,7 @@ describe Flipper::Echo do
53
53
  describe '#disable' do
54
54
  it 'disables feature' do
55
55
  expect_any_instance_of(Flipper::Echo::Event).to receive(:notify) do |e|
56
- expect(e.action).to eq(:disable)
56
+ expect(e.action).to eq(:disabled)
57
57
  end
58
58
 
59
59
  adapter.disable(feature, gate, target)
@@ -63,7 +63,7 @@ describe Flipper::Echo do
63
63
  describe '#remove' do
64
64
  it 'removes feature' do
65
65
  expect_any_instance_of(Flipper::Echo::Event).to receive(:notify) do |e|
66
- expect(e.action).to eq(:remove)
66
+ expect(e.action).to eq(:removed)
67
67
  end
68
68
 
69
69
  adapter.remove(feature)
@@ -73,7 +73,7 @@ describe Flipper::Echo do
73
73
  describe '#clear' do
74
74
  it 'clears feature' do
75
75
  expect_any_instance_of(Flipper::Echo::Event).to receive(:notify) do |e|
76
- expect(e.action).to eq(:clear)
76
+ expect(e.action).to eq(:cleared)
77
77
  end
78
78
 
79
79
  adapter.clear(feature)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flipper-echo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Heather Rivers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-13 00:00:00.000000000 Z
11
+ date: 2015-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: flipper
@@ -110,10 +110,17 @@ files:
110
110
  - lib/flipper/echo.rb
111
111
  - lib/flipper/echo/configuration.rb
112
112
  - lib/flipper/echo/event.rb
113
+ - lib/flipper/echo/slack.rb
114
+ - lib/flipper/echo/slack/message.rb
115
+ - lib/flipper/echo/slack/notifier.rb
116
+ - lib/flipper/echo/stdout.rb
117
+ - lib/flipper/echo/stdout/notifier.rb
113
118
  - lib/flipper/echo/version.rb
114
119
  - spec/flipper/echo/configuration_spec.rb
115
120
  - spec/flipper/echo/event_spec.rb
116
- - spec/flipper/echo/version_spec.rb
121
+ - spec/flipper/echo/slack/message_spec.rb
122
+ - spec/flipper/echo/slack/notifier_spec.rb
123
+ - spec/flipper/echo/stdout/notifier_spec.rb
117
124
  - spec/flipper/echo_spec.rb
118
125
  - spec/spec_helper.rb
119
126
  - spec/support/adapter_support.rb
@@ -144,7 +151,9 @@ summary: Flipper event notifier
144
151
  test_files:
145
152
  - spec/flipper/echo/configuration_spec.rb
146
153
  - spec/flipper/echo/event_spec.rb
147
- - spec/flipper/echo/version_spec.rb
154
+ - spec/flipper/echo/slack/message_spec.rb
155
+ - spec/flipper/echo/slack/notifier_spec.rb
156
+ - spec/flipper/echo/stdout/notifier_spec.rb
148
157
  - spec/flipper/echo_spec.rb
149
158
  - spec/spec_helper.rb
150
159
  - spec/support/adapter_support.rb
File without changes