feature_flagger 1.0.1 → 2.0.1

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: 1e6648b809fb71f619b7f183de45faff5c8f7e180b716bb7ed4f41178b9b6a7b
4
- data.tar.gz: ba3ec6da4184d199d2a74e360fcb789fd2ac9aeb95dea738de7dc650129f6369
3
+ metadata.gz: 89d925393dab41d5de3c0fd8872e9d0914936ed98140d5dea69e9ff9286cde7f
4
+ data.tar.gz: 68cd51804dbc9a1b8547ed1ddbd0be9630704afd0493e99b3c1a740f4c460c99
5
5
  SHA512:
6
- metadata.gz: 196c76cad916494a7bb3438a69a4ddfe4dbc3a1efc6584078f4eee681c7dc9d3e53ece3e37796aed9d4e4d865602cf12deb4e165f1fc3a62f43eee0f5f71878f
7
- data.tar.gz: 7b81c8fd3679000af48b11f05996155962215928d14c28cd841b0874bbf19ce09d1aa6149e7831f4de69e11ce09cad94daf8837ae94a2387173bb20c5f38c198
6
+ metadata.gz: 6d1be4855ef2b133f1c0233f12f21833bdfd81bf35b3dd172e562fdd404bd6d674c429aeef4ec67a0f3062741b84f1ee99ba5bf6d317ec12b7f6517a9ab77ce1
7
+ data.tar.gz: 434ad5fda2e78b6bc63157bdee07000fcfde62ae102db74e543a09852914441c4bdd72fd15ddbf72bf1dec55e7acc2ff735d69bf9ca49e8482d56356ea032d6c
data/README.md CHANGED
@@ -28,7 +28,6 @@ Or install it yourself as:
28
28
 
29
29
  $ gem install feature_flagger
30
30
 
31
-
32
31
  ## Configuration
33
32
 
34
33
  By default, feature_flagger uses the REDIS_URL env var to setup it's storage.
@@ -60,6 +59,29 @@ class Account < ActiveRecord::Base
60
59
  # ....
61
60
  end
62
61
  ```
62
+ #### Notifier
63
+ The notifier_callback property in config, enables the dispatch of events when a release operation happens.
64
+ ```ruby
65
+ config.notifier_callback = -> {|event| do something with event }
66
+ ```
67
+
68
+
69
+ It accepts a lambda function that will receive a hash with the operation triggered like:
70
+ ```ruby
71
+ {
72
+ type: 'release',
73
+ model: 'account',
74
+ key: 'somefeature:somerolloutkey'
75
+ id: 'account_id' #In realease_to_all and unrelease_to_all operations id will be nil
76
+ }
77
+ ```
78
+
79
+ The supported operations are:
80
+ * release
81
+ * unrelease
82
+ * release_to_all
83
+ * unrelease_to_all
84
+
63
85
 
64
86
  ## Usage
65
87
 
@@ -111,6 +133,13 @@ To clean it up, execute or schedule the rake:
111
133
 
112
134
  $ bundle exec rake feature_flagger:cleanup_removed_rollouts
113
135
 
136
+ ## Upgrading
137
+
138
+ When upgrading from `1.1.x` to `1.2.x` the following command must be executed
139
+ to ensure the data stored in Redis storage is right. Check [#67](https://github.com/ResultadosDigitais/feature_flagger/pull/67) and [#68](https://github.com/ResultadosDigitais/feature_flagger/pull/68) for more info.
140
+
141
+ $ bundle exec rake feature_flagger:migrate_to_resource_keys
142
+
114
143
  ## Contributing
115
144
 
116
145
  Bug reports and pull requests are welcome!
@@ -2,18 +2,22 @@ require 'yaml'
2
2
 
3
3
  require 'feature_flagger/version'
4
4
  require 'feature_flagger/storage/redis'
5
+ require 'feature_flagger/storage/feature_keys_migration'
5
6
  require 'feature_flagger/control'
6
7
  require 'feature_flagger/model'
8
+ require 'feature_flagger/model_settings'
7
9
  require 'feature_flagger/feature'
8
10
  require 'feature_flagger/configuration'
9
11
  require 'feature_flagger/manager'
10
12
  require 'feature_flagger/railtie'
13
+ require 'feature_flagger/notifier'
11
14
 
12
15
  module FeatureFlagger
13
16
  class << self
14
17
  def configure
15
18
  @@configuration = nil
16
19
  @@control = nil
20
+ @@notifier = nil
17
21
  yield config if block_given?
18
22
  end
19
23
 
@@ -21,8 +25,12 @@ module FeatureFlagger
21
25
  @@configuration ||= Configuration.new
22
26
  end
23
27
 
28
+ def notifier
29
+ @@notifier ||= Notifier.new(config.notifier_callback)
30
+ end
31
+
24
32
  def control
25
- @@control ||= Control.new(config.storage)
33
+ @@control ||= Control.new(config.storage, notifier)
26
34
  end
27
35
  end
28
36
  end
@@ -1,10 +1,11 @@
1
1
  module FeatureFlagger
2
2
  class Configuration
3
- attr_accessor :storage, :yaml_filepath
3
+ attr_accessor :storage, :yaml_filepath, :notifier_callback
4
4
 
5
5
  def initialize
6
6
  @storage ||= Storage::Redis.default_client
7
7
  @yaml_filepath ||= default_yaml_filepath
8
+ @notifier_callback = nil
8
9
  end
9
10
 
10
11
  def info
@@ -4,8 +4,9 @@ module FeatureFlagger
4
4
 
5
5
  RELEASED_FEATURES = 'released_features'
6
6
 
7
- def initialize(storage)
7
+ def initialize(storage, notifier)
8
8
  @storage = storage
9
+ @notifier = notifier
9
10
  end
10
11
 
11
12
  def released?(feature_key, resource_id)
@@ -13,18 +14,33 @@ module FeatureFlagger
13
14
  end
14
15
 
15
16
  def release(feature_key, resource_id)
16
- @storage.add(feature_key, resource_id)
17
+ resource_name = Storage::Keys.extract_resource_name_from_feature_key(
18
+ feature_key
19
+ )
20
+
21
+ @notifier.send(FeatureFlagger::Notifier::RELEASE, feature_key, resource_id)
22
+ @storage.add(feature_key, resource_name, resource_id)
23
+ end
24
+
25
+ def releases(resource_name, resource_id)
26
+ @storage.fetch_releases(resource_name, resource_id, RELEASED_FEATURES)
17
27
  end
18
28
 
19
29
  def release_to_all(feature_key)
30
+ @notifier.send(FeatureFlagger::Notifier::RELEASE_TO_ALL, feature_key)
20
31
  @storage.add_all(RELEASED_FEATURES, feature_key)
21
32
  end
22
33
 
23
34
  def unrelease(feature_key, resource_id)
24
- @storage.remove(feature_key, resource_id)
35
+ resource_name = Storage::Keys.extract_resource_name_from_feature_key(
36
+ feature_key
37
+ )
38
+ @notifier.send(FeatureFlagger::Notifier::UNRELEASE, feature_key, resource_id)
39
+ @storage.remove(feature_key, resource_name, resource_id)
25
40
  end
26
41
 
27
42
  def unrelease_to_all(feature_key)
43
+ @notifier.send(FeatureFlagger::Notifier::UNRELEASE_TO_ALL, feature_key)
28
44
  @storage.remove_all(RELEASED_FEATURES, feature_key)
29
45
  end
30
46
 
@@ -40,8 +56,14 @@ module FeatureFlagger
40
56
  @storage.has_value?(RELEASED_FEATURES, feature_key)
41
57
  end
42
58
 
59
+ # DEPRECATED: this method will be removed from public api on v2.0 version.
60
+ # use instead the feature_keys method.
43
61
  def search_keys(query)
44
62
  @storage.search_keys(query)
45
63
  end
64
+
65
+ def feature_keys
66
+ @storage.feature_keys - [FeatureFlagger::Control::RELEASED_FEATURES]
67
+ end
46
68
  end
47
69
  end
@@ -0,0 +1,18 @@
1
+ begin
2
+ require 'active_support/core_ext/string/inflections'
3
+ rescue LoadError
4
+ unless ''.respond_to?(:constantize)
5
+ class String
6
+ def constantize
7
+ names = split('::')
8
+ names.shift if names.empty? || names.first.empty?
9
+
10
+ constant = Object
11
+ names.each do |name|
12
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
13
+ end
14
+ constant
15
+ end
16
+ end
17
+ end
18
+ end
@@ -2,8 +2,9 @@ module FeatureFlagger
2
2
  class Manager
3
3
 
4
4
  def self.detached_feature_keys
5
- persisted_features = FeatureFlagger.control.search_keys("*").to_a
5
+ persisted_features = FeatureFlagger.control.feature_keys
6
6
  mapped_feature_keys = FeatureFlagger.config.mapped_feature_keys
7
+
7
8
  persisted_features - mapped_feature_keys
8
9
  end
9
10
 
@@ -13,44 +13,64 @@ module FeatureFlagger
13
13
  end
14
14
 
15
15
  def released?(*feature_key)
16
- self.class.released_id?(id, feature_key)
16
+ self.class.released_id?(feature_flagger_identifier, feature_key)
17
17
  end
18
18
 
19
19
  def release(*feature_key)
20
- self.class.release_id(id, *feature_key)
20
+ self.class.release_id(feature_flagger_identifier, *feature_key)
21
21
  end
22
22
 
23
23
  def unrelease(*feature_key)
24
- resource_name = self.class.rollout_resource_name
24
+ resource_name = self.class.feature_flagger_model_settings.entity_name
25
25
  feature = Feature.new(feature_key, resource_name)
26
26
  FeatureFlagger.control.unrelease(feature.key, id)
27
27
  end
28
28
 
29
+ def releases
30
+ resource_name = self.class.feature_flagger_model_settings.entity_name
31
+ FeatureFlagger.control.releases(resource_name, id)
32
+ end
33
+
34
+ private
35
+
36
+ def feature_flagger_identifier
37
+ public_send(self.class.feature_flagger_model_settings.identifier_field)
38
+ end
39
+
29
40
  module ClassMethods
41
+ def feature_flagger
42
+ raise ArgumentError unless block_given?
43
+ yield feature_flagger_model_settings
44
+ end
30
45
 
31
46
  def released_id?(resource_id, *feature_key)
32
- feature = Feature.new(feature_key, rollout_resource_name)
47
+ feature = Feature.new(feature_key, feature_flagger_model_settings.entity_name)
33
48
  FeatureFlagger.control.released?(feature.key, resource_id)
34
49
  end
35
50
 
36
51
  def release_id(resource_id, *feature_key)
37
- feature = Feature.new(feature_key, rollout_resource_name)
52
+ feature = Feature.new(feature_key, feature_flagger_model_settings.entity_name)
38
53
  FeatureFlagger.control.release(feature.key, resource_id)
39
54
  end
40
55
 
56
+ def unrelease_id(resource_id, *feature_key)
57
+ feature = Feature.new(feature_key, feature_flagger_model_settings.entity_name)
58
+ FeatureFlagger.control.unrelease(feature.key, resource_id)
59
+ end
60
+
41
61
  def all_released_ids_for(*feature_key)
42
62
  feature_key.flatten!
43
- feature = Feature.new(feature_key, rollout_resource_name)
63
+ feature = Feature.new(feature_key, feature_flagger_model_settings.entity_name)
44
64
  FeatureFlagger.control.resource_ids(feature.key)
45
65
  end
46
66
 
47
67
  def release_to_all(*feature_key)
48
- feature = Feature.new(feature_key, rollout_resource_name)
68
+ feature = Feature.new(feature_key, feature_flagger_model_settings.entity_name)
49
69
  FeatureFlagger.control.release_to_all(feature.key)
50
70
  end
51
71
 
52
72
  def unrelease_to_all(*feature_key)
53
- feature = Feature.new(feature_key, rollout_resource_name)
73
+ feature = Feature.new(feature_key, feature_flagger_model_settings.entity_name)
54
74
  FeatureFlagger.control.unrelease_to_all(feature.key)
55
75
  end
56
76
 
@@ -59,18 +79,19 @@ module FeatureFlagger
59
79
  end
60
80
 
61
81
  def released_to_all?(*feature_key)
62
- feature = Feature.new(feature_key, rollout_resource_name)
82
+ feature = Feature.new(feature_key, feature_flagger_model_settings.entity_name)
63
83
  FeatureFlagger.control.released_to_all?(feature.key)
64
84
  end
65
85
 
66
86
  def detached_feature_keys
87
+ rollout_resource_name = feature_flagger_model_settings.entity_name
67
88
  persisted_features = FeatureFlagger.control.search_keys("#{rollout_resource_name}:*").to_a
68
89
  mapped_feature_keys = FeatureFlagger.config.mapped_feature_keys(rollout_resource_name)
69
90
  (persisted_features - mapped_feature_keys).map { |key| key.sub("#{rollout_resource_name}:",'') }
70
91
  end
71
92
 
72
93
  def cleanup_detached(*feature_key)
73
- complete_feature_key = feature_key.map(&:to_s).insert(0, rollout_resource_name)
94
+ complete_feature_key = feature_key.map(&:to_s).insert(0, feature_flagger_model_settings.entity_name)
74
95
  key_value = FeatureFlagger.config.info.dig(*complete_feature_key)
75
96
  raise "key is still mapped" if key_value
76
97
  FeatureFlagger.control.unrelease_to_all(complete_feature_key.join(':'))
@@ -85,6 +106,17 @@ module FeatureFlagger
85
106
  klass_name.downcase!
86
107
  klass_name
87
108
  end
109
+
110
+ def feature_flagger_model_settings
111
+ @feature_flagger_model_settings ||= FeatureFlagger::ModelSettings.new(
112
+ identifier_field: :id,
113
+ entity_name: rollout_resource_name
114
+ )
115
+ end
116
+
117
+ def feature_flagger_identifier
118
+ public_send(feature_flagger_model_settings.identifier_field)
119
+ end
88
120
  end
89
121
  end
90
122
  end
@@ -0,0 +1,36 @@
1
+ module FeatureFlagger
2
+ class ModelSettings
3
+ def initialize(arguments)
4
+ arguments.each do |field, value|
5
+ self.public_send("#{field}=", value)
6
+ end
7
+ end
8
+
9
+ # Public: identifier_field Refers to which field must represent the unique model
10
+ # id.
11
+ attr_accessor :identifier_field
12
+
13
+ # Public: entity_name to which entity the model is targeting.
14
+ # Take this yaml file as example:
15
+ #
16
+ # account:
17
+ # email_marketing:
18
+ # whitelabel:
19
+ # description: a rollout
20
+ # owner: core
21
+ # account_in_migration:
22
+ # email_marketing:
23
+ # whitelabel:
24
+ # description: a rollout
25
+ # owner: core
26
+ #
27
+ # class Account < ActiveRecord::Base
28
+ # include FeatureFlagger::Model
29
+ #
30
+ # feature_flagger do |config|
31
+ # config.identifier_field = :cdp_tenant_id
32
+ # config.entity_name = :account_in_migration
33
+ # end
34
+ attr_accessor :entity_name
35
+ end
36
+ end
@@ -0,0 +1,45 @@
1
+ module FeatureFlagger
2
+ class Notifier
3
+ attr_reader :notify
4
+
5
+ RELEASE = 'release'.freeze
6
+ UNRELEASE = 'unrelease'.freeze
7
+ RELEASE_TO_ALL = 'release_to_all'.freeze
8
+ UNRELEASE_TO_ALL = 'unrelease_to_all'.freeze
9
+
10
+ def initialize(notify = nil)
11
+ @notify = valid_notify?(notify) ? notify : nullNotify
12
+ end
13
+
14
+ def send(operation, feature_key, resource_id = nil)
15
+ @notify.call(build_event(operation, extract_resource_from_key(feature_key), feature_key, resource_id))
16
+ end
17
+
18
+ private
19
+
20
+ def nullNotify
21
+ lambda {|e| }
22
+ end
23
+
24
+ def valid_notify?(notify)
25
+ !notify.nil? && notify.is_a?(Proc)
26
+ end
27
+
28
+ def extract_resource_from_key(key)
29
+ Storage::Keys.extract_resource_name_from_feature_key(
30
+ key
31
+ )
32
+ rescue FeatureFlagger::Storage::Keys::InvalidResourceNameError
33
+ "legacy key"
34
+ end
35
+
36
+ def build_event(operation, resource_name, feature_key, resource_id)
37
+ {
38
+ type: operation,
39
+ model: resource_name,
40
+ feature: feature_key,
41
+ id: resource_id
42
+ }
43
+ end
44
+ end
45
+ end
@@ -2,8 +2,8 @@ if defined?(Rails)
2
2
  module FeatureFlagger
3
3
  class Railtie < Rails::Railtie
4
4
  rake_tasks do
5
- load 'tasks/cleanup.rake'
5
+ load 'tasks/feature_flagger.rake'
6
6
  end
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FeatureFlagger
4
+ module Storage
5
+ class FeatureKeysMigration
6
+
7
+ def initialize(from_redis, to_control)
8
+ @from_redis = from_redis
9
+ @to_control = to_control
10
+ end
11
+
12
+ # call migrates features key from the old fashioned to the new
13
+ # format.
14
+ #
15
+ # It must replicate feature keys with changes:
16
+ #
17
+ # from "avenue:traffic_lights" => 42
18
+ # to "avenue:42" => traffic_lights
19
+ def call
20
+ @from_redis.scan_each(match: "*", count: FeatureFlagger::Storage::Redis::SCAN_EACH_BATCH_SIZE) do |redis_key|
21
+ # filter out resource_keys
22
+ next if redis_key.start_with?("#{FeatureFlagger::Storage::Redis::RESOURCE_PREFIX}:")
23
+
24
+ migrate_key(redis_key)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def migrate_key(key)
31
+ return migrate_release_to_all(key) if feature_released_to_all?(key)
32
+
33
+ migrate_release(key)
34
+ end
35
+
36
+ def migrate_release_to_all(key)
37
+ features = @from_redis.smembers(key)
38
+
39
+ features.each do |feature_key|
40
+ @to_control.release_to_all(feature_key)
41
+ end
42
+ end
43
+
44
+ def feature_released_to_all?(key)
45
+ FeatureFlagger::Control::RELEASED_FEATURES == key
46
+ end
47
+
48
+ def migrate_release(key)
49
+ resource_ids = @from_redis.smembers(key)
50
+
51
+ resource_ids.each do |id|
52
+ @to_control.release(key, id)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,20 @@
1
+ module FeatureFlagger
2
+ module Storage
3
+ module Keys
4
+ MINIMUM_VALID_FEATURE_PATH = 2.freeze
5
+
6
+ def self.resource_key(prefix, resource_name, resource_id)
7
+ "#{prefix}:#{resource_name}:#{resource_id}"
8
+ end
9
+
10
+ def self.extract_resource_name_from_feature_key(feature_key)
11
+ feature_paths = feature_key.split(':')
12
+ raise InvalidResourceNameError if feature_paths.size < MINIMUM_VALID_FEATURE_PATH
13
+
14
+ feature_paths.first
15
+ end
16
+
17
+ class InvalidResourceNameError < StandardError; end
18
+ end
19
+ end
20
+ end
@@ -1,11 +1,13 @@
1
1
  require 'redis'
2
2
  require 'redis-namespace'
3
+ require_relative './keys'
3
4
 
4
5
  module FeatureFlagger
5
6
  module Storage
6
7
  class Redis
7
-
8
8
  DEFAULT_NAMESPACE = :feature_flagger
9
+ RESOURCE_PREFIX = "_r".freeze
10
+ SCAN_EACH_BATCH_SIZE = 1000.freeze
9
11
 
10
12
  def initialize(redis)
11
13
  @redis = redis
@@ -17,39 +19,104 @@ module FeatureFlagger
17
19
  new(ns)
18
20
  end
19
21
 
22
+ def fetch_releases(resource_name, resource_id, global_key)
23
+ resource_key = resource_key(resource_name, resource_id)
24
+ releases = @redis.sunion(resource_key, global_key)
25
+
26
+ releases.select{ |release| release.start_with?(resource_name) }
27
+ end
28
+
20
29
  def has_value?(key, value)
21
30
  @redis.sismember(key, value)
22
31
  end
23
32
 
24
- def add(key, value)
25
- @redis.sadd(key, value)
26
- end
33
+ def add(feature_key, resource_name, resource_id)
34
+ resource_key = resource_key(resource_name, resource_id)
27
35
 
28
- def remove(key, value)
29
- @redis.srem(key, value)
36
+ @redis.multi do |redis|
37
+ redis.sadd(feature_key, resource_id)
38
+ redis.sadd(resource_key, feature_key)
39
+ end
30
40
  end
31
41
 
32
- def remove_all(global_key, key)
42
+ def remove(feature_key, resource_name, resource_id)
43
+ resource_key = resource_key(resource_name, resource_id)
44
+
33
45
  @redis.multi do |redis|
34
- redis.srem(global_key, key)
35
- redis.del(key)
46
+ redis.srem(feature_key, resource_id)
47
+ redis.srem(resource_key, feature_key)
36
48
  end
37
49
  end
38
50
 
51
+ def remove_all(global_key, feature_key)
52
+ @redis.srem(global_key, feature_key)
53
+ remove_feature_key_from_resources(feature_key)
54
+ end
55
+
39
56
  def add_all(global_key, key)
40
- @redis.multi do |redis|
41
- redis.sadd(global_key, key)
42
- redis.del(key)
43
- end
57
+ @redis.sadd(global_key, key)
58
+ remove_feature_key_from_resources(key)
44
59
  end
45
60
 
46
61
  def all_values(key)
47
62
  @redis.smembers(key)
48
63
  end
49
64
 
65
+ # DEPRECATED: this method will be removed from public api on v2.0 version.
66
+ # use instead the feature_keys method.
50
67
  def search_keys(query)
51
68
  @redis.scan_each(match: query)
52
69
  end
70
+
71
+ def feature_keys
72
+ feature_keys = []
73
+
74
+ @redis.scan_each(match: "*") do |key|
75
+ # Reject keys related to feature responsible for return
76
+ # released features for a given account.
77
+ next if key.start_with?("#{RESOURCE_PREFIX}:")
78
+
79
+ feature_keys << key
80
+ end
81
+
82
+ feature_keys
83
+ end
84
+
85
+ def synchronize_feature_and_resource
86
+ FeatureFlagger::Storage::FeatureKeysMigration.new(
87
+ @redis,
88
+ FeatureFlagger.control,
89
+ ).call
90
+ end
91
+
92
+ private
93
+
94
+ def resource_key(resource_name, resource_id)
95
+ FeatureFlagger::Storage::Keys.resource_key(
96
+ RESOURCE_PREFIX,
97
+ resource_name,
98
+ resource_id,
99
+ )
100
+ end
101
+
102
+ def remove_feature_key_from_resources(feature_key)
103
+ cursor = 0
104
+ resource_name = feature_key.split(":").first
105
+
106
+ loop do
107
+ cursor, resource_ids = @redis.sscan(feature_key, cursor, count: SCAN_EACH_BATCH_SIZE)
108
+
109
+ @redis.multi do |redis|
110
+ resource_ids.each do |resource_id|
111
+ key = resource_key(resource_name, resource_id)
112
+ redis.srem(key, feature_key)
113
+ redis.srem(feature_key, resource_id)
114
+ end
115
+ end
116
+
117
+ break if cursor == "0"
118
+ end
119
+ end
53
120
  end
54
121
  end
55
122
  end
@@ -1,3 +1,3 @@
1
1
  module FeatureFlagger
2
- VERSION = "1.0.1"
2
+ VERSION = "2.0.1"
3
3
  end
@@ -0,0 +1,41 @@
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
+
11
+ desc "Synchronizes resource_keys with feature_keys, recommended to apps that installed feature flagger before v.1.2.0"
12
+ task :migrate_to_resource_keys => :environment do
13
+ storage = FeatureFlagger.config.storage
14
+ storage.synchronize_feature_and_resource
15
+ end
16
+
17
+ desc "Release feature to given identifiers, Usage: `$ bundle exec rake feature_flagger:release\[Account,email_marketing:whitelabel,1,2,3,4\]`"
18
+ task :release, [:entity_name, :feature_key] => :environment do |_, args|
19
+ entity = args.entity_name.constantize
20
+ entity_ids = args.extras
21
+ entity.release_id(entity_ids, *args.feature_key.split(':'))
22
+ end
23
+
24
+ desc "Unrelease feature to given identifiers, Usage: `$ bundle exec rake feature_flagger:unrelease\[Account,email_marketing:whitelabel,1,2,3,4\]`"
25
+ task :unrelease, [:entity_name, :feature_key] => :environment do |_, args|
26
+ entity, entity_ids = args.entity_name.constantize, args.extras
27
+ entity.unrelease_id(entity_ids, *args.feature_key.split(':'))
28
+ end
29
+
30
+ desc "Release one feature to all entity ids, Usage: `$ bundle exec rake feature_flagger:release_to_all\[Account,email_marketing:whitelabel\]`"
31
+ task :release_to_all, [:entity_name, :feature_key] => :environment do |_, args|
32
+ entity = args.entity_name.constantize
33
+ entity.release_to_all(*args.feature_key.split(':'))
34
+ end
35
+
36
+ desc "Unrelease one feature to all entity ids, Usage: `$ bundle exec rake feature_flagger:unrelease_to_all\[Account,email_marketing:whitelabel\]`"
37
+ task :unrelease_to_all, [:entity_name, :feature_key] => :environment do |_, args|
38
+ entity = args.entity_name.constantize
39
+ entity.unrelease_to_all(*args.feature_key.split(':'))
40
+ end
41
+ 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: 1.0.1
4
+ version: 2.0.1
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-08-09 00:00:00.000000000 Z
12
+ date: 2021-01-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
@@ -43,30 +43,30 @@ dependencies:
43
43
  name: bundler
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - "~>"
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: '2.0'
48
+ version: '0'
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - "~>"
53
+ - - ">="
54
54
  - !ruby/object:Gem::Version
55
- version: '2.0'
55
+ version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: rake
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
60
  - - "~>"
61
61
  - !ruby/object:Gem::Version
62
- version: '10.0'
62
+ version: '13.0'
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
- version: '10.0'
69
+ version: '13.0'
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: rspec
72
72
  requirement: !ruby/object:Gem::Requirement
@@ -81,20 +81,34 @@ dependencies:
81
81
  - - "~>"
82
82
  - !ruby/object:Gem::Version
83
83
  version: '3.0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: simplecov
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '='
89
+ - !ruby/object:Gem::Version
90
+ version: 0.21.2
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '='
96
+ - !ruby/object:Gem::Version
97
+ version: 0.21.2
84
98
  - !ruby/object:Gem::Dependency
85
99
  name: fakeredis
86
100
  requirement: !ruby/object:Gem::Requirement
87
101
  requirements:
88
102
  - - '='
89
103
  - !ruby/object:Gem::Version
90
- version: 0.7.0
104
+ version: 0.8.0
91
105
  type: :development
92
106
  prerelease: false
93
107
  version_requirements: !ruby/object:Gem::Requirement
94
108
  requirements:
95
109
  - - '='
96
110
  - !ruby/object:Gem::Version
97
- version: 0.7.0
111
+ version: 0.8.0
98
112
  description: Management tool to make it easier rollouting features to customers.
99
113
  email:
100
114
  - nandosousafr@gmail.com
@@ -108,13 +122,18 @@ files:
108
122
  - lib/feature_flagger.rb
109
123
  - lib/feature_flagger/configuration.rb
110
124
  - lib/feature_flagger/control.rb
125
+ - lib/feature_flagger/core_ext.rb
111
126
  - lib/feature_flagger/feature.rb
112
127
  - lib/feature_flagger/manager.rb
113
128
  - lib/feature_flagger/model.rb
129
+ - lib/feature_flagger/model_settings.rb
130
+ - lib/feature_flagger/notifier.rb
114
131
  - lib/feature_flagger/railtie.rb
132
+ - lib/feature_flagger/storage/feature_keys_migration.rb
133
+ - lib/feature_flagger/storage/keys.rb
115
134
  - lib/feature_flagger/storage/redis.rb
116
135
  - lib/feature_flagger/version.rb
117
- - lib/tasks/cleanup.rake
136
+ - lib/tasks/feature_flagger.rake
118
137
  homepage: http://github.com/ResultadosDigitais/feature_flagger
119
138
  licenses:
120
139
  - MIT
@@ -134,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
153
  - !ruby/object:Gem::Version
135
154
  version: 2.0.0
136
155
  requirements: []
137
- rubygems_version: 3.0.3
156
+ rubygems_version: 3.2.3
138
157
  signing_key:
139
158
  specification_version: 4
140
159
  summary: Partial release your features.
@@ -1,10 +0,0 @@
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