abstract_feature_branch 1.3.0 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +20 -8
- data/VERSION +1 -1
- data/abstract_feature_branch.gemspec +7 -41
- data/lib/abstract_feature_branch/configuration.rb +26 -10
- data/lib/abstract_feature_branch/redis/connection_pool_to_redis_adapter.rb +34 -0
- data/lib/abstract_feature_branch.rb +12 -5
- data/lib/ext/feature_branch.rb +1 -1
- data/lib/generators/templates/config/initializers/abstract_feature_branch.rb +8 -1
- metadata +6 -40
- data/.coveralls.yml +0 -1
- data/.travis.yml +0 -30
- data/RELEASE_NOTES.md +0 -55
- data/TODO.md +0 -3
- data/config/features/admin.local.yml +0 -15
- data/config/features/admin.yml +0 -17
- data/config/features/internal/wiki.local.yml +0 -15
- data/config/features/internal/wiki.yml +0 -17
- data/config/features/public.local.yml +0 -15
- data/config/features/public.yml +0 -17
- data/img/BigAstronaut-Logo.png +0 -0
- data/img/EarlyShares-Logo.svg +0 -22
- data/img/Factor75-Logo.svg +0 -54
- data/ruby187.Gemfile +0 -13
- data/spec/abstract_feature_branch/file_beautifier_spec.rb +0 -384
- data/spec/ext/feature_branch__feature_branch_per_user_spec.rb +0 -122
- data/spec/ext/feature_branch__feature_branch_spec.rb +0 -148
- data/spec/ext/feature_branch__feature_enabled_spec.rb +0 -274
- data/spec/fixtures/application_development_config/config/features.reference.yml +0 -21
- data/spec/fixtures/application_no_config/no_config +0 -1
- data/spec/fixtures/application_rails_config/config/features.local.yml +0 -16
- data/spec/fixtures/application_rails_config/config/features.yml +0 -20
- data/spec/fixtures/application_ugly_config_reference/config/another_application_configuration.yml +0 -31
- data/spec/fixtures/application_ugly_config_reference/config/database.yml +0 -17
- data/spec/fixtures/application_ugly_config_reference/config/features/admin.local.yml +0 -44
- data/spec/fixtures/application_ugly_config_reference/config/features/admin.yml +0 -44
- data/spec/fixtures/application_ugly_config_reference/config/features/empty.local.yml +0 -0
- data/spec/fixtures/application_ugly_config_reference/config/features/feature_empty_config.local.yml +0 -13
- data/spec/fixtures/application_ugly_config_reference/config/features/including_comments.local.yml +0 -52
- data/spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.local.yml +0 -44
- data/spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.yml +0 -44
- data/spec/fixtures/application_ugly_config_reference/config/features/public.local.yml +0 -44
- data/spec/fixtures/application_ugly_config_reference/config/features/public.yml +0 -44
- data/spec/fixtures/application_ugly_config_reference/config/features.local.yml +0 -44
- data/spec/fixtures/application_ugly_config_reference/config/features.yml +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47e99ade543da399fb1529db07bbecd871e23a1eb7cff9239a578067453dc312
|
4
|
+
data.tar.gz: b54ab8066e04ee68d6d40940a84dd69f237354d40523e5003be4f34ef6d4e03b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2d9b1f7a36c405bbb7406bd22b4ec29f0f9d4d55a1ecf7d83ee8adb6f77cba28159f20a32be8b1fa36f97422ccdf74a7f93c6c06d8cb617b0f5405d0d833052
|
7
|
+
data.tar.gz: d851c77683233aa129261171769b8e693949bf178af7c958995daf8f237fed1d7364db8b805e635e5346acdb26c3944af24aab15aab8c5c1f686efa29aba5bcc
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 1.3.2
|
4
|
+
|
5
|
+
- Ensure better performance, fetch Redis Overrides at app/server startup time only by default while providing option to fetch live by setting `AbstractFeatureBranch.feature_store_live_fetching` to `true`
|
6
|
+
- Do not automatically pre-init `AbstractFeatureBranch.feature_store` with `Redis.new` if it was `nil` as that is a bad default.
|
7
|
+
- Fix issue with crashing when not including the `connection_pool` gem manually if needed with a version of `redis` older than 5
|
8
|
+
|
9
|
+
## 1.3.1
|
10
|
+
|
11
|
+
- Support Redis `ConnectionPool` `AbstractFeatureBranch::Configuration#feature_store`
|
12
|
+
|
3
13
|
## 1.3.0
|
4
14
|
|
5
15
|
- Officially support newer `redis` client gem version 5
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Abstract Feature Branch 1.3.
|
1
|
+
# Abstract Feature Branch 1.3.2
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/abstract_feature_branch.png)](http://badge.fury.io/rb/abstract_feature_branch)
|
3
3
|
[![Build Status](https://api.travis-ci.org/AndyObtiva/abstract_feature_branch.png?branch=master)](https://travis-ci.org/AndyObtiva/abstract_feature_branch)
|
4
4
|
[![Coverage Status](https://coveralls.io/repos/AndyObtiva/abstract_feature_branch/badge.png?branch=master)](https://coveralls.io/r/AndyObtiva/abstract_feature_branch?branch=master)
|
@@ -37,17 +37,17 @@ Setup
|
|
37
37
|
### Rails Application Use
|
38
38
|
|
39
39
|
1. Configure Rubygem
|
40
|
-
- With `rails` between `~> 7.0` and `~> 2.0`: Add the following to Gemfile <pre>gem 'abstract_feature_branch', '~> 1.3.
|
41
|
-
- With `rails` `~> 2.0` only: Add the following to config/environment.rb <pre>config.gem 'abstract_feature_branch', :version => '1.3.
|
40
|
+
- With `rails` between `~> 7.0` and `~> 2.0`: Add the following to Gemfile <pre>gem 'abstract_feature_branch', '~> 1.3.2'</pre>
|
41
|
+
- With `rails` `~> 2.0` only: Add the following to config/environment.rb <pre>config.gem 'abstract_feature_branch', :version => '1.3.2'</pre>
|
42
42
|
2. Generate <code>config/initializers/abstract_feature_branch.rb</code>, <code>lib/tasks/abstract_feature_branch.rake</code>, <code>config/features.yml</code> and <code>config/features.local.yml</code> in your Rails app directory by running <pre>rails g abstract_feature_branch:install</pre>
|
43
43
|
3. [Optional] Generate <code>config/features/[context_path].yml</code> in your Rails app directory by running <pre>rails g abstract_feature_branch:context context_path</pre> (more details under [**instructions**](#instructions))
|
44
|
-
4. [Optional] Customize configuration in <code>config/initializers/abstract_feature_branch.rb</code> (can be useful for changing location of feature files in Rails application, configuring Redis for per-user feature enablement, or troubleshooting a specific Rails environment feature configuration)
|
44
|
+
4. [Optional] Customize configuration in <code>config/initializers/abstract_feature_branch.rb</code> (can be useful for changing location of feature files in Rails application, configuring Redis with a Redis or ConnectionPool instance to use for overrides, and per-user feature enablement, or troubleshooting a specific Rails environment feature configuration)
|
45
45
|
5. [Optional] Redis Server (between `~> 7.0` and `~> 3.0`): Install view [Homebrew](https://brew.sh/) with `brew install redis`
|
46
46
|
6. [Optional] `redis` client gem (between `~> 5.0` and `~> 3.0`): Add the following to Gemfile above `abstract_feature_branch` <pre>gem 'redis', '~> 5.0.5'</pre>
|
47
47
|
|
48
48
|
### Ruby Application General Use
|
49
49
|
|
50
|
-
1. <pre>gem install abstract_feature_branch -v 1.3.
|
50
|
+
1. <pre>gem install abstract_feature_branch -v 1.3.2</pre>
|
51
51
|
2. Add code <code>require 'abstract_feature_branch'</code>
|
52
52
|
3. Create <code>config/features.yml</code> under <code>AbstractFeatureBranch.application_root</code> and fill it with content similar to that of the sample <code>config/features.yml</code> mentioned under [**instructions**](#instructions).
|
53
53
|
4. [Optional] Create <code>config/features.local.yml</code> under <code>AbstractFeatureBranch.application_root</code> (more details under [**instructions**](#instructions))
|
@@ -57,7 +57,8 @@ Setup
|
|
57
57
|
8. [Optional] Add code <code>AbstractFeatureBranch.logger = "[your_application_logger]"</code> (it defaults to a new instance of Ruby <code>Logger</code>. Must use a logger with <code>info</code> and <code>warn</code> methods).
|
58
58
|
9. [Optional] Add code <code>AbstractFeatureBranch.cacheable = {[environment] => [true/false]}</code> to indicate cacheability of loaded feature files for enhanced performance (it defaults to true for every environment other than development).
|
59
59
|
10. [Optional] Add code <code>AbstractFeatureBranch.load_application_features</code> to pre-load application features for improved first-use performance
|
60
|
-
11. [Optional] Add code <code>AbstractFeatureBranch.feature_store = Redis.new(options)</code> to configure Redis for overrides or per-user feature enablement
|
60
|
+
11. [Optional] Add code <code>AbstractFeatureBranch.feature_store = Redis.new(options)</code> to configure Redis for overrides and/or per-user feature enablement
|
61
|
+
12. [Optional] Set <code>AbstractFeatureBranch.feature_store_live_fetching = true</code> to enable live fetching of features from store (e.g. Redis) to avoid need for app/server restart upon feature changes, with the trade-off of slightly more latency due to making calls to feature store over the network
|
61
62
|
|
62
63
|
Instructions
|
63
64
|
------------
|
@@ -262,12 +263,16 @@ application more easily.
|
|
262
263
|
Redis Overrides
|
263
264
|
---------------
|
264
265
|
|
265
|
-
Prerequisites: Redis server and client (`redis` gem) and
|
266
|
+
Prerequisites: Redis server and client (`redis` gem) and Redis configuration of `AbstractFeatureBranch.feature_store` in `config/initializers/abstract_feature_branch.rb` (`Redis` `ConnectionPool` instance is recommended for Production environments)
|
266
267
|
|
267
268
|
To be able to override feature configuration in a production environment, you can utilize Redis Overrides.
|
268
269
|
|
269
270
|
Alternatively, you may use Redis Overrides as your main source of feature configuration if you prefer that instead of relying on YAML files.
|
270
271
|
|
272
|
+
Keep in mind that by default, Redis Overrides are fetched on app/server start to pre-cache for better performance.
|
273
|
+
|
274
|
+
To enable live fetching of Redis Overrides, set `AbstractFeatureBranch#feature_store_live_fetching` to `true` (e.g. in `config/initializers/abstract_feature_branch.rb`), but keep in mind the trade-off with more latency due to making calls to Redis Server over the network.
|
275
|
+
|
271
276
|
You can override feature configuration with Redis hash values by calling `AbstractFeatureBranch#set_store_feature` in `rails console` (or `irb` after requiring `redis` and `abstract_feature_branch`):
|
272
277
|
|
273
278
|
```ruby
|
@@ -349,12 +354,19 @@ Rails Initializer
|
|
349
354
|
|
350
355
|
Here is the content of the generated initializer [with `redis` client gem added] (<code>config/initializers/abstract_feature_branch.rb</code>), which contains instructions on how to customize via [dependency injection](http://en.wikipedia.org/wiki/Dependency_injection):
|
351
356
|
|
352
|
-
> # Storage system for features (other than YAML/Env-Vars). Right now, only Redis
|
357
|
+
> # Storage system for features (other than YAML/Env-Vars). Right now, only Redis and ConnectionPool are supported.
|
353
358
|
> # AbstractFeatureBranch.feature_store = Redis.new
|
354
359
|
>
|
360
|
+
> # Storage can be a Redis ConnectionPool instance
|
361
|
+
> # AbstractFeatureBranch.feature_store = ConnectionPool.new { Redis.new }
|
362
|
+
>
|
355
363
|
> # The following example line works with Heroku Redis To Go while still operating on local Redis for local development
|
356
364
|
> # AbstractFeatureBranch.feature_store = Redis.new(:url => ENV['REDISTOGO_URL'])
|
357
365
|
>
|
366
|
+
> # Enable live fetching of feature configuration from storage system, to update features without app/server restart.
|
367
|
+
> # false by default to only load features on app/server start for faster performance (requires restart on change)
|
368
|
+
> AbstractFeatureBranch.feature_store_live_fetching = false
|
369
|
+
>
|
358
370
|
> # Application root where config/features.yml or config/features/ is found
|
359
371
|
> AbstractFeatureBranch.application_root = Rails.root
|
360
372
|
>
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.3.
|
1
|
+
1.3.2
|
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: abstract_feature_branch 1.3.
|
5
|
+
# stub: abstract_feature_branch 1.3.2 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "abstract_feature_branch".freeze
|
9
|
-
s.version = "1.3.
|
9
|
+
s.version = "1.3.2"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Annas \"Andy\" Maleh".freeze]
|
14
|
-
s.date = "2022-12-
|
14
|
+
s.date = "2022-12-12"
|
15
15
|
s.description = "abstract_feature_branch is a Rails gem that enables developers to easily branch by abstraction as per this pattern:\nhttp://paulhammant.com/blog/branch_by_abstraction.html\n\nIt is a productivity and fault tolerance enhancing team practice.\n\nIt provides the ability to wrap blocks of code with an abstract feature branch name, and then\nspecify in a configuration file which features to be switched on or off.\n\nThe goal is to build out upcoming features in the same source code repository branch, regardless of whether all are\ncompleted by the next release date or not, thus increasing team productivity by preventing integration delays.\nDevelopers then disable in-progress features until they are ready to be switched on in production, yet enable them\nlocally and in staging environments for in-progress testing.\n\nThis gives developers the added benefit of being able to switch a feature off after release should big problems arise\nfor a high risk feature.\n\nabstract_feature_branch additionally supports DDD's pattern of\nBounded Contexts by allowing developers to configure\ncontext-specific feature files if needed.\n".freeze
|
16
16
|
s.extra_rdoc_files = [
|
17
17
|
"CHANGELOG.md",
|
@@ -19,27 +19,15 @@ Gem::Specification.new do |s|
|
|
19
19
|
"README.md"
|
20
20
|
]
|
21
21
|
s.files = [
|
22
|
-
".coveralls.yml",
|
23
|
-
".travis.yml",
|
24
22
|
"CHANGELOG.md",
|
25
23
|
"LICENSE.txt",
|
26
24
|
"README.md",
|
27
|
-
"RELEASE_NOTES.md",
|
28
|
-
"TODO.md",
|
29
25
|
"VERSION",
|
30
26
|
"abstract_feature_branch.gemspec",
|
31
|
-
"config/features/admin.local.yml",
|
32
|
-
"config/features/admin.yml",
|
33
|
-
"config/features/internal/wiki.local.yml",
|
34
|
-
"config/features/internal/wiki.yml",
|
35
|
-
"config/features/public.local.yml",
|
36
|
-
"config/features/public.yml",
|
37
|
-
"img/BigAstronaut-Logo.png",
|
38
|
-
"img/EarlyShares-Logo.svg",
|
39
|
-
"img/Factor75-Logo.svg",
|
40
27
|
"lib/abstract_feature_branch.rb",
|
41
28
|
"lib/abstract_feature_branch/configuration.rb",
|
42
29
|
"lib/abstract_feature_branch/file_beautifier.rb",
|
30
|
+
"lib/abstract_feature_branch/redis/connection_pool_to_redis_adapter.rb",
|
43
31
|
"lib/ext/feature_branch.rb",
|
44
32
|
"lib/generators/abstract_feature_branch/context_generator.rb",
|
45
33
|
"lib/generators/abstract_feature_branch/install_generator.rb",
|
@@ -47,34 +35,12 @@ Gem::Specification.new do |s|
|
|
47
35
|
"lib/generators/templates/config/features.local.yml",
|
48
36
|
"lib/generators/templates/config/features.yml",
|
49
37
|
"lib/generators/templates/config/initializers/abstract_feature_branch.rb",
|
50
|
-
"lib/generators/templates/lib/tasks/abstract_feature_branch.rake"
|
51
|
-
"ruby187.Gemfile",
|
52
|
-
"spec/abstract_feature_branch/file_beautifier_spec.rb",
|
53
|
-
"spec/ext/feature_branch__feature_branch_per_user_spec.rb",
|
54
|
-
"spec/ext/feature_branch__feature_branch_spec.rb",
|
55
|
-
"spec/ext/feature_branch__feature_enabled_spec.rb",
|
56
|
-
"spec/fixtures/application_development_config/config/features.reference.yml",
|
57
|
-
"spec/fixtures/application_no_config/no_config",
|
58
|
-
"spec/fixtures/application_rails_config/config/features.local.yml",
|
59
|
-
"spec/fixtures/application_rails_config/config/features.yml",
|
60
|
-
"spec/fixtures/application_ugly_config_reference/config/another_application_configuration.yml",
|
61
|
-
"spec/fixtures/application_ugly_config_reference/config/database.yml",
|
62
|
-
"spec/fixtures/application_ugly_config_reference/config/features.local.yml",
|
63
|
-
"spec/fixtures/application_ugly_config_reference/config/features.yml",
|
64
|
-
"spec/fixtures/application_ugly_config_reference/config/features/admin.local.yml",
|
65
|
-
"spec/fixtures/application_ugly_config_reference/config/features/admin.yml",
|
66
|
-
"spec/fixtures/application_ugly_config_reference/config/features/empty.local.yml",
|
67
|
-
"spec/fixtures/application_ugly_config_reference/config/features/feature_empty_config.local.yml",
|
68
|
-
"spec/fixtures/application_ugly_config_reference/config/features/including_comments.local.yml",
|
69
|
-
"spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.local.yml",
|
70
|
-
"spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.yml",
|
71
|
-
"spec/fixtures/application_ugly_config_reference/config/features/public.local.yml",
|
72
|
-
"spec/fixtures/application_ugly_config_reference/config/features/public.yml"
|
38
|
+
"lib/generators/templates/lib/tasks/abstract_feature_branch.rake"
|
73
39
|
]
|
74
40
|
s.homepage = "http://github.com/AndyObtiva/abstract_feature_branch".freeze
|
75
41
|
s.licenses = ["MIT".freeze]
|
76
|
-
s.post_install_message = "\nRails-only post-install instructions:\n\n1) Run the following command to generate the Rails initializer and basic feature files:\n\nrails g abstract_feature_branch:install\n\n2) Optionally, you may run this command to generate feature files per context:\n\nrails g abstract_feature_branch:context context_path\n \n3) Optionally, install Redis server with [Homebrew](https://brew.sh/) by running:\n\nbrew install redis\n\n4) Optionally, install redis client gem (required with Redis server) by adding the following line to Gemfile above abstract_feature_branch:\n\ngem 'redis', '~> 5.0.5'\n\nAfterwards, run:\n\nbundle\n\n5) Optionally, customize configuration in config/initializers/abstract_feature_branch.rb\n\n(can be useful for changing location of feature files in Rails application,\nconfiguring Redis to use for overrides and per-user feature enablement,\nand/or troubleshooting specific Rails environment feature configurations)\n\n".freeze
|
77
|
-
s.rubygems_version = "3.
|
42
|
+
s.post_install_message = "\nRails-only post-install instructions:\n\n1) Run the following command to generate the Rails initializer and basic feature files:\n\nrails g abstract_feature_branch:install\n\n2) Optionally, you may run this command to generate feature files per context:\n\nrails g abstract_feature_branch:context context_path\n \n3) Optionally, install Redis server with [Homebrew](https://brew.sh/) by running:\n\nbrew install redis\n\n4) Optionally, install redis client gem (required with Redis server) by adding the following line to Gemfile above abstract_feature_branch:\n\ngem 'redis', '~> 5.0.5'\n\nAfterwards, run:\n\nbundle\n\n5) Optionally, customize configuration in config/initializers/abstract_feature_branch.rb\n\n(can be useful for changing location of feature files in Rails application,\nconfiguring Redis with a Redis or ConnectionPool instance to use for overrides and per-user feature enablement,\nand/or troubleshooting specific Rails environment feature configurations)\n\n".freeze
|
43
|
+
s.rubygems_version = "3.1.4".freeze
|
78
44
|
s.summary = "abstract_feature_branch is a Rails gem that enables developers to easily branch by abstraction as per this pattern: http://paulhammant.com/blog/branch_by_abstraction.html".freeze
|
79
45
|
|
80
46
|
if s.respond_to? :specification_version then
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'abstract_feature_branch/redis/connection_pool_to_redis_adapter'
|
2
|
+
|
1
3
|
module AbstractFeatureBranch
|
2
4
|
class Configuration
|
3
5
|
def application_root
|
@@ -43,22 +45,36 @@ module AbstractFeatureBranch
|
|
43
45
|
end
|
44
46
|
|
45
47
|
def feature_store
|
46
|
-
@feature_store
|
48
|
+
@feature_store
|
47
49
|
end
|
48
50
|
alias user_features_storage feature_store
|
49
51
|
|
50
52
|
def feature_store=(feature_store)
|
51
|
-
|
53
|
+
if feature_store.nil?
|
54
|
+
@feature_store = nil
|
55
|
+
else
|
56
|
+
begin
|
57
|
+
@feature_store = feature_store.is_a?(::ConnectionPool) ? AbstractFeatureBranch::Redis::ConnectionPoolToRedisAdapter.new(feature_store) : feature_store
|
58
|
+
rescue NameError => e
|
59
|
+
logger.debug { "connection_pool gem is not available" }
|
60
|
+
@feature_store = feature_store
|
61
|
+
end
|
62
|
+
end
|
52
63
|
end
|
53
64
|
alias user_features_storage= feature_store=
|
54
65
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
66
|
+
def feature_store_live_fetching
|
67
|
+
initialize_feature_store_live_fetching if @feature_store_live_fetching.nil?
|
68
|
+
@feature_store_live_fetching
|
69
|
+
end
|
70
|
+
alias feature_store_live_fetching? feature_store_live_fetching
|
71
|
+
|
72
|
+
def feature_store_live_fetching=(value)
|
73
|
+
@feature_store_live_fetching = value
|
74
|
+
end
|
75
|
+
|
76
|
+
def initialize_feature_store_live_fetching
|
77
|
+
@feature_store_live_fetching = false
|
78
|
+
end
|
63
79
|
end
|
64
80
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module AbstractFeatureBranch
|
2
|
+
module Redis
|
3
|
+
# Adapts a ConnectionPool instance to the Redis object interface
|
4
|
+
class ConnectionPoolToRedisAdapter
|
5
|
+
attr_reader :connection_pool
|
6
|
+
|
7
|
+
def initialize(connection_pool)
|
8
|
+
@connection_pool = connection_pool
|
9
|
+
end
|
10
|
+
|
11
|
+
def respond_to?(method_name, include_private = false, &block)
|
12
|
+
result = false
|
13
|
+
@connection_pool.with do |connection|
|
14
|
+
result ||= connection.respond_to?(method_name, include_private, &block)
|
15
|
+
end
|
16
|
+
result || super
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(method_name, *args, &block)
|
20
|
+
connection_can_respond_to = nil
|
21
|
+
result = nil
|
22
|
+
@connection_pool.with do |connection|
|
23
|
+
connection_can_respond_to = connection.respond_to?(method_name, true)
|
24
|
+
result = connection.send(method_name, *args, &block) if connection_can_respond_to
|
25
|
+
end
|
26
|
+
if connection_can_respond_to
|
27
|
+
result
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -13,7 +13,9 @@ require 'logger' unless defined?(Rails) && Rails.logger
|
|
13
13
|
require 'deep_merge' unless {}.respond_to?(:deep_merge!)
|
14
14
|
require 'forwardable'
|
15
15
|
|
16
|
-
|
16
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
17
|
+
|
18
|
+
require 'abstract_feature_branch/configuration'
|
17
19
|
|
18
20
|
module AbstractFeatureBranch
|
19
21
|
ENV_FEATURE_PREFIX = "abstract_feature_branch_"
|
@@ -21,14 +23,16 @@ module AbstractFeatureBranch
|
|
21
23
|
|
22
24
|
class << self
|
23
25
|
extend Forwardable
|
24
|
-
def_delegators :configuration, :application_root, :application_root=, :initialize_application_root, :application_environment, :application_environment=, :initialize_application_environment,
|
26
|
+
def_delegators :configuration, :application_root, :application_root=, :initialize_application_root, :application_environment, :application_environment=, :initialize_application_environment,
|
27
|
+
:logger, :logger=, :initialize_logger, :cacheable, :cacheable=, :initialize_cacheable, :feature_store, :feature_store=, :user_features_storage, :user_features_storage=,
|
28
|
+
:feature_store_live_fetching, :feature_store_live_fetching=
|
25
29
|
|
26
30
|
def configuration
|
27
31
|
@configuration ||= Configuration.new
|
28
32
|
end
|
29
33
|
|
30
34
|
def redis_overrides
|
31
|
-
load_redis_overrides
|
35
|
+
@redis_overrides ||= load_redis_overrides
|
32
36
|
end
|
33
37
|
def load_redis_overrides
|
34
38
|
return {} if feature_store.nil?
|
@@ -37,7 +41,7 @@ module AbstractFeatureBranch
|
|
37
41
|
output.merge(feature => get_store_feature(feature))
|
38
42
|
end
|
39
43
|
|
40
|
-
downcase_keys(redis_feature_hash)
|
44
|
+
@redis_overrides = downcase_keys(redis_feature_hash)
|
41
45
|
end
|
42
46
|
|
43
47
|
def environment_variable_overrides
|
@@ -74,19 +78,22 @@ module AbstractFeatureBranch
|
|
74
78
|
local_features[environment] ||= {}
|
75
79
|
@environment_features[environment] = features[environment].
|
76
80
|
merge(local_features[environment]).
|
77
|
-
merge(environment_variable_overrides)
|
81
|
+
merge(environment_variable_overrides).
|
82
|
+
merge(redis_overrides)
|
78
83
|
end
|
79
84
|
def application_features
|
80
85
|
unload_application_features unless cacheable?
|
81
86
|
environment_features(application_environment)
|
82
87
|
end
|
83
88
|
def load_application_features
|
89
|
+
AbstractFeatureBranch.load_redis_overrides
|
84
90
|
AbstractFeatureBranch.load_environment_variable_overrides
|
85
91
|
AbstractFeatureBranch.load_features
|
86
92
|
AbstractFeatureBranch.load_local_features
|
87
93
|
AbstractFeatureBranch.load_environment_features(application_environment)
|
88
94
|
end
|
89
95
|
def unload_application_features
|
96
|
+
@redis_overrides = nil
|
90
97
|
@environment_variable_overrides = nil
|
91
98
|
@features = nil
|
92
99
|
@local_features = nil
|
data/lib/ext/feature_branch.rb
CHANGED
@@ -10,7 +10,7 @@ class Object
|
|
10
10
|
def self.feature_enabled?(feature_name, user_id = nil)
|
11
11
|
normalized_feature_name = feature_name.to_s.downcase
|
12
12
|
|
13
|
-
redis_override_value = AbstractFeatureBranch.get_store_feature(normalized_feature_name) rescue nil
|
13
|
+
redis_override_value = (AbstractFeatureBranch.get_store_feature(normalized_feature_name) rescue nil) if AbstractFeatureBranch.configuration.feature_store_live_fetching?
|
14
14
|
value = !redis_override_value.nil? ? redis_override_value : AbstractFeatureBranch.application_features[normalized_feature_name]
|
15
15
|
if value == 'per_user'
|
16
16
|
value = !user_id.nil? && AbstractFeatureBranch.user_features_storage.sismember("#{AbstractFeatureBranch::ENV_FEATURE_PREFIX}#{normalized_feature_name}", user_id)
|
@@ -1,9 +1,16 @@
|
|
1
|
-
# Storage system for features (other than YAML/Env-Vars). Right now, only Redis
|
1
|
+
# Storage system for features (other than YAML/Env-Vars). Right now, only Redis and ConnectionPool are supported.
|
2
2
|
# AbstractFeatureBranch.feature_store = Redis.new
|
3
3
|
|
4
|
+
# Storage can be a Redis ConnectionPool instance
|
5
|
+
# AbstractFeatureBranch.feature_store = ConnectionPool.new { Redis.new }
|
6
|
+
|
4
7
|
# The following example line works with Heroku Redis To Go while still operating on local Redis for local development
|
5
8
|
# AbstractFeatureBranch.feature_store = Redis.new(:url => ENV['REDISTOGO_URL'])
|
6
9
|
|
10
|
+
# Enable live fetching of feature configuration from storage system, to update features without app/server restart.
|
11
|
+
# false by default to only load features on app/server start for faster performance (requires restart on change)
|
12
|
+
AbstractFeatureBranch.feature_store_live_fetching = false
|
13
|
+
|
7
14
|
# Application root where config/features.yml or config/features/ is found
|
8
15
|
AbstractFeatureBranch.application_root = Rails.root
|
9
16
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: abstract_feature_branch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Annas "Andy" Maleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-12-
|
11
|
+
date: 2022-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: deep_merge
|
@@ -122,27 +122,15 @@ extra_rdoc_files:
|
|
122
122
|
- LICENSE.txt
|
123
123
|
- README.md
|
124
124
|
files:
|
125
|
-
- ".coveralls.yml"
|
126
|
-
- ".travis.yml"
|
127
125
|
- CHANGELOG.md
|
128
126
|
- LICENSE.txt
|
129
127
|
- README.md
|
130
|
-
- RELEASE_NOTES.md
|
131
|
-
- TODO.md
|
132
128
|
- VERSION
|
133
129
|
- abstract_feature_branch.gemspec
|
134
|
-
- config/features/admin.local.yml
|
135
|
-
- config/features/admin.yml
|
136
|
-
- config/features/internal/wiki.local.yml
|
137
|
-
- config/features/internal/wiki.yml
|
138
|
-
- config/features/public.local.yml
|
139
|
-
- config/features/public.yml
|
140
|
-
- img/BigAstronaut-Logo.png
|
141
|
-
- img/EarlyShares-Logo.svg
|
142
|
-
- img/Factor75-Logo.svg
|
143
130
|
- lib/abstract_feature_branch.rb
|
144
131
|
- lib/abstract_feature_branch/configuration.rb
|
145
132
|
- lib/abstract_feature_branch/file_beautifier.rb
|
133
|
+
- lib/abstract_feature_branch/redis/connection_pool_to_redis_adapter.rb
|
146
134
|
- lib/ext/feature_branch.rb
|
147
135
|
- lib/generators/abstract_feature_branch/context_generator.rb
|
148
136
|
- lib/generators/abstract_feature_branch/install_generator.rb
|
@@ -151,28 +139,6 @@ files:
|
|
151
139
|
- lib/generators/templates/config/features.yml
|
152
140
|
- lib/generators/templates/config/initializers/abstract_feature_branch.rb
|
153
141
|
- lib/generators/templates/lib/tasks/abstract_feature_branch.rake
|
154
|
-
- ruby187.Gemfile
|
155
|
-
- spec/abstract_feature_branch/file_beautifier_spec.rb
|
156
|
-
- spec/ext/feature_branch__feature_branch_per_user_spec.rb
|
157
|
-
- spec/ext/feature_branch__feature_branch_spec.rb
|
158
|
-
- spec/ext/feature_branch__feature_enabled_spec.rb
|
159
|
-
- spec/fixtures/application_development_config/config/features.reference.yml
|
160
|
-
- spec/fixtures/application_no_config/no_config
|
161
|
-
- spec/fixtures/application_rails_config/config/features.local.yml
|
162
|
-
- spec/fixtures/application_rails_config/config/features.yml
|
163
|
-
- spec/fixtures/application_ugly_config_reference/config/another_application_configuration.yml
|
164
|
-
- spec/fixtures/application_ugly_config_reference/config/database.yml
|
165
|
-
- spec/fixtures/application_ugly_config_reference/config/features.local.yml
|
166
|
-
- spec/fixtures/application_ugly_config_reference/config/features.yml
|
167
|
-
- spec/fixtures/application_ugly_config_reference/config/features/admin.local.yml
|
168
|
-
- spec/fixtures/application_ugly_config_reference/config/features/admin.yml
|
169
|
-
- spec/fixtures/application_ugly_config_reference/config/features/empty.local.yml
|
170
|
-
- spec/fixtures/application_ugly_config_reference/config/features/feature_empty_config.local.yml
|
171
|
-
- spec/fixtures/application_ugly_config_reference/config/features/including_comments.local.yml
|
172
|
-
- spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.local.yml
|
173
|
-
- spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.yml
|
174
|
-
- spec/fixtures/application_ugly_config_reference/config/features/public.local.yml
|
175
|
-
- spec/fixtures/application_ugly_config_reference/config/features/public.yml
|
176
142
|
homepage: http://github.com/AndyObtiva/abstract_feature_branch
|
177
143
|
licenses:
|
178
144
|
- MIT
|
@@ -186,8 +152,8 @@ post_install_message: "\nRails-only post-install instructions:\n\n1) Run the fol
|
|
186
152
|
following line to Gemfile above abstract_feature_branch:\n\ngem 'redis', '~> 5.0.5'\n\nAfterwards,
|
187
153
|
run:\n\nbundle\n\n5) Optionally, customize configuration in config/initializers/abstract_feature_branch.rb\n\n(can
|
188
154
|
be useful for changing location of feature files in Rails application,\nconfiguring
|
189
|
-
Redis to use for overrides and per-user
|
190
|
-
specific Rails environment feature configurations)\n\n"
|
155
|
+
Redis with a Redis or ConnectionPool instance to use for overrides and per-user
|
156
|
+
feature enablement,\nand/or troubleshooting specific Rails environment feature configurations)\n\n"
|
191
157
|
rdoc_options: []
|
192
158
|
require_paths:
|
193
159
|
- lib
|
@@ -202,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
202
168
|
- !ruby/object:Gem::Version
|
203
169
|
version: '0'
|
204
170
|
requirements: []
|
205
|
-
rubygems_version: 3.
|
171
|
+
rubygems_version: 3.1.4
|
206
172
|
signing_key:
|
207
173
|
specification_version: 4
|
208
174
|
summary: 'abstract_feature_branch is a Rails gem that enables developers to easily
|
data/.coveralls.yml
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
repo_token: ylr6gphUkEVGf9nvY5Hfz48RHZnOf0Jjv
|
data/.travis.yml
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
services:
|
3
|
-
- redis-server
|
4
|
-
addons:
|
5
|
-
code_climate:
|
6
|
-
repo_token: 535ff40cf55554362b2f48b85e913a7362f0cf3e51638455dab456006258c5a0
|
7
|
-
rvm:
|
8
|
-
- 2.2.1
|
9
|
-
- 2.1.5
|
10
|
-
- 2.0.0
|
11
|
-
- 1.9.3
|
12
|
-
- 1.8.7
|
13
|
-
- ree
|
14
|
-
gemfile:
|
15
|
-
- Gemfile
|
16
|
-
- ruby187.Gemfile
|
17
|
-
matrix:
|
18
|
-
exclude:
|
19
|
-
- rvm: 2.2.1
|
20
|
-
gemfile: ruby187.Gemfile
|
21
|
-
- rvm: 2.1.5
|
22
|
-
gemfile: ruby187.Gemfile
|
23
|
-
- rvm: 2.0.0
|
24
|
-
gemfile: ruby187.Gemfile
|
25
|
-
- rvm: 1.9.3
|
26
|
-
gemfile: ruby187.Gemfile
|
27
|
-
- rvm: 1.8.7
|
28
|
-
gemfile: Gemfile
|
29
|
-
- rvm: ree
|
30
|
-
gemfile: Gemfile
|
data/RELEASE_NOTES.md
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
Release Notes
|
2
|
-
-------------
|
3
|
-
|
4
|
-
Version 1.0.0:
|
5
|
-
- Added configuration support for feature cacheability. Completed documentation, adding more details.
|
6
|
-
|
7
|
-
Version 0.9.0:
|
8
|
-
- Added support for runtime read of feature files in development to ease local testing (trading off performance)
|
9
|
-
|
10
|
-
Version 0.8.0:
|
11
|
-
- Added rake task for beautifying feature files, sorting feature names within environment sections and eliminating extra empty lines. Added support for externalized logger.
|
12
|
-
|
13
|
-
Version 0.7.1:
|
14
|
-
- Fixed undefined method issue with using <code>AbstractFeatureBranch.load_application_features</code> to improve first use performance
|
15
|
-
|
16
|
-
Version 0.7.0:
|
17
|
-
- Added support for general Ruby use (without Rails) by externalizing AbstractFeatureBranch.application_root and AbstractFeatureBranch.application_environment. Added initializer to optionally configure them. Supported case-insensitive feature names.
|
18
|
-
|
19
|
-
Version 0.6.1 - 0.6.4:
|
20
|
-
- Fixed issues including making feature configuration files optional (in case one wants to get rid of <code>features.local.yml</code> or even <code>features.yml</code>)
|
21
|
-
|
22
|
-
Version 0.6.0:
|
23
|
-
- Added a context generator and support for reading feature configuration from context files <code>config/features/**/*.yml</code> and <code>config/features/**/*.local.yml</code>
|
24
|
-
|
25
|
-
Version 0.5.0:
|
26
|
-
- Added support for local configuration feature ignored by git + some performance optimizations via configuration caching and better algorithms.
|
27
|
-
|
28
|
-
Version 0.4.0:
|
29
|
-
- Added support for overwriting feature configuration with environment variable overrides. Very useful on Heroku to quickly enable/disable features without a redeploy.
|
30
|
-
|
31
|
-
Version 0.3.6:
|
32
|
-
- Fixed feature_branch issue with invalid feature name, preventing block execution and returning nil instead
|
33
|
-
|
34
|
-
Version 0.3.5:
|
35
|
-
- Fixed issue with generator not allowing consuming client app to start Rails server successfully
|
36
|
-
|
37
|
-
Version 0.3.4:
|
38
|
-
- Added <code>abstract_feature_branch:install</code> generator to easily get started with a sample <code>config/features.yml</code>
|
39
|
-
|
40
|
-
Version 0.3.3:
|
41
|
-
- Removed version from README title
|
42
|
-
|
43
|
-
Version 0.3.2:
|
44
|
-
- Added <code>AbstractFeatureBranch.features</code> to delay YAML load until <code>Rails.root</code> has been established
|
45
|
-
|
46
|
-
Version 0.3.1:
|
47
|
-
- Removed dependency on the rails_config gem
|
48
|
-
|
49
|
-
Version 0.3.0:
|
50
|
-
- Simplified <code>features.yml</code> requirement to have a features header under each environment
|
51
|
-
- Moved feature storage from Settings object to <code>AbstractFeatureBranch::FEATURES</code>
|
52
|
-
|
53
|
-
Version 0.2.0:
|
54
|
-
- Support an "else" block to execute when a feature is off (via <code>:true</code> and <code>:false</code> lambda arguments)
|
55
|
-
- Support ability to check if a feature is enabled or not (via <code>feature_enabled?</code>)
|
data/TODO.md
DELETED
data/config/features/admin.yml
DELETED