flipper 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +2 -0
- data/.rubocop.yml +3 -0
- data/Changelog.md +19 -2
- data/Rakefile +1 -6
- data/docs/Gates.md +3 -3
- data/lib/flipper.rb +10 -2
- data/lib/flipper/dsl.rb +5 -0
- data/lib/flipper/feature.rb +8 -0
- data/lib/flipper/middleware/memoizer.rb +4 -4
- data/lib/flipper/spec/shared_adapter_specs.rb +11 -0
- data/lib/flipper/test/shared_adapter_test.rb +11 -0
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/adapter_spec.rb +7 -0
- data/spec/flipper/dsl_spec.rb +17 -0
- data/spec/flipper/feature_spec.rb +20 -0
- data/spec/flipper/middleware/memoizer_spec.rb +4 -4
- data/spec/flipper_spec.rb +18 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc4f086ed26b95a195d65b0ef2162c09bf7d4878
|
4
|
+
data.tar.gz: 4360d2c7f218cc2790248497827ac55b866e617f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cafced6f460315fb925d0e8b849dd68bcc1c81bd719075378727095a2921ad80b4b3dce30ed616f5f9b13ac2f7a90e9521e27b01ea72957cc1a44176693caf77
|
7
|
+
data.tar.gz: 446d33765b51edda016f98ebf4fbf88cbd51ea5248b4e750fc8c26d72bcb24ac2d45b97929e206620b8ddbd47e46b2d57ec8b827a1554a801d4261aeadd8f98d
|
data/.codeclimate.yml
ADDED
data/.rubocop.yml
CHANGED
data/Changelog.md
CHANGED
@@ -1,10 +1,24 @@
|
|
1
|
+
## 0.12
|
2
|
+
|
3
|
+
### Additions/Changes
|
4
|
+
|
5
|
+
* Added Flipper.instance= writer method for explicitly setting the default instance (https://github.com/jnunemaker/flipper/pull/309).
|
6
|
+
* Added Flipper::UI configuration instance for changing text and things (https://github.com/jnunemaker/flipper/pull/306).
|
7
|
+
* Delegate memoize= and memoizing? for Flipper and Flipper::DSL (https://github.com/jnunemaker/flipper/pull/310).
|
8
|
+
* Fixed error when enabling the same group or actor more than once (https://github.com/jnunemaker/flipper/pull/313).
|
9
|
+
* Fixed redis cache adapter key (and thus cache misses) (https://github.com/jnunemaker/flipper/pull/325).
|
10
|
+
* Added Rollout adapter to make it easy to import rollout data into Flipper (https://github.com/jnunemaker/flipper/pull/319).
|
11
|
+
* Relaxed redis gem dependency constraint to allow redis-rb 4 (https://github.com/jnunemaker/flipper/pull/317).
|
12
|
+
* Added configuration option for Flipper::UI to disable feature removal (https://github.com/jnunemaker/flipper/pull/322).
|
13
|
+
|
1
14
|
## 0.11
|
2
15
|
|
3
16
|
### Backwards Compatibility Breaks
|
4
17
|
|
5
|
-
* Set flipper from env for API and UI (https://github.com/jnunemaker/flipper/pull/223 and https://github.com/jnunemaker/flipper/pull/229). It is documented, but now the memoizing middleware requires that the SetupEnv middleware is used first.
|
18
|
+
* Set flipper from env for API and UI (https://github.com/jnunemaker/flipper/pull/223 and https://github.com/jnunemaker/flipper/pull/229). It is documented, but now the memoizing middleware requires that the SetupEnv middleware is used first, unless you are configuring a Flipper default instance.
|
6
19
|
* Drop support for Ruby 2.0 as it is end of lined (https://github.com/jnunemaker/flipper/commit/c2c81ed89938155ce91acb5173ac38580f630e3d).
|
7
20
|
* Allow unregistered groups (https://github.com/jnunemaker/flipper/pull/244). Only break in compatibility is that previously unregistered groups could not be enabled and now they can be.
|
21
|
+
* Removed support for metriks (https://github.com/jnunemaker/flipper/pull/291).
|
8
22
|
|
9
23
|
### Additions/Changes
|
10
24
|
|
@@ -22,9 +36,12 @@
|
|
22
36
|
* Add DSL#preload_all and Adapter#get_all to allow for making even more efficient loading of features (https://github.com/jnunemaker/flipper/pull/255).
|
23
37
|
* Allow setting debug output of http adapter (https://github.com/jnunemaker/flipper/pull/256 and https://github.com/jnunemaker/flipper/pull/258).
|
24
38
|
* Allow setting env key for middleware (https://github.com/jnunemaker/flipper/pull/259).
|
25
|
-
* Added ActiveSupport cache store adapter for use with Rails.cache (https://github.com/jnunemaker/flipper/pull/265).
|
39
|
+
* Added ActiveSupport cache store adapter for use with Rails.cache (https://github.com/jnunemaker/flipper/pull/265 and https://github.com/jnunemaker/flipper/pull/297).
|
26
40
|
* Added support for up to 3 decimal places in percentage based rollouts (https://github.com/jnunemaker/flipper/pull/274).
|
27
41
|
* Removed Flipper::GroupNotRegistered error as it is now unused (https://github.com/jnunemaker/flipper/pull/270).
|
42
|
+
* Added get_all to all adapters (https://github.com/jnunemaker/flipper/pull/298).
|
43
|
+
* Added support for Rails 5.1 (https://github.com/jnunemaker/flipper/pull/299).
|
44
|
+
* Added Flipper default instance generation (https://github.com/jnunemaker/flipper/pull/279).
|
28
45
|
|
29
46
|
## 0.10.2
|
30
47
|
|
data/Rakefile
CHANGED
@@ -41,9 +41,4 @@ Rake::TestTask.new do |t|
|
|
41
41
|
t.pattern = 'test/**/*_test.rb'
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
|
-
t.libs = %w(lib test)
|
46
|
-
t.pattern = 'lib/flipper/shared/test/**_test.rb'
|
47
|
-
end
|
48
|
-
|
49
|
-
task default: [:spec, :test, :shared_test]
|
44
|
+
task default: [:spec, :test]
|
data/docs/Gates.md
CHANGED
@@ -15,7 +15,7 @@ flipper[:stats].enabled? # check
|
|
15
15
|
|
16
16
|
## 2. Group
|
17
17
|
|
18
|
-
Turn on feature based on the return value of block. Super flexible way to turn on a feature for multiple things (users, people, accounts, etc.) as long as the thing returns true when passed to the block.
|
18
|
+
Turn on feature based on the return value of block. Super flexible way to turn on a feature for multiple things (users, people, accounts, etc.) as long as the thing returns true when passed to the block.
|
19
19
|
|
20
20
|
```ruby
|
21
21
|
# this registers a group
|
@@ -71,8 +71,8 @@ In your application code, you can do something like this now:
|
|
71
71
|
if flipper[:stats].enabled?(some_admin)
|
72
72
|
# do thing...
|
73
73
|
else
|
74
|
-
|
75
|
-
end
|
74
|
+
# do not do thing
|
75
|
+
end
|
76
76
|
```
|
77
77
|
|
78
78
|
## 3. Individual Actor
|
data/lib/flipper.rb
CHANGED
@@ -32,7 +32,7 @@ module Flipper
|
|
32
32
|
# Public: Sets Flipper::Configuration instance.
|
33
33
|
def configuration=(configuration)
|
34
34
|
# need to reset flipper instance if configuration changes
|
35
|
-
|
35
|
+
self.instance = nil
|
36
36
|
@configuration = configuration
|
37
37
|
end
|
38
38
|
|
@@ -46,6 +46,13 @@ module Flipper
|
|
46
46
|
Thread.current[:flipper_instance] ||= configuration.default
|
47
47
|
end
|
48
48
|
|
49
|
+
# Public: Set the flipper instance. It is most common to use the
|
50
|
+
# Configuration#default to set this instance, but for things like the test
|
51
|
+
# environment, this writer is actually useful.
|
52
|
+
def instance=(flipper)
|
53
|
+
Thread.current[:flipper_instance] = flipper
|
54
|
+
end
|
55
|
+
|
49
56
|
# Public: All the methods delegated to instance. These should match the
|
50
57
|
# interface of Flipper::DSL.
|
51
58
|
def_delegators :instance,
|
@@ -57,7 +64,8 @@ module Flipper
|
|
57
64
|
:enable_percentage_of_time, :disable_percentage_of_time,
|
58
65
|
:time, :percentage_of_time,
|
59
66
|
:features, :feature, :[], :preload, :preload_all,
|
60
|
-
:adapter, :add, :remove, :import
|
67
|
+
:adapter, :add, :remove, :import,
|
68
|
+
:memoize=, :memoizing?
|
61
69
|
|
62
70
|
# Public: Use this to register a group by name.
|
63
71
|
#
|
data/lib/flipper/dsl.rb
CHANGED
@@ -1,14 +1,19 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
require 'flipper/adapters/memoizable'
|
2
3
|
require 'flipper/instrumenters/noop'
|
3
4
|
|
4
5
|
module Flipper
|
5
6
|
class DSL
|
7
|
+
extend Forwardable
|
8
|
+
|
6
9
|
# Private
|
7
10
|
attr_reader :adapter
|
8
11
|
|
9
12
|
# Private: What is being used to instrument all the things.
|
10
13
|
attr_reader :instrumenter
|
11
14
|
|
15
|
+
def_delegators :@adapter, :memoize=, :memoizing?
|
16
|
+
|
12
17
|
# Public: Returns a new instance of the DSL.
|
13
18
|
#
|
14
19
|
# adapter - The adapter that this DSL instance should use.
|
data/lib/flipper/feature.rb
CHANGED
@@ -6,6 +6,7 @@ require 'flipper/gate_values'
|
|
6
6
|
require 'flipper/instrumenters/noop'
|
7
7
|
|
8
8
|
module Flipper
|
9
|
+
# rubocop:disable Metrics/ClassLength
|
9
10
|
class Feature
|
10
11
|
# Private: The name of feature instrumentation events.
|
11
12
|
InstrumentationName = "feature_operation.#{InstrumentationNamespace}".freeze
|
@@ -83,6 +84,13 @@ module Flipper
|
|
83
84
|
instrument(:remove) { adapter.remove(self) }
|
84
85
|
end
|
85
86
|
|
87
|
+
# Public: Clears all gate values for this feature.
|
88
|
+
#
|
89
|
+
# Returns the result of Adapter#clear.
|
90
|
+
def clear
|
91
|
+
instrument(:clear) { adapter.clear(self) }
|
92
|
+
end
|
93
|
+
|
86
94
|
# Public: Check if a feature is enabled for a thing.
|
87
95
|
#
|
88
96
|
# Returns true if enabled, false if not.
|
@@ -52,8 +52,8 @@ module Flipper
|
|
52
52
|
def memoized_call(env)
|
53
53
|
reset_on_body_close = false
|
54
54
|
flipper = env.fetch(@env_key) { Flipper }
|
55
|
-
original = flipper.
|
56
|
-
flipper.
|
55
|
+
original = flipper.memoizing?
|
56
|
+
flipper.memoize = true
|
57
57
|
|
58
58
|
flipper.preload_all if @opts[:preload_all]
|
59
59
|
|
@@ -63,12 +63,12 @@ module Flipper
|
|
63
63
|
|
64
64
|
response = @app.call(env)
|
65
65
|
response[2] = Rack::BodyProxy.new(response[2]) do
|
66
|
-
flipper.
|
66
|
+
flipper.memoize = original
|
67
67
|
end
|
68
68
|
reset_on_body_close = true
|
69
69
|
response
|
70
70
|
ensure
|
71
|
-
flipper.
|
71
|
+
flipper.memoize = original if flipper && !reset_on_body_close
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
@@ -258,4 +258,15 @@ RSpec.shared_examples_for 'a flipper adapter' do
|
|
258
258
|
expect(stats).to eq(subject.default_config.merge(boolean: 'true'))
|
259
259
|
expect(search).to eq(subject.default_config)
|
260
260
|
end
|
261
|
+
|
262
|
+
it 'can double enable an actor without error' do
|
263
|
+
actor = Flipper::Actor.new('Flipper::Actor;22')
|
264
|
+
expect(subject.enable(feature, actor_gate, flipper.actor(actor))).to eq(true)
|
265
|
+
expect(subject.enable(feature, actor_gate, flipper.actor(actor))).to eq(true)
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'can double enable a group without error' do
|
269
|
+
expect(subject.enable(feature, group_gate, flipper.group(:admins))).to eq(true)
|
270
|
+
expect(subject.enable(feature, group_gate, flipper.group(:admins))).to eq(true)
|
271
|
+
end
|
261
272
|
end
|
@@ -253,6 +253,17 @@ module Flipper
|
|
253
253
|
assert_equal @adapter.default_config.merge(boolean: 'true'), stats
|
254
254
|
assert_equal @adapter.default_config, search
|
255
255
|
end
|
256
|
+
|
257
|
+
def test_can_double_enable_an_actor_without_error
|
258
|
+
actor = Flipper::Actor.new('Flipper::Actor;22')
|
259
|
+
assert_equal true, @adapter.enable(@feature, @actor_gate, @flipper.actor(actor))
|
260
|
+
assert_equal true, @adapter.enable(@feature, @actor_gate, @flipper.actor(actor))
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_can_double_enable_a_group_without_error
|
264
|
+
assert_equal true, @adapter.enable(@feature, @group_gate, @flipper.group(:admins))
|
265
|
+
assert_equal true, @adapter.enable(@feature, @group_gate, @flipper.group(:admins))
|
266
|
+
end
|
256
267
|
end
|
257
268
|
end
|
258
269
|
end
|
data/lib/flipper/version.rb
CHANGED
@@ -65,6 +65,13 @@ RSpec.describe Flipper::Adapter do
|
|
65
65
|
|
66
66
|
destination_flipper.import(source_flipper)
|
67
67
|
|
68
|
+
feature = destination_flipper[:yep]
|
69
|
+
expect(feature.boolean_value).to be(true)
|
70
|
+
expect(feature.groups_value).to eq(Set[])
|
71
|
+
expect(feature.actors_value).to eq(Set[])
|
72
|
+
expect(feature.percentage_of_actors_value).to be(0)
|
73
|
+
expect(feature.percentage_of_time_value).to be(0)
|
74
|
+
|
68
75
|
feature = destination_flipper[:preview_features]
|
69
76
|
expect(feature.boolean_value).to be(false)
|
70
77
|
expect(feature.actors_value).to eq(Set['1', '2', '3'])
|
data/spec/flipper/dsl_spec.rb
CHANGED
@@ -329,4 +329,21 @@ RSpec.describe Flipper::DSL do
|
|
329
329
|
subject.import(destination_flipper)
|
330
330
|
end
|
331
331
|
end
|
332
|
+
|
333
|
+
describe '#memoize=' do
|
334
|
+
it 'delegates to adapter' do
|
335
|
+
expect(subject.adapter).not_to be_memoizing
|
336
|
+
subject.memoize = true
|
337
|
+
expect(subject.adapter).to be_memoizing
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
describe '#memoizing?' do
|
342
|
+
it 'delegates to adapter' do
|
343
|
+
subject.memoize = false
|
344
|
+
expect(subject.adapter.memoizing?).to eq(subject.memoizing?)
|
345
|
+
subject.memoize = true
|
346
|
+
expect(subject.adapter.memoizing?).to eq(subject.memoizing?)
|
347
|
+
end
|
348
|
+
end
|
332
349
|
end
|
@@ -106,6 +106,15 @@ RSpec.describe Flipper::Feature do
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
|
+
describe '#clear' do
|
110
|
+
it 'clears feature using adapter' do
|
111
|
+
subject.enable
|
112
|
+
expect(subject).to be_enabled
|
113
|
+
subject.clear
|
114
|
+
expect(subject).not_to be_enabled
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
109
118
|
describe '#inspect' do
|
110
119
|
it 'returns easy to read string representation' do
|
111
120
|
string = subject.inspect
|
@@ -234,6 +243,17 @@ RSpec.describe Flipper::Feature do
|
|
234
243
|
expect(event.payload[:result]).not_to be_nil
|
235
244
|
end
|
236
245
|
|
246
|
+
it 'is recorded for clear' do
|
247
|
+
subject.clear
|
248
|
+
|
249
|
+
event = instrumenter.events.last
|
250
|
+
expect(event).not_to be_nil
|
251
|
+
expect(event.name).to eq('feature_operation.flipper')
|
252
|
+
expect(event.payload[:feature_name]).to eq(:search)
|
253
|
+
expect(event.payload[:operation]).to eq(:clear)
|
254
|
+
expect(event.payload[:result]).not_to be_nil
|
255
|
+
end
|
256
|
+
|
237
257
|
it 'is recorded for enabled?' do
|
238
258
|
thing = Flipper::Types::Actor.new(Flipper::Actor.new('1'))
|
239
259
|
gate = subject.gate_for(thing)
|
@@ -18,7 +18,7 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
18
18
|
let(:env) { { 'flipper' => flipper } }
|
19
19
|
|
20
20
|
after do
|
21
|
-
flipper.
|
21
|
+
flipper.memoize = nil
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'raises if initialized with app and flipper instance' do
|
@@ -51,9 +51,9 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
51
51
|
middleware = described_class.new(app)
|
52
52
|
body = middleware.call(env).last
|
53
53
|
|
54
|
-
expect(flipper.
|
54
|
+
expect(flipper.memoizing?).to eq(true)
|
55
55
|
body.close
|
56
|
-
expect(flipper.
|
56
|
+
expect(flipper.memoizing?).to eq(false)
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'clears local cache after body close' do
|
@@ -231,7 +231,7 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
231
231
|
middleware = described_class.new(app)
|
232
232
|
middleware.call(env)
|
233
233
|
rescue RuntimeError
|
234
|
-
expect(flipper.
|
234
|
+
expect(flipper.memoizing?).to be(false)
|
235
235
|
end
|
236
236
|
end
|
237
237
|
end
|
data/spec/flipper_spec.rb
CHANGED
@@ -54,6 +54,14 @@ RSpec.describe Flipper do
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
+
describe '.instance=' do
|
58
|
+
it 'updates Flipper.instance' do
|
59
|
+
instance = described_class.new(Flipper::Adapters::Memory.new)
|
60
|
+
described_class.instance = instance
|
61
|
+
expect(described_class.instance).to be(instance)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
57
65
|
describe "delegation to instance" do
|
58
66
|
let(:group) { Flipper::Types::Group.new(:admins) }
|
59
67
|
let(:actor) { Flipper::Actor.new("1") }
|
@@ -193,6 +201,16 @@ RSpec.describe Flipper do
|
|
193
201
|
it 'delegates adapter to instance' do
|
194
202
|
expect(described_class.adapter).to eq(described_class.instance.adapter)
|
195
203
|
end
|
204
|
+
|
205
|
+
it 'delegates memoize= to instance' do
|
206
|
+
expect(described_class.adapter.memoizing?).to be(false)
|
207
|
+
described_class.memoize = true
|
208
|
+
expect(described_class.adapter.memoizing?).to be(true)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'delegates memoizing? to instance' do
|
212
|
+
expect(described_class.memoizing?).to eq(described_class.adapter.memoizing?)
|
213
|
+
end
|
196
214
|
end
|
197
215
|
|
198
216
|
describe '.register' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Feature flipper is the act of enabling/disabling features in your application,
|
14
14
|
ideally without re-deploying or changing anything in your code base. Flipper makes
|
@@ -19,6 +19,7 @@ executables: []
|
|
19
19
|
extensions: []
|
20
20
|
extra_rdoc_files: []
|
21
21
|
files:
|
22
|
+
- ".codeclimate.yml"
|
22
23
|
- ".rubocop.yml"
|
23
24
|
- ".rubocop_todo.yml"
|
24
25
|
- Changelog.md
|