flipper 0.17.1 → 0.20.0.beta1

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
  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