feature_flagger 0.7.3 → 1.0.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
- 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.