flipper 0.23.1 → 0.25.0

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: a41bf1dd43734d1d6c6b56a46ea393af74164d46aadd7671994bdcc10e4eb646
4
- data.tar.gz: e935dc1375a66156f0d0f7ba967269d184b8babaf119333c614943643f760ed7
3
+ metadata.gz: 896d9fb7468ffbc19e1200a6abe2a5c3992fae7abb3d4211fd29829364fb1a42
4
+ data.tar.gz: e157fa74da897e4ad56b3548cd438adc0ddbc0e2fec89e4d8214dd4ca2b2596e
5
5
  SHA512:
6
- metadata.gz: 82d249a9f90b96fcf88713890a2df5a7fa5f05927b7a1903630e276507ee709b5426b91fba46aa6ef034e15dc6b50b35781d61b56afe512a46673e4de3eb559d
7
- data.tar.gz: c986d6fb7c1a773ab56e6b7cb35734648485562690799dff901578b2c31566f5582bb8390268228f48eda9fba6797f8b72bd7fd385e45a9a04155c14a4c8b95f
6
+ metadata.gz: c99039ff6cc5dc62953289d9343bcee6b2d2935e52b4cc7b33f5134c266a3ac99180d713220432cbde7e2cb57a90d42e41249eb0bcf55f20eb60a9e0cc379208
7
+ data.tar.gz: 9f3b2dea4b9137b20f86d359a5dd5eb3b220655364dc9baf498faecbd42ddca286f6d94e91694b203d21cce8c0a986ed421e6f7436ec0fd956d9e590698ec59c
@@ -15,13 +15,17 @@ jobs:
15
15
  --health-retries 5
16
16
  strategy:
17
17
  matrix:
18
- ruby: ['2.5', '2.6', '2.7']
18
+ ruby: ['2.6', '2.7', '3.0', '3.1']
19
19
  rails: ['5.2', '6.0.0', '6.1.0', '7.0.0']
20
20
  exclude:
21
- - ruby: "2.5"
22
- rails: "7.0.0"
23
21
  - ruby: "2.6"
24
22
  rails: "7.0.0"
23
+ - ruby: "3.0"
24
+ rails: "5.2"
25
+ - ruby: "3.1"
26
+ rails: "5.2"
27
+ - ruby: "3.1"
28
+ rails: "6.0.0"
25
29
  env:
26
30
  SQLITE3_VERSION: 1.4.1
27
31
  REDIS_URL: redis://localhost:6379/0
@@ -43,7 +47,7 @@ jobs:
43
47
  restore-keys: |
44
48
  ${{ runner.os }}-gems-${{ matrix.ruby }}-${{ matrix.rails }}-
45
49
  - name: Set up Ruby ${{ matrix.ruby }}
46
- uses: actions/setup-ruby@v1
50
+ uses: ruby/setup-ruby@v1
47
51
  with:
48
52
  ruby-version: ${{ matrix.ruby }}
49
53
  - name: Install libpq-dev
@@ -16,8 +16,18 @@ jobs:
16
16
  --health-retries 5
17
17
  strategy:
18
18
  matrix:
19
- ruby: ['2.5', '2.6', '2.7']
20
- rails: ['5.2', '6.0.0', '6.1.0']
19
+ ruby: ['2.6', '2.7', '3.0', '3.1']
20
+ rails: ['5.2', '6.0.0', '6.1.0', '7.0.0']
21
+ exclude:
22
+ - ruby: "2.6"
23
+ rails: "7.0.0"
24
+ - ruby: "3.0"
25
+ rails: "5.2"
26
+ - ruby: "3.1"
27
+ rails: "5.2"
28
+ - ruby: "3.1"
29
+ rails: "6.0.0"
30
+
21
31
  env:
22
32
  SQLITE3_VERSION: 1.4.1
23
33
  REDIS_URL: redis://localhost:6379/0
@@ -39,7 +49,7 @@ jobs:
39
49
  restore-keys: |
40
50
  ${{ runner.os }}-gems-${{ matrix.ruby }}-${{ matrix.rails }}-
41
51
  - name: Set up Ruby ${{ matrix.ruby }}
42
- uses: actions/setup-ruby@v1
52
+ uses: ruby/setup-ruby@v1
43
53
  with:
44
54
  ruby-version: ${{ matrix.ruby }}
45
55
  - name: Install libpq-dev
data/Changelog.md CHANGED
@@ -1,3 +1,34 @@
1
+ ## Unreleased
2
+
3
+ ### Additions/Changes
4
+
5
+ * Added a prompt in Flipper UI for the 'Delete' button to prevent accidental delete of features (https://github.com/jnunemaker/flipper/pull/625)
6
+ * Added failsafe adapter (https://github.com/jnunemaker/flipper/pull/626)
7
+ * Removed previously deprecated options and settings. Those upgrading from `<0.21` should upgrade to `~>0.24` first and fix any deprecation warnings when initializing Flipper. (https://github.com/jnunemaker/flipper/pull/627)
8
+ * ActiveRecord: base class for internal models (https://github.com/jnunemaker/flipper/pull/629)
9
+ * Remove use of `Rack::BodyProxy` in the memoizer middleware (https://github.com/jnunemaker/flipper/pull/631)
10
+
11
+ ## 0.24.1
12
+
13
+ ### Additions/Changes
14
+
15
+ * flipper-api: `exclude_gates` parameter to exclude gate data in GETs (https://github.com/jnunemaker/flipper/pull/572).
16
+ * Make it possible to disable internal memoization (https://github.com/jnunemaker/flipper/pull/612).
17
+ * Add Flipper::Actor#hash so actors can be hash keys (https://github.com/jnunemaker/flipper/pull/616).
18
+ * Pretty Up `rails routes` again and make rack-protection dependency less strict (https://github.com/jnunemaker/flipper/pull/619).
19
+ * Add kwargs for method_missing using ruby 3.0 (https://github.com/jnunemaker/flipper/pull/620).
20
+ * Relax the rack-protection dependency (https://github.com/jnunemaker/flipper/commit/c1cb9cd78140c2b09123687642558101e6e5d37d).
21
+
22
+ ## 0.24.0
23
+
24
+ ### Additions/Changes
25
+
26
+ * Add Ruby 3.0 and 3.1 to the CI matrix and fix groups block arity check for ruby 3 (https://github.com/jnunemaker/flipper/pull/601)
27
+ * Removed support for Ruby 2.5 (which was end of line 9 months ago)
28
+ * Add (alpha) client side instrumentation of events to cloud (https://github.com/jnunemaker/flipper/pull/602)
29
+ * Fix deprecated uses of Redis#pipelined (https://github.com/jnunemaker/flipper/pull/603). redis-rb >= 3 now required.
30
+ * Fix Flipper UI Rack application when `Rack::Session::Pool` is used to build it (https://github.com/jnunemaker/flipper/pull/606).
31
+
1
32
  ## 0.23.1
2
33
 
3
34
  ### Additions/Changes
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM ruby:2.5
1
+ FROM ruby:3.0
2
2
 
3
3
  RUN apt-get update && apt-get install -y \
4
4
  # build-essential \
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ Dir['flipper-*.gemspec'].each do |gemspec|
6
6
  gemspec(name: "flipper-#{plugin}", development_group: plugin)
7
7
  end
8
8
 
9
- gem 'pry'
9
+ gem 'debug'
10
10
  gem 'rake', '~> 12.3.3'
11
11
  gem 'shotgun', '~> 0.9'
12
12
  gem 'statsd-ruby', '~> 1.2.1'
data/lib/flipper/actor.rb CHANGED
@@ -12,5 +12,9 @@ module Flipper
12
12
  self.class.eql?(other.class) && @flipper_id == other.flipper_id
13
13
  end
14
14
  alias_method :==, :eql?
15
+
16
+ def hash
17
+ flipper_id.hash
18
+ end
15
19
  end
16
20
  end
@@ -0,0 +1,76 @@
1
+ module Flipper
2
+ module Adapters
3
+ class Failsafe
4
+ include ::Flipper::Adapter
5
+
6
+ # Public: The name of the adapter.
7
+ attr_reader :name
8
+
9
+ # Public: Build a new Failsafe instance.
10
+ #
11
+ # adapter - Flipper adapter to guard.
12
+ # options - Hash of options:
13
+ # :errors - Array of exception types for which to fail safe
14
+
15
+ def initialize(adapter, options = {})
16
+ @adapter = adapter
17
+ @errors = options.fetch(:errors, [StandardError])
18
+ @name = :failsafe
19
+ end
20
+
21
+ def features
22
+ @adapter.features
23
+ rescue *@errors
24
+ Set.new
25
+ end
26
+
27
+ def add(feature)
28
+ @adapter.add(feature)
29
+ rescue *@errors
30
+ false
31
+ end
32
+
33
+ def remove(feature)
34
+ @adapter.remove(feature)
35
+ rescue *@errors
36
+ false
37
+ end
38
+
39
+ def clear(feature)
40
+ @adapter.clear(feature)
41
+ rescue *@errors
42
+ false
43
+ end
44
+
45
+ def get(feature)
46
+ @adapter.get(feature)
47
+ rescue *@errors
48
+ {}
49
+ end
50
+
51
+ def get_multi(features)
52
+ @adapter.get_multi(features)
53
+ rescue *@errors
54
+ {}
55
+ end
56
+
57
+ def get_all
58
+ @adapter.get_all
59
+ rescue *@errors
60
+ {}
61
+ end
62
+
63
+ def enable(feature, gate, thing)
64
+ @adapter.enable(feature, gate, thing)
65
+ rescue *@errors
66
+ false
67
+ end
68
+
69
+ def disable(feature, gate, thing)
70
+ @adapter.disable(feature, gate, thing)
71
+ rescue *@errors
72
+ false
73
+ end
74
+ end
75
+ end
76
+ end
data/lib/flipper/dsl.rb CHANGED
@@ -17,10 +17,12 @@ module Flipper
17
17
  # adapter - The adapter that this DSL instance should use.
18
18
  # options - The Hash of options.
19
19
  # :instrumenter - What should be used to instrument all the things.
20
+ # :memoize - Should adapter be wrapped by memoize adapter or not.
20
21
  def initialize(adapter, options = {})
21
22
  @instrumenter = options.fetch(:instrumenter, Instrumenters::Noop)
22
- memoized = Adapters::Memoizable.new(adapter)
23
- @adapter = memoized
23
+ memoize = options.fetch(:memoize, true)
24
+ adapter = Adapters::Memoizable.new(adapter) if memoize
25
+ @adapter = adapter
24
26
  @memoized_features = {}
25
27
  end
26
28
 
@@ -12,15 +12,6 @@ module Flipper
12
12
  # Raised when attempting to declare a group name that has already been used.
13
13
  class DuplicateGroup < Error; end
14
14
 
15
- # Raised when default instance not configured but there is an attempt to
16
- # use it.
17
- class DefaultNotSet < Flipper::Error
18
- def initialize(message = nil)
19
- warn "Flipper::DefaultNotSet is deprecated and will be removed in 1.0"
20
- super
21
- end
22
- end
23
-
24
15
  # Raised when an invalid value is set to a configuration property
25
16
  class InvalidConfigurationValue < Flipper::Error
26
17
  def initialize(message = nil)
@@ -28,12 +19,4 @@ module Flipper
28
19
  super(message || default)
29
20
  end
30
21
  end
31
-
32
- # Raised when accessing a configuration property that has been deprecated
33
- class ConfigurationDeprecated < Flipper::Error
34
- def initialize(message = nil)
35
- default = "The configuration property has been deprecated"
36
- super(message || default)
37
- end
38
- end
39
22
  end
@@ -25,11 +25,6 @@ module Flipper
25
25
  raise 'Flipper::Middleware::Memoizer no longer initializes with a flipper instance or block. Read more at: https://git.io/vSo31.'
26
26
  end
27
27
 
28
- if opts[:preload_all]
29
- warn "Flipper::Middleware::Memoizer: `preload_all` is deprecated, use `preload: true`"
30
- opts[:preload] = true
31
- end
32
-
33
28
  @app = app
34
29
  @opts = opts
35
30
  @env_key = opts.fetch(:env_key, 'flipper')
@@ -74,14 +69,9 @@ module Flipper
74
69
  when Array then flipper.preload(@opts[:preload])
75
70
  end
76
71
 
77
- response = @app.call(env)
78
- response[2] = Rack::BodyProxy.new(response[2]) do
79
- flipper.memoize = false
80
- end
81
- reset_on_body_close = true
82
- response
72
+ @app.call(env)
83
73
  ensure
84
- flipper.memoize = false if flipper && !reset_on_body_close
74
+ flipper.memoize = false if flipper
85
75
  end
86
76
  end
87
77
  end
@@ -23,8 +23,14 @@ module Flipper
23
23
  super || @thing.respond_to?(*args)
24
24
  end
25
25
 
26
- def method_missing(name, *args, &block)
27
- @thing.send name, *args, &block
26
+ if RUBY_VERSION >= '3.0'
27
+ def method_missing(name, *args, **kwargs, &block)
28
+ @thing.send name, *args, **kwargs, &block
29
+ end
30
+ else
31
+ def method_missing(name, *args, &block)
32
+ @thing.send name, *args, &block
33
+ end
28
34
  end
29
35
  end
30
36
  end
@@ -14,7 +14,7 @@ module Flipper
14
14
 
15
15
  if block_given?
16
16
  @block = block
17
- @single_argument = @block.arity.abs == 1
17
+ @single_argument = call_with_no_context?(@block)
18
18
  else
19
19
  @block = ->(_thing, _context) { false }
20
20
  @single_argument = false
@@ -28,6 +28,13 @@ module Flipper
28
28
  @block.call(thing, context)
29
29
  end
30
30
  end
31
+
32
+ NO_PARAMS_IN_RUBY_3 = [[:req], [:rest]]
33
+ def call_with_no_context?(block)
34
+ return true if block.parameters == NO_PARAMS_IN_RUBY_3
35
+
36
+ block.arity.abs == 1
37
+ end
31
38
  end
32
39
  end
33
40
  end
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = '0.23.1'.freeze
2
+ VERSION = '0.25.0'.freeze
3
3
  end
@@ -43,4 +43,14 @@ RSpec.describe Flipper::Actor do
43
43
  expect(actor1.==(actor2)).to be(false)
44
44
  end
45
45
  end
46
+
47
+ describe '#hash' do
48
+ it 'returns a hash-value based on the flipper id' do
49
+ h = {
50
+ described_class.new("User;123") => true
51
+ }
52
+ expect(h).to have_key(described_class.new("User;123"))
53
+ expect(h).not_to have_key(described_class.new("User;456"))
54
+ end
55
+ end
46
56
  end
@@ -0,0 +1,58 @@
1
+ require 'flipper/adapters/failsafe'
2
+
3
+ RSpec.describe Flipper::Adapters::Failsafe do
4
+ subject { described_class.new(memory_adapter, options) }
5
+
6
+ let(:memory_adapter) { Flipper::Adapters::Memory.new }
7
+ let(:options) { {} }
8
+ let(:flipper) { Flipper.new(subject) }
9
+
10
+ it_should_behave_like 'a flipper adapter'
11
+
12
+ context 'when disaster strikes' do
13
+ before do
14
+ expect(flipper[feature.name].enable).to be(true)
15
+
16
+ (subject.methods - Object.methods).each do |method_name|
17
+ allow(memory_adapter).to receive(method_name).and_raise(IOError)
18
+ end
19
+ end
20
+
21
+ let(:feature) { Flipper::Feature.new(:my_feature, subject) }
22
+
23
+ it { expect(subject.features).to eq(Set.new) }
24
+ it { expect(feature.add).to eq(false) }
25
+ it { expect(feature.remove).to eq(false) }
26
+ it { expect(feature.clear).to eq(false) }
27
+ it { expect(subject.get(feature)).to eq({}) }
28
+ it { expect(subject.get_multi([feature])).to eq({}) }
29
+ it { expect(subject.get_all).to eq({}) }
30
+ it { expect(feature.enable).to eq(false) }
31
+ it { expect(feature.disable).to eq(false) }
32
+
33
+ context 'when used via Flipper' do
34
+ it { expect(flipper.features).to eq(Set.new) }
35
+ it { expect(flipper[feature.name].enabled?).to eq(false) }
36
+ it { expect(flipper[feature.name].enable).to eq(false) }
37
+ it { expect(flipper[feature.name].disable).to eq(false) }
38
+ end
39
+
40
+ context 'when there is a syntax error' do
41
+ let(:test) { flipper[feature.name].enabled? }
42
+
43
+ before do
44
+ expect(memory_adapter).to receive(:get).and_raise(SyntaxError)
45
+ end
46
+
47
+ it 'does not catch this type of error' do
48
+ expect { test }.to raise_error(SyntaxError)
49
+ end
50
+
51
+ context 'when configured to catch SyntaxError' do
52
+ let(:options) { { errors: [SyntaxError] } }
53
+
54
+ it { expect(test).to eq(false) }
55
+ end
56
+ end
57
+ end
58
+ end
@@ -6,9 +6,19 @@ RSpec.describe Flipper::DSL do
6
6
  let(:adapter) { Flipper::Adapters::Memory.new }
7
7
 
8
8
  describe '#initialize' do
9
- it 'sets adapter' do
10
- dsl = described_class.new(adapter)
11
- expect(dsl.adapter).not_to be_nil
9
+ context 'when using default memoize strategy' do
10
+ it 'wraps the given adapter with Flipper::Adapters::Memoizable' do
11
+ dsl = described_class.new(adapter)
12
+ expect(dsl.adapter.class).to be(Flipper::Adapters::Memoizable)
13
+ expect(dsl.adapter.adapter).to be(adapter)
14
+ end
15
+ end
16
+
17
+ context 'when disabling memoization' do
18
+ it 'uses the given adapter directly' do
19
+ dsl = described_class.new(adapter, memoize: false)
20
+ expect(dsl.adapter).to be(adapter)
21
+ end
12
22
  end
13
23
 
14
24
  it 'defaults instrumenter to noop' do
@@ -38,26 +38,6 @@ RSpec.describe Flipper::Middleware::Memoizer do
38
38
  expect(called).to eq(true)
39
39
  end
40
40
 
41
- it 'disables local cache after body close' do
42
- app = ->(_env) { [200, {}, []] }
43
- middleware = described_class.new(app)
44
- body = middleware.call(env).last
45
-
46
- expect(flipper.memoizing?).to eq(true)
47
- body.close
48
- expect(flipper.memoizing?).to eq(false)
49
- end
50
-
51
- it 'clears local cache after body close' do
52
- app = ->(_env) { [200, {}, []] }
53
- middleware = described_class.new(app)
54
- body = middleware.call(env).last
55
-
56
- flipper.adapter.cache['hello'] = 'world'
57
- body.close
58
- expect(flipper.adapter.cache).to be_empty
59
- end
60
-
61
41
  it 'clears the local cache with a successful request' do
62
42
  flipper.adapter.cache['hello'] = 'world'
63
43
  get '/', {}, 'flipper' => flipper
data/spec/spec_helper.rb CHANGED
@@ -9,7 +9,7 @@ require 'bundler'
9
9
 
10
10
  Bundler.setup(:default)
11
11
 
12
- require 'pry'
12
+ require 'debug'
13
13
  require 'webmock/rspec'
14
14
  WebMock.disable_net_connect!(allow_localhost: true)
15
15
 
@@ -22,6 +22,7 @@ Dir[FlipperRoot.join('spec/support/**/*.rb')].sort.each { |f| require f }
22
22
 
23
23
  RSpec.configure do |config|
24
24
  config.before(:example) do
25
+ Flipper::Cloud::Registry.default.clear if defined?(Flipper::Cloud)
25
26
  Flipper.unregister_groups
26
27
  Flipper.configuration = nil
27
28
  end
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.23.1
4
+ version: 0.25.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: 2022-01-19 00:00:00.000000000 Z
11
+ date: 2022-06-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -57,6 +57,7 @@ files:
57
57
  - lib/flipper/adapter.rb
58
58
  - lib/flipper/adapters/dual_write.rb
59
59
  - lib/flipper/adapters/failover.rb
60
+ - lib/flipper/adapters/failsafe.rb
60
61
  - lib/flipper/adapters/http.rb
61
62
  - lib/flipper/adapters/http/client.rb
62
63
  - lib/flipper/adapters/http/error.rb
@@ -110,6 +111,7 @@ files:
110
111
  - spec/flipper/adapter_spec.rb
111
112
  - spec/flipper/adapters/dual_write_spec.rb
112
113
  - spec/flipper/adapters/failover_spec.rb
114
+ - spec/flipper/adapters/failsafe_spec.rb
113
115
  - spec/flipper/adapters/http_spec.rb
114
116
  - spec/flipper/adapters/instrumented_spec.rb
115
117
  - spec/flipper/adapters/memoizable_spec.rb
@@ -188,6 +190,7 @@ test_files:
188
190
  - spec/flipper/adapter_spec.rb
189
191
  - spec/flipper/adapters/dual_write_spec.rb
190
192
  - spec/flipper/adapters/failover_spec.rb
193
+ - spec/flipper/adapters/failsafe_spec.rb
191
194
  - spec/flipper/adapters/http_spec.rb
192
195
  - spec/flipper/adapters/instrumented_spec.rb
193
196
  - spec/flipper/adapters/memoizable_spec.rb