feature_flagger 0.7.3 → 1.0.0

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
- SHA1:
3
- metadata.gz: '08ad3deca247deb946f6fd7f95fe12747978303e'
4
- data.tar.gz: 8512e9a0a733eaaa95c8faa61caf340786b10189
2
+ SHA256:
3
+ metadata.gz: a96951570dcb83956c8a817ac63a0928fdcd276e65fda789828fd4ef2a9b0234
4
+ data.tar.gz: 332306b6061c58cd5f215b3e51ad0084434eff4d82d77d7ae533b353176ecca6
5
5
  SHA512:
6
- metadata.gz: 11e2542ada2893c96bd7588a959f424f1904e29e8b7a4a1425557e995a8cefa95c4e47b839282e28bb8a4e7d6b4ef753e24dc538ebdfbba6c8a590b8904af509
7
- data.tar.gz: fd70b4252d581ff110ca37ce59a5e5dcae514fa040e52e1580f4ef5c24ca51313b9ec7c041a8b1c9898c3c0ce4be884605fe1d420e17b6bde0d2594db2a29140
6
+ metadata.gz: 1dd51d20a1e52136ee0609ca619c3bb11d6fbc086170f339e6b40c6c09ab49bd9a3ff55b5901ad9a4a09c9e2b840e3eda44ebedc504e07deeede38c9cfcedfb9
7
+ data.tar.gz: 97c93e48cb0a5ef452c3df7f17b35848c636151366bbdf329f91f40e19134491c2c6d441bb31e3308ccaea67bc2688788d5817b7c657ede7f7f1b20de93f809e
data/README.md CHANGED
@@ -4,6 +4,14 @@
4
4
 
5
5
  Partially release your features.
6
6
 
7
+ ## Working with Docker
8
+
9
+ Open IRB
10
+ `docker-compose run feature_flagger`
11
+
12
+ Running tests
13
+ `docker-compose run feature_flagger rspec`
14
+
7
15
  ## Installation
8
16
 
9
17
  Add this line to your application's Gemfile:
@@ -63,7 +71,7 @@ account.release(:email_marketing, :new_email_flow)
63
71
  #=> true
64
72
 
65
73
  # Check feature for a given account
66
- account.rollout?(:email_marketing, :new_email_flow)
74
+ account.released?(:email_marketing, :new_email_flow)
67
75
  #=> true
68
76
 
69
77
  # Remove feature for given account
@@ -71,7 +79,7 @@ account.unrelease(:email_marketing, :new_email_flow)
71
79
  #=> true
72
80
 
73
81
  # If you try to check an inexistent rollout key it will raise an error.
74
- account.rollout?(:email_marketing, :new_email_flow)
82
+ account.released?(:email_marketing, :new_email_flow)
75
83
  FeatureFlagger::KeyNotFoundError: ["account", "email_marketing", "new_email_flo"]
76
84
 
77
85
  # Check feature for a specific account id
@@ -95,7 +103,15 @@ Account.unrelease_to_all(:email_marketing, :new_email_flow)
95
103
  Account.released_features_to_all
96
104
  ```
97
105
 
106
+ ## Clean up action
107
+
108
+ By default when a key is removed from `rollout.yml` file, its data still in the storage.
109
+
110
+ To clean it up, execute or schedule the rake:
111
+
112
+ $ bundle exec rake feature_flagger:cleanup_removed_rollouts
113
+
98
114
  ## Contributing
99
115
 
100
- Bug reports and pull requests are welcome on GitHub at
101
- https://github.com/ResultadosDigitais/feature_flagger.
116
+ Bug reports and pull requests are welcome!
117
+ Please take a look at our guidelines [here](CONTRIBUTING.md).
@@ -11,10 +11,36 @@ module FeatureFlagger
11
11
  @info ||= YAML.load_file(yaml_filepath) if yaml_filepath
12
12
  end
13
13
 
14
+ def mapped_feature_keys(resource_name = nil)
15
+ info_filtered = resource_name ? info[resource_name] : info
16
+ [].tap do |keys|
17
+ make_keys_recursively(info_filtered).each { |key| keys.push(join_key(resource_name, key)) }
18
+ end
19
+ end
20
+
14
21
  private
15
22
 
16
23
  def default_yaml_filepath
17
24
  "#{Rails.root}/config/rollout.yml" if defined?(Rails)
18
25
  end
26
+
27
+ def make_keys_recursively(hash, keys = [], composed_key = [])
28
+ unless hash.values[0].is_a?(Hash)
29
+ keys.push(composed_key)
30
+ return
31
+ end
32
+
33
+ hash.each do |key, value|
34
+ composed_key_cloned = composed_key.clone
35
+ composed_key_cloned.push(key.to_sym)
36
+ make_keys_recursively(value, keys, composed_key_cloned)
37
+ end
38
+ keys
39
+ end
40
+
41
+ def join_key(resource_name, key)
42
+ key.unshift resource_name if resource_name
43
+ key.join(":")
44
+ end
19
45
  end
20
46
  end
@@ -8,7 +8,7 @@ module FeatureFlagger
8
8
  @storage = storage
9
9
  end
10
10
 
11
- def rollout?(feature_key, resource_id)
11
+ def released?(feature_key, resource_id)
12
12
  @storage.has_value?(RELEASED_FEATURES, feature_key) || @storage.has_value?(feature_key, resource_id)
13
13
  end
14
14
 
@@ -17,13 +17,7 @@ module FeatureFlagger
17
17
  end
18
18
 
19
19
  def release_to_all(feature_key)
20
- @storage.add(RELEASED_FEATURES, feature_key)
21
- end
22
-
23
- # <b>DEPRECATED:</b> Please use <tt>release</tt> instead.
24
- def release!(feature_key, resource_id)
25
- warn "[DEPRECATION] `release!` is deprecated. Please use `release` instead."
26
- release(feature_key, resource_id)
20
+ @storage.add_all(RELEASED_FEATURES, feature_key)
27
21
  end
28
22
 
29
23
  def unrelease(feature_key, resource_id)
@@ -31,13 +25,7 @@ module FeatureFlagger
31
25
  end
32
26
 
33
27
  def unrelease_to_all(feature_key)
34
- @storage.remove(RELEASED_FEATURES, feature_key)
35
- end
36
-
37
- # <b>DEPRECATED:</b> Please use <tt>unrelease</tt> instead.
38
- def unrelease!(feature_key, resource_id)
39
- warn "[DEPRECATION] `unrelease!` is deprecated. Please use `unrelease` instead."
40
- unrelease(feature_key, resource_id)
28
+ @storage.remove_all(RELEASED_FEATURES, feature_key)
41
29
  end
42
30
 
43
31
  def resource_ids(feature_key)
@@ -47,5 +35,13 @@ module FeatureFlagger
47
35
  def released_features_to_all
48
36
  @storage.all_values(RELEASED_FEATURES)
49
37
  end
38
+
39
+ def released_to_all?(feature_key)
40
+ @storage.has_value?(RELEASED_FEATURES, feature_key)
41
+ end
42
+
43
+ def search_keys(query)
44
+ @storage.search_keys(query)
45
+ end
50
46
  end
51
47
  end
@@ -0,0 +1,18 @@
1
+ module FeatureFlagger
2
+ class Manager
3
+
4
+ def self.detached_feature_keys
5
+ persisted_features = FeatureFlagger.control.search_keys("*").to_a
6
+ mapped_feature_keys = FeatureFlagger.config.mapped_feature_keys
7
+ persisted_features - mapped_feature_keys
8
+ end
9
+
10
+ def self.cleanup_detached(resource_name, *feature_key)
11
+ complete_feature_key = feature_key.map(&:to_s).insert(0, resource_name.to_s)
12
+ key_value = FeatureFlagger.config.info.dig(*complete_feature_key)
13
+ raise "key is still mapped" if key_value
14
+ FeatureFlagger.control.unrelease_to_all(complete_feature_key.join(':'))
15
+ end
16
+
17
+ end
18
+ end
@@ -12,26 +12,14 @@ module FeatureFlagger
12
12
  base.extend ClassMethods
13
13
  end
14
14
 
15
- def rollout?(*feature_key)
15
+ def released?(*feature_key)
16
16
  self.class.released_id?(id, feature_key)
17
17
  end
18
18
 
19
- # <b>DEPRECATED:</b> Please use <tt>release</tt> instead.
20
- def release!(*feature_key)
21
- warn "[DEPRECATION] `release!` is deprecated. Please use `release` instead."
22
- release(*feature_key)
23
- end
24
-
25
19
  def release(*feature_key)
26
20
  self.class.release_id(id, *feature_key)
27
21
  end
28
22
 
29
- # <b>DEPRECATED:</b> Please use <tt>unrelease</tt> instead.
30
- def unrelease!(*feature_key)
31
- warn "[DEPRECATION] `unrelease!` is deprecated. Please use `unrelease` instead."
32
- unrelease(*feature_key)
33
- end
34
-
35
23
  def unrelease(*feature_key)
36
24
  resource_name = self.class.rollout_resource_name
37
25
  feature = Feature.new(feature_key, resource_name)
@@ -39,9 +27,10 @@ module FeatureFlagger
39
27
  end
40
28
 
41
29
  module ClassMethods
30
+
42
31
  def released_id?(resource_id, *feature_key)
43
32
  feature = Feature.new(feature_key, rollout_resource_name)
44
- FeatureFlagger.control.rollout?(feature.key, resource_id)
33
+ FeatureFlagger.control.released?(feature.key, resource_id)
45
34
  end
46
35
 
47
36
  def release_id(resource_id, *feature_key)
@@ -69,6 +58,24 @@ module FeatureFlagger
69
58
  FeatureFlagger.control.released_features_to_all
70
59
  end
71
60
 
61
+ def released_to_all?(*feature_key)
62
+ feature = Feature.new(feature_key, rollout_resource_name)
63
+ FeatureFlagger.control.released_to_all?(feature.key)
64
+ end
65
+
66
+ def detached_feature_keys
67
+ persisted_features = FeatureFlagger.control.search_keys("#{rollout_resource_name}:*").to_a
68
+ mapped_feature_keys = FeatureFlagger.config.mapped_feature_keys(rollout_resource_name)
69
+ (persisted_features - mapped_feature_keys).map { |key| key.sub("#{rollout_resource_name}:",'') }
70
+ end
71
+
72
+ def cleanup_detached(*feature_key)
73
+ complete_feature_key = feature_key.map(&:to_s).insert(0, rollout_resource_name)
74
+ key_value = FeatureFlagger.config.info.dig(*complete_feature_key)
75
+ raise "key is still mapped" if key_value
76
+ FeatureFlagger.control.unrelease_to_all(complete_feature_key.join(':'))
77
+ end
78
+
72
79
  def rollout_resource_name
73
80
  klass_name = self.to_s
74
81
  klass_name.gsub!(/::/, '_')
@@ -0,0 +1,9 @@
1
+ if defined?(Rails)
2
+ module FeatureFlagger
3
+ class Railtie < Rails::Railtie
4
+ rake_tasks do
5
+ load 'tasks/cleanup.rake'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -29,9 +29,27 @@ module FeatureFlagger
29
29
  @redis.srem(key, value)
30
30
  end
31
31
 
32
+ def remove_all(global_key, key)
33
+ @redis.multi do |redis|
34
+ redis.srem(global_key, key)
35
+ redis.del(key)
36
+ end
37
+ end
38
+
39
+ def add_all(global_key, key)
40
+ @redis.multi do |redis|
41
+ redis.sadd(global_key, key)
42
+ redis.del(key)
43
+ end
44
+ end
45
+
32
46
  def all_values(key)
33
47
  @redis.smembers(key)
34
48
  end
49
+
50
+ def search_keys(query)
51
+ @redis.scan_each(match: query)
52
+ end
35
53
  end
36
54
  end
37
55
  end
@@ -1,3 +1,3 @@
1
1
  module FeatureFlagger
2
- VERSION = "0.7.3"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -6,6 +6,8 @@ require 'feature_flagger/control'
6
6
  require 'feature_flagger/model'
7
7
  require 'feature_flagger/feature'
8
8
  require 'feature_flagger/configuration'
9
+ require 'feature_flagger/manager'
10
+ require 'feature_flagger/railtie'
9
11
 
10
12
  module FeatureFlagger
11
13
  class << self
@@ -0,0 +1,10 @@
1
+ namespace :feature_flagger do
2
+ desc "cleaning up keys from storage that are no longer in the rollout.yml file"
3
+ task :cleanup_removed_rollouts => :environment do
4
+ keys = FeatureFlagger::Manager.detached_feature_keys
5
+ puts "Found keys to remove: #{keys}"
6
+ keys.each do |key|
7
+ FeatureFlagger::Manager.cleanup_detached key
8
+ end
9
+ end
10
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feature_flagger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nando Sousa
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-01-22 00:00:00.000000000 Z
12
+ date: 2019-05-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
@@ -109,9 +109,12 @@ files:
109
109
  - lib/feature_flagger/configuration.rb
110
110
  - lib/feature_flagger/control.rb
111
111
  - lib/feature_flagger/feature.rb
112
+ - lib/feature_flagger/manager.rb
112
113
  - lib/feature_flagger/model.rb
114
+ - lib/feature_flagger/railtie.rb
113
115
  - lib/feature_flagger/storage/redis.rb
114
116
  - lib/feature_flagger/version.rb
117
+ - lib/tasks/cleanup.rake
115
118
  homepage: http://github.com/ResultadosDigitais/feature_flagger
116
119
  licenses:
117
120
  - MIT
@@ -124,15 +127,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
124
127
  requirements:
125
128
  - - ">="
126
129
  - !ruby/object:Gem::Version
127
- version: '0'
130
+ version: '2.5'
128
131
  required_rubygems_version: !ruby/object:Gem::Requirement
129
132
  requirements:
130
133
  - - ">="
131
134
  - !ruby/object:Gem::Version
132
- version: '0'
135
+ version: 2.0.0
133
136
  requirements: []
134
137
  rubyforge_project:
135
- rubygems_version: 2.5.2.3
138
+ rubygems_version: 2.7.8
136
139
  signing_key:
137
140
  specification_version: 4
138
141
  summary: Partial release your features.