flipper 0.17.1 → 0.20.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df515c2e52128d5b5508b4aa16799850313e11cc519d5a21894f2d968d5de19c
4
- data.tar.gz: 5747f267aad32feb4a7b63207905f74096fd4f2a2b7037bed5909b4b37446586
3
+ metadata.gz: b11913845dd63e7156086ce778927c1986694c48472dbb5b779155318c6eeab6
4
+ data.tar.gz: bc1bf62134ccd35ef86a5373f8105a9d511e3061e5666e55b0183fd20437a74f
5
5
  SHA512:
6
- metadata.gz: eef86eef8bcd970d5f4e96daa3f7c4296a74cec026ba94a1d8c9679ef50cb9515c490d0b3bd1479a780f3c98f115c1023f2c5ed9f216230ebba1c0ca402e89f6
7
- data.tar.gz: 6fa04470cdf9e5c3b53b7489dff534780e6a8855ffb8fb6fdd74017caf392c7955fe45d18f209054eca7f26d35747d34719fee895e35a8877485adc6edd6083b
6
+ metadata.gz: ec24f067db0fc80d5d3e9f00ce1b87b51d5111f89e9d35842d044347dbbbfc836663e972e7eb0c640713e375938e10a7d70769af27c87aea82270eba29432ca0
7
+ data.tar.gz: fb56eb175c3067f1b301d5875818b0c0a372f6e11da7e68c88337ab2660c8a7cfa20c027e8862cfc9aca126c5bd4b424dc962b846e2c812932400cc0f9592855
@@ -1,3 +1,38 @@
1
+ ## 0.19.1
2
+
3
+ ### Additions/Changes
4
+
5
+ * Bump rack-protection version to < 2.2 (https://github.com/jnunemaker/flipper/pull/487)
6
+ * Add memoizer_options to Flipper::Api.app (https://github.com/jnunemaker/flipper/commit/174ad4bb94046a25c432d3c53fe1ff9f5a76d838)
7
+
8
+ ## 0.19.0
9
+
10
+ ### Additions/Changes
11
+
12
+ * 100% of actors is now considered conditional. Feature#on?, Feature#conditional?, Feature#state would all be affected. See https://github.com/jnunemaker/flipper/issues/463 for more.
13
+ * Several doc updates.
14
+
15
+ ## 0.18.0
16
+
17
+ ### Additions/Changes
18
+
19
+ * Add support for feature descriptions to flipper-ui (https://github.com/jnunemaker/flipper/pull/461).
20
+ * Remove rubocop (https://github.com/jnunemaker/flipper/pull/469).
21
+ * flipper-ui redesign (https://github.com/jnunemaker/flipper/pull/470).
22
+ * Removed support for ruby 2.4.
23
+ * Added support for ruby 2.7.
24
+ * Removed support for Rails 4.x.x.
25
+ * Removed support for customizing actors, groups, % of actors and % of time text in flipper-ui in favor of automatic and more descriptive text.
26
+
27
+ ## 0.17.2
28
+
29
+ ### Additions/Changes
30
+
31
+ * Avoid errors on import when there are no features and shared specs/tests for get all with no features (https://github.com/jnunemaker/flipper/pull/441 and https://github.com/jnunemaker/flipper/pull/442)
32
+ * ::ActiveRecord::RecordNotUnique > ActiveRecord::RecordNotUnique (https://github.com/jnunemaker/flipper/pull/444)
33
+ * Clear gate values on enable (https://github.com/jnunemaker/flipper/pull/454)
34
+ * Remove use of multi from redis adapter (https://github.com/jnunemaker/flipper/pull/451)
35
+
1
36
  ## 0.17.1
2
37
 
3
38
  * Fix require in flipper-active_record (https://github.com/jnunemaker/flipper/pull/437)
@@ -81,7 +116,7 @@
81
116
 
82
117
  ### Additions/Changes
83
118
 
84
- * Added rollout adapter documentation (https://github.com/jnunemaker/flipper/pull/328).
119
+ * Added rollout adapter documentation (https://github.com/jnunemaker/flipper/pull/328).
85
120
 
86
121
  ### Bug Fixes
87
122
 
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM ruby:2.2.5
1
+ FROM ruby:2.5
2
2
 
3
3
  RUN apt-get update && apt-get install -y \
4
4
  # build-essential \
data/Gemfile CHANGED
@@ -12,20 +12,16 @@ gem 'shotgun', '~> 0.9'
12
12
  gem 'statsd-ruby', '~> 1.2.1'
13
13
  gem 'rspec', '~> 3.0'
14
14
  gem 'rack-test', '~> 0.6.3'
15
- gem 'sqlite3', "~> #{ENV['SQLITE3_VERSION'] || '1.3.11'}"
15
+ gem 'sqlite3', "~> #{ENV['SQLITE3_VERSION'] || '1.4.1'}"
16
16
  gem 'rails', "~> #{ENV['RAILS_VERSION'] || '6.0.0'}"
17
17
  gem 'minitest', '~> 5.8'
18
18
  gem 'minitest-documentation'
19
- gem 'rubocop'
20
- gem 'rubocop-rspec'
21
19
  gem 'webmock', '~> 3.0'
20
+ gem 'climate_control'
22
21
 
23
22
  group(:guard) do
24
23
  gem 'guard', '~> 2.15'
25
- gem 'guard-rubocop', '~> 1.3'
26
24
  gem 'guard-rspec', '~> 4.5'
27
25
  gem 'guard-bundler', '~> 2.2'
28
- gem 'guard-coffeescript', '~> 2.0'
29
- gem 'guard-sass', '~> 1.6'
30
26
  gem 'rb-fsevent', '~> 0.9'
31
27
  end
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env rake
2
2
  $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
3
  require 'rake/testtask'
4
- require 'rubocop/rake_task'
5
4
  require 'flipper/version'
6
5
 
7
6
  # gem install pkg/*.gem
@@ -50,6 +49,4 @@ Rake::TestTask.new(:test_rails) do |t|
50
49
  t.warning = false
51
50
  end
52
51
 
53
- RuboCop::RakeTask.new
54
-
55
- task default: [:spec, :test, :test_rails, :rubocop]
52
+ task default: [:spec, :test, :test_rails]
@@ -4,7 +4,7 @@ I plan on supporting the adapters in the flipper repo. Other adapters are welcom
4
4
 
5
5
  ## Officially Supported
6
6
 
7
- * [ActiveRecord adapter](https://github.com/jnunemaker/flipper/blob/master/docs/active_record) - Rails 3, 4, and 5.
7
+ * [ActiveRecord adapter](https://github.com/jnunemaker/flipper/blob/master/docs/active_record) - Rails 3, 4, 5, and 6.
8
8
  * [ActiveSupportCacheStore adapter](https://github.com/jnunemaker/flipper/blob/master/docs/active_support_cache_store) - ActiveSupport::Cache::Store
9
9
  * [Cassanity adapter](https://github.com/jnunemaker/flipper-cassanity)
10
10
  * [Http adapter](https://github.com/jnunemaker/flipper/blob/master/docs/http)
@@ -11,7 +11,6 @@ new contributor could start working on code with a minumum efforts.
11
11
  1. Install gems `docker-compose run --rm app bundle install`
12
12
  1. Run specs `docker-compose run --rm app bundle exec rspec`
13
13
  1. Run tests `docker-compose run --rm app bundle exec rake test`
14
- 1. Clear and check files with Rubocop `docker-compose run --rm app bundle exec rubocop -D`
15
14
  1. Optional: log in to container an using a `bash` shell for running specs
16
15
  ```sh
17
16
  docker-compose run --rm app bash
@@ -96,7 +96,7 @@ flipper[:logging].enable percentage
96
96
  flipper[:logging].enabled? # this will return true 5% of the time.
97
97
 
98
98
  # you can also use shortcut methods
99
- flipper.enable_percentage_of_time :search, 5 # registers a feature called "enable_percentage_of_time" and enables it 5% of the time
99
+ flipper.enable_percentage_of_time :search, 5 # registers a feature called "search" and enables it 5% of the time
100
100
  flipper.disable_percentage_of_time :search # sets to 0
101
101
  flipper[:search].enable_percentage_of_time 5
102
102
  flipper[:search].disable_percentage_of_time # sets to 0
@@ -139,7 +139,7 @@ Flipper.register(:admins) do |actor|
139
139
  actor.respond_to?(:admin?) && actor.admin?
140
140
  end
141
141
  ```
142
- - The above first registers a group called `admins` which essentially saves a [Proc](http://www.eriktrautman.com/posts/ruby-explained-blocks-procs-and-lambdas-aka-closures) to be called later.
142
+ - The above first registers a group called `admins` which essentially saves a [Proc](http://www.eriktrautman.com/posts/ruby-explained-blocks-procs-and-lambdas-aka-closures) to be called later. The `actor` is an instance of the `Flipper::Types::Actor` that wraps the thing being checked against and `actor.thing` is the original object being checked.
143
143
 
144
144
  ```
145
145
  flipper[:stats].enable flipper.group(:admins)
@@ -0,0 +1,39 @@
1
+ require File.expand_path('../example_setup', __FILE__)
2
+
3
+ require 'flipper'
4
+ require 'flipper/adapters/operation_logger'
5
+ require 'flipper/instrumentation/log_subscriber'
6
+
7
+ Flipper.configure do |config|
8
+ config.default do
9
+ # pick an adapter, this uses memory, any will do
10
+ adapter = Flipper::Adapters::OperationLogger.new(Flipper::Adapters::Memory.new)
11
+
12
+ # pass adapter to handy DSL instance
13
+ Flipper.new(adapter)
14
+ end
15
+ end
16
+
17
+ Flipper.enable(:foo)
18
+ Flipper.enable(:bar)
19
+ Flipper.disable(:baz)
20
+ Flipper.disable(:wick)
21
+ # reset the operation logging adapter to empty for clarity
22
+ Flipper.adapter.reset
23
+
24
+ # Turn on memoization (the memoizing middleware does this per request).
25
+ Flipper.memoize = true
26
+
27
+ # Preload all the features.
28
+ Flipper.preload_all
29
+
30
+ # Do as many feature checks as your heart desires.
31
+ %w[foo bar baz wick].each do |name|
32
+ Flipper.enabled?(name)
33
+ end
34
+
35
+ # See that only one operation exists, a get_all (which is the preload_all).
36
+ pp Flipper.adapter.operations
37
+ # [#<Flipper::Adapters::OperationLogger::Operation:0x00007fdcfe1100e8
38
+ # @args=[],
39
+ # @type=:get_all>]
@@ -25,13 +25,12 @@ Gem::Specification.new do |gem|
25
25
  gem.authors = ['John Nunemaker']
26
26
  gem.email = ['nunemaker@gmail.com']
27
27
  gem.summary = 'Feature flipper for ANYTHING'
28
- gem.description = 'Feature flipper is the act of enabling/disabling features in your application, ideally without re-deploying or changing anything in your code base. Flipper makes this extremely easy to do with any backend you would like to use.' # rubocop:disable Metrics/LineLength
29
28
  gem.homepage = 'https://github.com/jnunemaker/flipper'
30
29
  gem.license = 'MIT'
31
30
 
32
- gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } # rubocop:disable Metrics/LineLength
33
- gem.files = `git ls-files`.split("\n") - ignored_files + ['lib/flipper/version.rb'] # rubocop:disable Metrics/LineLength
34
- gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") - ignored_test_files # rubocop:disable Metrics/LineLength
31
+ gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
32
+ gem.files = `git ls-files`.split("\n") - ignored_files + ['lib/flipper/version.rb']
33
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") - ignored_test_files
35
34
  gem.name = 'flipper'
36
35
  gem.require_paths = ['lib']
37
36
  gem.version = Flipper::VERSION
@@ -1,7 +1,7 @@
1
1
  require "forwardable"
2
2
 
3
3
  module Flipper
4
- extend self # rubocop:disable Style/ModuleFunction
4
+ extend self
5
5
  extend Forwardable
6
6
 
7
7
  # Private: The namespace for all instrumented events.
@@ -65,7 +65,8 @@ module Flipper
65
65
  :time, :percentage_of_time,
66
66
  :features, :feature, :[], :preload, :preload_all,
67
67
  :adapter, :add, :exist?, :remove, :import,
68
- :memoize=, :memoizing?
68
+ :memoize=, :memoizing?,
69
+ :sync, :sync_secret # For Flipper::Cloud. Will error for OSS Flipper.
69
70
 
70
71
  # Public: Use this to register a group by name.
71
72
  #
@@ -65,7 +65,10 @@ module Flipper
65
65
  # Public
66
66
  def enable(feature, gate, thing)
67
67
  case gate.data_type
68
- when :boolean, :integer
68
+ when :boolean
69
+ clear(feature)
70
+ write key(feature, gate), thing.value.to_s
71
+ when :integer
69
72
  write key(feature, gate), thing.value.to_s
70
73
  when :set
71
74
  set_add key(feature, gate), thing.value.to_s
@@ -84,7 +84,10 @@ module Flipper
84
84
  def enable(feature, gate, thing)
85
85
  @store.transaction do
86
86
  case gate.data_type
87
- when :boolean, :integer
87
+ when :boolean
88
+ clear_gates(feature)
89
+ write key(feature, gate), thing.value.to_s
90
+ when :integer
88
91
  write key(feature, gate), thing.value.to_s
89
92
  when :set
90
93
  set_add key(feature, gate), thing.value.to_s
@@ -34,26 +34,26 @@ module Flipper
34
34
  synchronizer = Synchronizer.new(@local, @remote, sync_options)
35
35
  IntervalSynchronizer.new(synchronizer, interval: options[:interval])
36
36
  end
37
- sync
37
+ synchronize
38
38
  end
39
39
 
40
40
  def features
41
- sync
41
+ synchronize
42
42
  @local.features
43
43
  end
44
44
 
45
45
  def get(feature)
46
- sync
46
+ synchronize
47
47
  @local.get(feature)
48
48
  end
49
49
 
50
50
  def get_multi(features)
51
- sync
51
+ synchronize
52
52
  @local.get_multi(features)
53
53
  end
54
54
 
55
55
  def get_all
56
- sync
56
+ synchronize
57
57
  @local.get_all
58
58
  end
59
59
 
@@ -89,7 +89,7 @@ module Flipper
89
89
 
90
90
  private
91
91
 
92
- def sync
92
+ def synchronize
93
93
  @synchronizer.call
94
94
  end
95
95
  end
@@ -15,6 +15,7 @@ module Flipper
15
15
  # adapter should be brought in line with.
16
16
  # options - The Hash of options.
17
17
  # :instrumenter - The instrumenter used to instrument.
18
+ # :raise - Should errors be raised (default: true).
18
19
  def initialize(local, remote, options = {})
19
20
  @local = local
20
21
  @remote = remote
@@ -5,7 +5,7 @@ require 'flipper/feature_check_context'
5
5
  require 'flipper/gate_values'
6
6
 
7
7
  module Flipper
8
- class Feature # rubocop:disable Metrics/ClassLength
8
+ class Feature
9
9
  # Private: The name of feature instrumentation events.
10
10
  InstrumentationName = "feature_operation.#{InstrumentationNamespace}".freeze
11
11
 
@@ -205,7 +205,7 @@ module Flipper
205
205
  boolean = gate(:boolean)
206
206
  non_boolean_gates = gates - [boolean]
207
207
 
208
- if values.boolean || values.percentage_of_actors == 100 || values.percentage_of_time == 100
208
+ if values.boolean || values.percentage_of_time == 100
209
209
  :on
210
210
  elsif non_boolean_gates.detect { |gate| gate.enabled?(values[gate.key]) }
211
211
  :conditional
@@ -23,7 +23,7 @@ module Flipper
23
23
  #
24
24
  def initialize(app, opts = {})
25
25
  if opts.is_a?(Flipper::DSL) || opts.is_a?(Proc)
26
- raise 'Flipper::Middleware::Memoizer no longer initializes with a flipper instance or block. Read more at: https://git.io/vSo31.' # rubocop:disable LineLength
26
+ raise 'Flipper::Middleware::Memoizer no longer initializes with a flipper instance or block. Read more at: https://git.io/vSo31.'
27
27
  end
28
28
 
29
29
  @app = app
@@ -7,7 +7,8 @@ module Flipper
7
7
  #
8
8
  # app - The app this middleware is included in.
9
9
  # flipper_or_block - The Flipper::DSL instance or a block that yields a
10
- # Flipper::DSL instance to use for all operations.
10
+ # Flipper::DSL instance to use for all operations
11
+ # (optional, default: Flipper).
11
12
  #
12
13
  # Examples
13
14
  #
@@ -19,18 +20,27 @@ module Flipper
19
20
  # # using with a block that yields a flipper instance
20
21
  # use Flipper::Middleware::SetupEnv, lambda { Flipper.new(...) }
21
22
  #
22
- def initialize(app, flipper_or_block, options = {})
23
+ # # using default configured Flipper instance
24
+ # Flipper.configure do |config|
25
+ # config.default { Flipper.new(...) }
26
+ # end
27
+ # use Flipper::Middleware::SetupEnv
28
+ def initialize(app, flipper_or_block = nil, options = {})
23
29
  @app = app
24
30
  @env_key = options.fetch(:env_key, 'flipper')
25
31
 
26
32
  if flipper_or_block.respond_to?(:call)
27
33
  @flipper_block = flipper_or_block
28
34
  else
29
- @flipper = flipper_or_block
35
+ @flipper = flipper_or_block || Flipper
30
36
  end
31
37
  end
32
38
 
33
39
  def call(env)
40
+ dup.call!(env)
41
+ end
42
+
43
+ def call!(env)
34
44
  env[@env_key] ||= flipper
35
45
  @app.call(env)
36
46
  end
@@ -289,4 +289,19 @@ RSpec.shared_examples_for 'a flipper adapter' do
289
289
  expect(subject.enable(feature, boolean_gate, flipper.boolean)).to eq(true)
290
290
  expect(subject.enable(feature, boolean_gate, flipper.boolean)).to eq(true)
291
291
  end
292
+
293
+ it 'can get_all features when there are none' do
294
+ expect(subject.features).to eq(Set.new)
295
+ expect(subject.get_all).to eq({})
296
+ end
297
+
298
+ it 'clears other gate values on enable' do
299
+ actor = Flipper::Actor.new('Flipper::Actor;22')
300
+ subject.enable(feature, actors_gate, flipper.actors(25))
301
+ subject.enable(feature, time_gate, flipper.time(25))
302
+ subject.enable(feature, group_gate, flipper.group(:admins))
303
+ subject.enable(feature, actor_gate, flipper.actor(actor))
304
+ subject.enable(feature, boolean_gate, flipper.boolean(true))
305
+ expect(subject.get(feature)).to eq(subject.default_config.merge(boolean: "true"))
306
+ end
292
307
  end
@@ -1,4 +1,3 @@
1
- # rubocop:disable Metrics/ModuleLength
2
1
  module Flipper
3
2
  module Test
4
3
  module SharedAdapterTests
@@ -285,6 +284,22 @@ module Flipper
285
284
  assert_equal true, @adapter.enable(@feature, @boolean_gate, @flipper.boolean)
286
285
  assert_equal true, @adapter.enable(@feature, @boolean_gate, @flipper.boolean)
287
286
  end
287
+
288
+ def test_can_get_all_features_when_there_are_none
289
+ expected = {}
290
+ assert_equal Set.new, @adapter.features
291
+ assert_equal expected, @adapter.get_all
292
+ end
293
+
294
+ def test_clears_other_gate_values_on_enable
295
+ actor = Flipper::Actor.new('Flipper::Actor;22')
296
+ assert_equal true, @adapter.enable(@feature, @actors_gate, @flipper.actors(25))
297
+ assert_equal true, @adapter.enable(@feature, @time_gate, @flipper.time(25))
298
+ assert_equal true, @adapter.enable(@feature, @group_gate, @flipper.group(:admins))
299
+ assert_equal true, @adapter.enable(@feature, @actor_gate, @flipper.actor(actor))
300
+ assert_equal true, @adapter.enable(@feature, @boolean_gate, @flipper.boolean(true))
301
+ assert_equal @adapter.default_config.merge(boolean: "true"), @adapter.get(@feature)
302
+ end
288
303
  end
289
304
  end
290
305
  end
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = '0.17.1'.freeze
2
+ VERSION = '0.20.0.beta1'.freeze
3
3
  end
@@ -16,7 +16,7 @@ RSpec.describe Flipper::Adapter do
16
16
  describe '.default_config' do
17
17
  it 'returns default config' do
18
18
  adapter_class = Class.new do
19
- include Flipper::Adapter # rubocop:disable RSpec/DescribedClass
19
+ include Flipper::Adapter
20
20
  end
21
21
  expect(adapter_class.default_config).to eq(default_config)
22
22
  end
@@ -25,7 +25,7 @@ RSpec.describe Flipper::Adapter do
25
25
  describe '#default_config' do
26
26
  it 'returns default config' do
27
27
  adapter_class = Class.new do
28
- include Flipper::Adapter # rubocop:disable RSpec/DescribedClass
28
+ include Flipper::Adapter
29
29
  end
30
30
  expect(adapter_class.new.default_config).to eq(default_config)
31
31
  end
@@ -175,22 +175,22 @@ RSpec.describe Flipper::Adapters::Sync do
175
175
  end
176
176
 
177
177
  it 'synchronizes for #features' do
178
- expect(subject).to receive(:sync)
178
+ expect(subject).to receive(:synchronize)
179
179
  subject.features
180
180
  end
181
181
 
182
182
  it 'synchronizes for #get' do
183
- expect(subject).to receive(:sync)
183
+ expect(subject).to receive(:synchronize)
184
184
  subject.get sync[:search]
185
185
  end
186
186
 
187
187
  it 'synchronizes for #get_multi' do
188
- expect(subject).to receive(:sync)
188
+ expect(subject).to receive(:synchronize)
189
189
  subject.get_multi [sync[:search]]
190
190
  end
191
191
 
192
192
  it 'synchronizes for #get_all' do
193
- expect(subject).to receive(:sync)
193
+ expect(subject).to receive(:synchronize)
194
194
  subject.get_all
195
195
  end
196
196