flipper-echo 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +50 -7
- data/lib/flipper/echo.rb +6 -4
- data/lib/flipper/echo/configuration.rb +27 -1
- data/lib/flipper/echo/event.rb +13 -7
- data/lib/flipper/echo/slack.rb +13 -0
- data/lib/flipper/echo/slack/message.rb +62 -0
- data/lib/flipper/echo/slack/notifier.rb +143 -0
- data/lib/flipper/echo/stdout.rb +12 -0
- data/lib/flipper/echo/stdout/notifier.rb +45 -0
- data/lib/flipper/echo/version.rb +1 -1
- data/spec/flipper/echo/configuration_spec.rb +12 -0
- data/spec/flipper/echo/event_spec.rb +5 -5
- data/spec/flipper/echo/slack/message_spec.rb +82 -0
- data/spec/flipper/echo/slack/notifier_spec.rb +126 -0
- data/spec/flipper/echo/stdout/notifier_spec.rb +52 -0
- data/spec/flipper/echo_spec.rb +4 -4
- metadata +13 -4
- data/spec/flipper/echo/version_spec.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b2f87cd93693142ff67b6ceeed1444b6f7b012f
|
4
|
+
data.tar.gz: 31f38685142d8e670acaf735beaea1432810b873
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d465bf8cf158efb1f6edb3c57ef6f952d9f6b2667cf39c59a1040884b7cbab83b69f2bd33758bd50187b47604b9385b635e65894bd91dcd92695e61582c59bb
|
7
|
+
data.tar.gz: 318e9de9d3ce75c78bd78d2802fecd91eb855f0120b55793428e7a3ee01896f3f56cbf5c004ed5855ba524969a931613f03cf1c4aec1e3faef2113167a0400ed
|
data/.gitignore
CHANGED
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
|
40
|
+
Then configure this gem in any of the following ways:
|
38
41
|
|
39
|
-
####
|
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
|
-
####
|
56
|
+
#### Handle event with an object
|
54
57
|
|
55
|
-
|
58
|
+
You can provide any Ruby object with a `notify` method:
|
56
59
|
|
57
60
|
```ruby
|
58
|
-
class
|
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 =
|
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, :
|
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, :
|
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, :
|
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, :
|
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
|
-
|
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
|
#
|
data/lib/flipper/echo/event.rb
CHANGED
@@ -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
|
-
# (`:
|
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
|
-
|
72
|
-
notifier.
|
73
|
-
|
74
|
-
|
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
|
97
|
-
Flipper::Echo.configuration.
|
102
|
+
def notifiers
|
103
|
+
Flipper::Echo.configuration.notifiers
|
98
104
|
end
|
99
105
|
end
|
100
106
|
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,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
|
data/lib/flipper/echo/version.rb
CHANGED
@@ -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(:
|
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(:
|
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 '#
|
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(:
|
170
|
+
receive(:notifiers).and_return([notifier]))
|
171
171
|
|
172
172
|
event = Flipper::Echo::Event.new(feature, action)
|
173
173
|
|
174
|
-
expect(event.send(:
|
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
|
data/spec/flipper/echo_spec.rb
CHANGED
@@ -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(:
|
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(:
|
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(:
|
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(:
|
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.
|
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-
|
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/
|
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/
|
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
|