flipper 0.28.0 → 0.28.1

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: a581a01f7e6dade34fb261d0b6215f262125e4041a0095081dd54719db303656
4
- data.tar.gz: 1d3df8718d8a46f88cb33e97e4ef2d193e0eae2dd2cf4eecd23fc87dd977d11a
3
+ metadata.gz: 5373416d79c0f4e67654bf9945bb4b1702fae520946f127be970fa89a7f3151a
4
+ data.tar.gz: 194180daeb197f5f2323363915de63daea4458486585eb687c76d380cc48df93
5
5
  SHA512:
6
- metadata.gz: e56bd86ca42668104197ad8b64596f7639bbf25c04ac48e3da6cff8f3d71736ab62282d9e01a13f2eb85fa7c058a11e2360e1a260fe249972e16f911d83ca2f5
7
- data.tar.gz: a11b459234c76ac9ab928b26c9e12009736af655f602a04557d776dc72579877cf1b7ab38f4faecd54d49b765186ff0bf754eef174a96ee1f5a584daf2dacd16
6
+ metadata.gz: 8e6652132da82dfd9ee46419d3f4fcc9836b6464fe2a89d670e17315f1664db6f88784ab3b3006b2aa43b150461a1645791d9334d96b93dd685b31cf98909a1d
7
+ data.tar.gz: 161e2acea4928753b8ebb8d83e9fa05e33dcee6bab15cc2323c3acc3beb8d5e95f96aace11ffceddcc2dc035ee3d9aa3918f61e956a9c4eeb243387c8eacf87a
data/Changelog.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 0.28.1
6
+
7
+ ### Additions/Changes
8
+
9
+ * Use new method of making logs bold for rails (https://github.com/jnunemaker/flipper/pull/726)
10
+ * Bundle bootstrap, jquery and poppler with the library. (https://github.com/jnunemaker/flipper/pull/731)
11
+
5
12
  ## 0.28.0
6
13
 
7
14
  ### Additions/Changes
@@ -11,6 +18,24 @@ All notable changes to this project will be documented in this file.
11
18
  - [user, user.team, user.org].any? { |actor| Flipper.enabled?(:my_feature, actor) }
12
19
  + Flipper.enabled?(:my_feature, user, user.team, user.org)
13
20
  ```
21
+ * If you currently use `actor.thing` in a group, you'll need to change it to `actor.actor`.
22
+ ```diff
23
+ - Flipper.register(:our_group) do |actor|
24
+ - actor.thing.is_a?(OurClassName)
25
+ - end
26
+ + Flipper.register(:our_group) do |actor|
27
+ + actor.actor.is_a?(OurClassName)
28
+ + end
29
+ ```
30
+ * If you currently use `context.thing` in a group or elsewhere, you'll need to change it to `context.actors`.
31
+ ```diff
32
+ - Flipper.register(:our_group) do |actor, context|
33
+ - context.thing.is_a?(OurClassName)
34
+ - end
35
+ + Flipper.register(:our_group) do |actor, context|
36
+ + context.actors.any? { |actor| actor.is_a?(OurClassName) }
37
+ + end
38
+ ```
14
39
 
15
40
  ### Deprecations
16
41
 
@@ -0,0 +1,59 @@
1
+ require 'bundler/setup'
2
+ require_relative 'active_record/ar_setup'
3
+ require 'flipper'
4
+ require 'flipper/adapters/redis'
5
+ require 'flipper/adapters/active_record'
6
+
7
+ # Say you have production...
8
+ production_adapter = Flipper::Adapters::Memory.new
9
+ production = Flipper.new(production_adapter)
10
+
11
+ # And production has some stuff enabled...
12
+ production.enable(:search)
13
+ production.enable_percentage_of_time(:verbose_logging, 5)
14
+ production.enable_percentage_of_actors(:new_feature, 5)
15
+ production.enable_actor(:issues, Flipper::Actor.new('1'))
16
+ production.enable_actor(:issues, Flipper::Actor.new('2'))
17
+ production.enable_group(:request_tracing, :staff)
18
+
19
+ # And you would like to mirror production to staging...
20
+ staging_adapter = Flipper::Adapters::Memory.new
21
+ staging = Flipper.new(staging_adapter)
22
+ staging_export = staging.export
23
+
24
+ puts "Here is the state of the world for staging and production..."
25
+ puts "Staging"
26
+ staging.features.each do |feature|
27
+ pp feature: feature.key, values: feature.gate_values
28
+ end
29
+ puts "Production"
30
+ production.features.each do |feature|
31
+ pp feature: feature.key, values: feature.gate_values
32
+ end
33
+
34
+ # NOTE: This wipes active record clean and copies features/gates from redis into active record.
35
+ puts "Mirroring production to staging..."
36
+ staging.import(production.export)
37
+ puts "Staging is now identical to Production."
38
+
39
+ puts "Staging"
40
+ staging.features.each do |feature|
41
+ pp feature: feature.key, values: feature.gate_values
42
+ end
43
+ puts "Production"
44
+ production.features.each do |feature|
45
+ pp feature: feature.key, values: feature.gate_values
46
+ end
47
+
48
+ puts "Restoring staging to original state..."
49
+ staging.import(staging_export)
50
+ puts "Staging restored."
51
+
52
+ puts "Staging"
53
+ staging.features.each do |feature|
54
+ pp feature: feature.key, values: feature.gate_values
55
+ end
56
+ puts "Production"
57
+ production.features.each do |feature|
58
+ pp feature: feature.key, values: feature.gate_values
59
+ end
@@ -1,6 +1,5 @@
1
1
  require "flipper/adapter"
2
2
  require "flipper/typecast"
3
- require 'concurrent/atomic/read_write_lock'
4
3
 
5
4
  module Flipper
6
5
  module Adapters
@@ -15,43 +14,44 @@ module Flipper
15
14
  attr_reader :name
16
15
 
17
16
  # Public
18
- def initialize(source = nil)
17
+ def initialize(source = nil, threadsafe: true)
19
18
  @source = Typecast.features_hash(source)
20
19
  @name = :memory
21
- @lock = Concurrent::ReadWriteLock.new
20
+ @lock = Mutex.new if threadsafe
21
+ reset
22
22
  end
23
23
 
24
24
  # Public: The set of known features.
25
25
  def features
26
- @lock.with_read_lock { @source.keys }.to_set
26
+ synchronize { @source.keys }.to_set
27
27
  end
28
28
 
29
29
  # Public: Adds a feature to the set of known features.
30
30
  def add(feature)
31
- @lock.with_write_lock { @source[feature.key] ||= default_config }
31
+ synchronize { @source[feature.key] ||= default_config }
32
32
  true
33
33
  end
34
34
 
35
35
  # Public: Removes a feature from the set of known features and clears
36
36
  # all the values for the feature.
37
37
  def remove(feature)
38
- @lock.with_write_lock { @source.delete(feature.key) }
38
+ synchronize { @source.delete(feature.key) }
39
39
  true
40
40
  end
41
41
 
42
42
  # Public: Clears all the gate values for a feature.
43
43
  def clear(feature)
44
- @lock.with_write_lock { @source[feature.key] = default_config }
44
+ synchronize { @source[feature.key] = default_config }
45
45
  true
46
46
  end
47
47
 
48
48
  # Public
49
49
  def get(feature)
50
- @lock.with_read_lock { @source[feature.key] } || default_config
50
+ synchronize { @source[feature.key] } || default_config
51
51
  end
52
52
 
53
53
  def get_multi(features)
54
- @lock.with_read_lock do
54
+ synchronize do
55
55
  result = {}
56
56
  features.each do |feature|
57
57
  result[feature.key] = @source[feature.key] || default_config
@@ -61,12 +61,12 @@ module Flipper
61
61
  end
62
62
 
63
63
  def get_all
64
- @lock.with_read_lock { Typecast.features_hash(@source) }
64
+ synchronize { Typecast.features_hash(@source) }
65
65
  end
66
66
 
67
67
  # Public
68
68
  def enable(feature, gate, thing)
69
- @lock.with_write_lock do
69
+ synchronize do
70
70
  @source[feature.key] ||= default_config
71
71
 
72
72
  case gate.data_type
@@ -87,7 +87,7 @@ module Flipper
87
87
 
88
88
  # Public
89
89
  def disable(feature, gate, thing)
90
- @lock.with_write_lock do
90
+ synchronize do
91
91
  @source[feature.key] ||= default_config
92
92
 
93
93
  case gate.data_type
@@ -118,9 +118,29 @@ module Flipper
118
118
  def import(source)
119
119
  adapter = self.class.from(source)
120
120
  get_all = Typecast.features_hash(adapter.get_all)
121
- @lock.with_write_lock { @source.replace(get_all) }
121
+ synchronize { @source.replace(get_all) }
122
122
  true
123
123
  end
124
+
125
+ private
126
+
127
+ def reset
128
+ @pid = Process.pid
129
+ @lock&.unlock if @lock&.locked?
130
+ end
131
+
132
+ def forked?
133
+ @pid != Process.pid
134
+ end
135
+
136
+ def synchronize(&block)
137
+ if @lock
138
+ reset if forked?
139
+ @lock.synchronize(&block)
140
+ else
141
+ block.call
142
+ end
143
+ end
124
144
  end
125
145
  end
126
146
  end
@@ -32,7 +32,7 @@ module Flipper
32
32
  details += " gate_name=#{gate_name}" unless gate_name.nil?
33
33
 
34
34
  name = '%s (%.1fms)' % [description, event.duration]
35
- debug " #{color(name, CYAN, true)} [ #{details} ]"
35
+ debug " #{color_name(name)} [ #{details} ]"
36
36
  end
37
37
 
38
38
  # Logs an adapter operation. If operation is for a feature, then that
@@ -64,12 +64,27 @@ module Flipper
64
64
  details = "result=#{result.inspect}"
65
65
 
66
66
  name = '%s (%.1fms)' % [description, event.duration]
67
- debug " #{color(name, CYAN, true)} [ #{details} ]"
67
+ debug " #{color_name(name)} [ #{details} ]"
68
68
  end
69
69
 
70
70
  def logger
71
71
  self.class.logger
72
72
  end
73
+
74
+ private
75
+
76
+ # Rails 7.1 changed the signature of this function.
77
+ # Checking if > 7.0.99 rather than >= 7.1 so that 7.1 pre-release versions are included.
78
+ COLOR_OPTIONS = if Rails.gem_version > Gem::Version.new('7.0.99')
79
+ { bold: true }.freeze
80
+ else
81
+ true
82
+ end
83
+ private_constant :COLOR_OPTIONS
84
+
85
+ def color_name(name)
86
+ color(name, CYAN, COLOR_OPTIONS)
87
+ end
73
88
  end
74
89
  end
75
90
 
@@ -28,7 +28,7 @@ module Flipper
28
28
  @remote_adapter = options.fetch(:remote_adapter)
29
29
  @interval = options.fetch(:interval, 10).to_f
30
30
  @last_synced_at = Concurrent::AtomicFixnum.new(0)
31
- @adapter = Adapters::Memory.new
31
+ @adapter = Adapters::Memory.new(nil, threadsafe: true)
32
32
 
33
33
  if @interval < 1
34
34
  warn "Flipper::Cloud poll interval must be greater than or equal to 1 but was #{@interval}. Setting @interval to 1."
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = '0.28.0'.freeze
2
+ VERSION = '0.28.1'.freeze
3
3
  end
@@ -1,8 +1,17 @@
1
1
  RSpec.describe Flipper::Adapters::Memory do
2
2
  let(:source) { {} }
3
- subject { described_class.new(source) }
4
3
 
5
- it_should_behave_like 'a flipper adapter'
4
+ context 'threadsafe: true' do
5
+ subject { described_class.new(source, threadsafe: true) }
6
+
7
+ it_should_behave_like 'a flipper adapter'
8
+ end
9
+
10
+ context 'threadsafe: false' do
11
+ subject { described_class.new(source, threadsafe: false) }
12
+
13
+ it_should_behave_like 'a flipper adapter'
14
+ end
6
15
 
7
16
  it "can initialize from big hash" do
8
17
  flipper = Flipper.new(subject)
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.28.0
4
+ version: 0.28.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-21 00:00:00.000000000 Z
11
+ date: 2023-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -68,6 +68,7 @@ files:
68
68
  - examples/instrumentation.rb
69
69
  - examples/instrumentation_last_accessed_at.rb
70
70
  - examples/memoizing.rb
71
+ - examples/mirroring.rb
71
72
  - examples/percentage_of_actors.rb
72
73
  - examples/percentage_of_actors_enabled_check.rb
73
74
  - examples/percentage_of_actors_group.rb