remote_config 1.0.0.pre.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +13 -0
- data/.github/workflows/continuous-deployment.yml +34 -0
- data/.github/workflows/continuous-integration.yml +45 -0
- data/.gitignore +58 -0
- data/.rubocop.yml +9 -0
- data/Gemfile +23 -0
- data/README.md +122 -0
- data/Rakefile +24 -0
- data/app/controllers/remote_config/application_controller.rb +5 -0
- data/app/models/remote_config/application_record.rb +8 -0
- data/bin/rails +14 -0
- data/config/routes.rb +3 -0
- data/lib/remote_config/adapters/base.rb +23 -0
- data/lib/remote_config/adapters/ruby_config_adapter.rb +32 -0
- data/lib/remote_config/engine.rb +7 -0
- data/lib/remote_config/exceptions.rb +47 -0
- data/lib/remote_config/flagging.rb +33 -0
- data/lib/remote_config/rails/routes.rb +11 -0
- data/lib/remote_config/version.rb +5 -0
- data/lib/remote_config.rb +50 -0
- data/remote-config.gemspec +21 -0
- data/spec/rails_app/.rspec +1 -0
- data/spec/rails_app/Rakefile +6 -0
- data/spec/rails_app/app/assets/config/manifest.js +3 -0
- data/spec/rails_app/app/assets/images/.keep +0 -0
- data/spec/rails_app/app/assets/stylesheets/application.css +15 -0
- data/spec/rails_app/app/channels/application_cable/channel.rb +4 -0
- data/spec/rails_app/app/channels/application_cable/connection.rb +4 -0
- data/spec/rails_app/app/controllers/application_controller.rb +2 -0
- data/spec/rails_app/app/controllers/concerns/.keep +0 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/jobs/application_job.rb +7 -0
- data/spec/rails_app/app/mailers/application_mailer.rb +4 -0
- data/spec/rails_app/app/models/application_record.rb +3 -0
- data/spec/rails_app/app/models/concerns/.keep +0 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +15 -0
- data/spec/rails_app/app/views/layouts/mailer.html.erb +13 -0
- data/spec/rails_app/app/views/layouts/mailer.text.erb +1 -0
- data/spec/rails_app/bin/rails +4 -0
- data/spec/rails_app/bin/rake +4 -0
- data/spec/rails_app/bin/setup +33 -0
- data/spec/rails_app/config/application.rb +25 -0
- data/spec/rails_app/config/boot.rb +5 -0
- data/spec/rails_app/config/cable.yml +10 -0
- data/spec/rails_app/config/database.yml +25 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +70 -0
- data/spec/rails_app/config/environments/production.rb +93 -0
- data/spec/rails_app/config/environments/test.rb +60 -0
- data/spec/rails_app/config/initializers/assets.rb +12 -0
- data/spec/rails_app/config/initializers/content_security_policy.rb +26 -0
- data/spec/rails_app/config/initializers/filter_parameter_logging.rb +8 -0
- data/spec/rails_app/config/initializers/inflections.rb +16 -0
- data/spec/rails_app/config/initializers/permissions_policy.rb +11 -0
- data/spec/rails_app/config/locales/en.yml +33 -0
- data/spec/rails_app/config/puma.rb +43 -0
- data/spec/rails_app/config/routes.rb +3 -0
- data/spec/rails_app/config/storage.yml +34 -0
- data/spec/rails_app/config.ru +6 -0
- data/spec/rails_app/db/schema.rb +15 -0
- data/spec/rails_app/lib/assets/.keep +0 -0
- data/spec/rails_app/log/.keep +0 -0
- data/spec/rails_app/public/404.html +67 -0
- data/spec/rails_app/public/422.html +67 -0
- data/spec/rails_app/public/500.html +66 -0
- data/spec/rails_app/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/rails_app/public/apple-touch-icon.png +0 -0
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/storage/.keep +0 -0
- data/spec/rails_app/tmp/.keep +0 -0
- data/spec/rails_app/tmp/development_secret.txt +1 -0
- data/spec/rails_app/tmp/pids/.keep +0 -0
- data/spec/rails_app/tmp/storage/.keep +0 -0
- data/spec/rails_helper.rb +66 -0
- data/spec/remote_config/adapters/ruby_config_adapter_spec.rb +83 -0
- data/spec/remote_config/flagging_spec.rb +171 -0
- data/spec/spec_helper.rb +97 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 31d21488e0ffa05436025e157209cc9d44dc1e3fabb307a2e9d71c220bdb7069
|
4
|
+
data.tar.gz: 0bd6482ddcbdb2ab5abe5286997ea029134f46b42bd5a1f695206904634c3bc1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 164e299f5dcd5585d136d3aafecb8d49d98a8555ec0330de972803fe798c2e763c76c6af188c8f24468890f36407aa04fc3a7c241129738315eee2b49f0dda80
|
7
|
+
data.tar.gz: 51a8988537d414973c5a3473a0aaaba25c0458ccc39352f565d2b0edd075866437409f3add830a3e2377a95f7819db8dbddd5826810979e6ec9ed5e482f5d304
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<!--
|
2
|
+
List of related JIRAs:
|
3
|
+
e.g. [[MISC-123]](https://paperkite.atlassian.net/browse/MISC-123)
|
4
|
+
-->
|
5
|
+
|
6
|
+
### Description
|
7
|
+
<!-- explanation of the change and your thinking behind the implementation -->
|
8
|
+
|
9
|
+
### How to test
|
10
|
+
<!-- explanation of how to test / perform acceptance over the changes -->
|
11
|
+
|
12
|
+
### Resources
|
13
|
+
<!-- attach screenshots of change or links to relevant resources when applicable -->
|
@@ -0,0 +1,34 @@
|
|
1
|
+
name: Continuous Deployment
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- v[0-9]+.[0-9]+.[0-9]+ # e.g. 2.7.1
|
7
|
+
- v[0-9]+.[0-9]+.[0-9]+-[a-z]+ # e.g. v2.7.1-beta
|
8
|
+
- v[0-9]+.[0-9]+.[0-9]+-[a-z]+.[0-9]+ # e.g. v2.7.1-beta.1
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
|
12
|
+
publish_to_rubygems:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v2
|
16
|
+
- uses: ruby/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: 3.1.1
|
19
|
+
- name: Install bundler and bundle
|
20
|
+
run: |
|
21
|
+
gem install bundler
|
22
|
+
bundle
|
23
|
+
- name: Set up Rubygems credentials
|
24
|
+
run: |
|
25
|
+
mkdir -p ~/.gem
|
26
|
+
cat > ~/.gem/credentials << ENDOFFILE
|
27
|
+
---
|
28
|
+
:github: Bearer ${{ github.token }}
|
29
|
+
:rubygems_api_key: ${{ secrets.RUBYGEMS_API_KEY }}
|
30
|
+
ENDOFFILE
|
31
|
+
|
32
|
+
chmod 0600 ~/.gem/credentials
|
33
|
+
- name: Publish to Rubygems
|
34
|
+
run: rake publish
|
@@ -0,0 +1,45 @@
|
|
1
|
+
name: Continuous Integration
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
- develop
|
8
|
+
- epic/*
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
|
12
|
+
rubocop:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v2
|
16
|
+
- uses: ruby/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: 3.0.1
|
19
|
+
- name: Install PK Rubocop gem
|
20
|
+
run: |
|
21
|
+
gem install paperkite-rubocop --pre
|
22
|
+
- name: Run Rubocop
|
23
|
+
run: |
|
24
|
+
rubocop
|
25
|
+
|
26
|
+
rspec:
|
27
|
+
runs-on: ubuntu-latest
|
28
|
+
strategy:
|
29
|
+
matrix:
|
30
|
+
ruby-version: [2.7.4, 3.0.1, 3.1.1]
|
31
|
+
steps:
|
32
|
+
- uses: actions/checkout@v2
|
33
|
+
- uses: ruby/setup-ruby@v1
|
34
|
+
with:
|
35
|
+
ruby-version: ${{ matrix.ruby-version }}
|
36
|
+
- name: Install bundler and bundle
|
37
|
+
run: |
|
38
|
+
gem install bundler
|
39
|
+
bundle
|
40
|
+
- name: Run RSpec
|
41
|
+
env:
|
42
|
+
RAILS_ENV: test
|
43
|
+
run: |
|
44
|
+
bundle exec rails db:test:prepare
|
45
|
+
bundle exec rspec
|
data/.gitignore
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/spec/rails_app/db/*.sqlite3
|
10
|
+
/spec/rails_app/log
|
11
|
+
/test/tmp/
|
12
|
+
/test/version_tmp/
|
13
|
+
/tmp/
|
14
|
+
|
15
|
+
# Used by dotenv library to load environment variables.
|
16
|
+
# .env
|
17
|
+
|
18
|
+
# Ignore Byebug command history file.
|
19
|
+
.byebug_history
|
20
|
+
|
21
|
+
## Specific to RubyMotion:
|
22
|
+
.dat*
|
23
|
+
.repl_history
|
24
|
+
build/
|
25
|
+
*.bridgesupport
|
26
|
+
build-iPhoneOS/
|
27
|
+
build-iPhoneSimulator/
|
28
|
+
|
29
|
+
## Specific to RubyMotion (use of CocoaPods):
|
30
|
+
#
|
31
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
32
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
33
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
34
|
+
#
|
35
|
+
# vendor/Pods/
|
36
|
+
|
37
|
+
## Documentation cache and generated files:
|
38
|
+
/.yardoc/
|
39
|
+
/_yardoc/
|
40
|
+
/doc/
|
41
|
+
/rdoc/
|
42
|
+
|
43
|
+
## Environment normalization:
|
44
|
+
/.bundle/
|
45
|
+
/vendor/bundle
|
46
|
+
/lib/bundler/man/
|
47
|
+
|
48
|
+
# for a library or gem, you might want to ignore these files since the code is
|
49
|
+
# intended to run in multiple environments; otherwise, check them in:
|
50
|
+
Gemfile.lock
|
51
|
+
.ruby-version
|
52
|
+
.ruby-gemset
|
53
|
+
|
54
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
55
|
+
.rvmrc
|
56
|
+
|
57
|
+
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
58
|
+
# .rubocop-https?--*
|
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
ruby RUBY_VERSION
|
6
|
+
|
7
|
+
gemspec
|
8
|
+
|
9
|
+
gem "config"
|
10
|
+
gem "rails"
|
11
|
+
|
12
|
+
group :test do
|
13
|
+
gem "rspec-rails"
|
14
|
+
gem "sqlite3"
|
15
|
+
end
|
16
|
+
|
17
|
+
group :test, :development do
|
18
|
+
gem "pry"
|
19
|
+
end
|
20
|
+
|
21
|
+
group :development do
|
22
|
+
gem "paperkite-rubocop", tag: "v1.0.0-beta.6"
|
23
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
# Remote config
|
2
|
+
|
3
|
+
A gem for managing feature and release flags in the backend and providing them remotely to a front-end.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
### Feature Flagging
|
8
|
+
|
9
|
+
Flagging allows checking of config values and doing different things based on their boolean value.
|
10
|
+
|
11
|
+
By including the flagging module you'll have access to the following methods:
|
12
|
+
|
13
|
+
```rb
|
14
|
+
include RemoteConfig::Flagging
|
15
|
+
```
|
16
|
+
|
17
|
+
```rb
|
18
|
+
caffeinate if feature_enabled? "coffee.caffeinated"
|
19
|
+
```
|
20
|
+
|
21
|
+
```rb
|
22
|
+
feature_enabled? "coffee.caffeinated" do
|
23
|
+
caffeinate
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
The `RemoteConfig::Flagging` module is included into the rails route mapper so you can use flagging at route setup. This allows the deployment of unreleased endpoints that aren't routable until they are released.
|
28
|
+
|
29
|
+
```rb
|
30
|
+
routes do
|
31
|
+
feature_enabled? "coffee_ordering" do
|
32
|
+
resource :coffee
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
### Release flags
|
38
|
+
|
39
|
+
Release flags work with the same syntax (replace `feature?` with `released?`), however instead of checking for boolean truthfulness, the value of the falg corresponds to a stage that it is released to. The `released?` method will then be checking if the current environment is in that release stage and returning true if so.
|
40
|
+
|
41
|
+
For example, if your configured release stages are:
|
42
|
+
```rb
|
43
|
+
RemoteConfig.configure do |config|
|
44
|
+
config.release_stages = {
|
45
|
+
production: %s[production qa dev development],
|
46
|
+
qa: %s[qa dev development],
|
47
|
+
development: %s[dev development]
|
48
|
+
}
|
49
|
+
```
|
50
|
+
|
51
|
+
Then the following values are returned:
|
52
|
+
|
53
|
+
| | development | uat | production |
|
54
|
+
| ----------- | ----------- | ----- | ---------- |
|
55
|
+
| dev | true | true | true |
|
56
|
+
| development | true | true | true |
|
57
|
+
| qa | false | true | true |
|
58
|
+
| production | false | false | true |
|
59
|
+
|
60
|
+
*Current environments down the left VS the release stages along the top.*
|
61
|
+
|
62
|
+
Alternatively, if you wanted to release to specific environments instead of progressing through them, you can return an array of the exact environment(s) that you want it released on.
|
63
|
+
|
64
|
+
e.g. if the value is `[:qa]`, them it'll be `false` on development, dev and production, while true on qa.
|
65
|
+
|
66
|
+
By including the flagging module you'll have access to the following methods:
|
67
|
+
|
68
|
+
```rb
|
69
|
+
include RemoteConfig::Flagging
|
70
|
+
```
|
71
|
+
|
72
|
+
```rb
|
73
|
+
prompt_for_coffee_ordering if released? "coffee_ordering.cta"
|
74
|
+
```
|
75
|
+
|
76
|
+
```rb
|
77
|
+
released? "coffee_ordering.cta" do
|
78
|
+
prompt_for_coffee_ordering
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
### Adapters
|
83
|
+
|
84
|
+
Where the feature and release flags are sorted from depends on what adapter is used. Currently, the only adapater is the `RemoteConfig::Adapters::RubyConfigAdapter`, which sources from a local YML file using the [Config](https://github.com/rubyconfig/config) gem.
|
85
|
+
|
86
|
+
By default the feature flagging looks for values under under `features` and release flagging looks for values under `releases`.
|
87
|
+
|
88
|
+
If you want to nest a flag under another, for example, you have a `coffee_ordering` release flag and you want to add a `coffee_ordernig.pre_pay` release flag. Then you can nest the new flag under the old one and add a `_` key underneath it for it's own value, e.g:
|
89
|
+
|
90
|
+
```yml
|
91
|
+
releases:
|
92
|
+
coffee_ordering:
|
93
|
+
_: uat
|
94
|
+
pre_pay: development
|
95
|
+
|
96
|
+
```
|
97
|
+
|
98
|
+
An example `app/config/settings.yml` might look like:
|
99
|
+
|
100
|
+
```yml
|
101
|
+
releases:
|
102
|
+
loyalty: uat
|
103
|
+
coffee_ordering:
|
104
|
+
_: production
|
105
|
+
pre_pay: production
|
106
|
+
v2:
|
107
|
+
_: uat
|
108
|
+
pre_pay: development
|
109
|
+
v3:
|
110
|
+
_: development
|
111
|
+
|
112
|
+
features:
|
113
|
+
pay_in_car: true
|
114
|
+
```
|
115
|
+
|
116
|
+
NOTE: it may be useful to split out your releases and features YML into different files and load them in.
|
117
|
+
|
118
|
+
`app/config/releases.yml`
|
119
|
+
`app/config/features.yml`
|
120
|
+
|
121
|
+
TODO: provide ruby snippet of how to set this up in the initializers
|
122
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
|
3
|
+
APP_RAKEFILE = File.expand_path("spec/rails_app/Rakefile", __dir__)
|
4
|
+
load "rails/tasks/engine.rake"
|
5
|
+
|
6
|
+
load "rails/tasks/statistics.rake"
|
7
|
+
|
8
|
+
require "bundler/gem_tasks"
|
9
|
+
require_relative "./lib/remote_config/version"
|
10
|
+
|
11
|
+
task :publish do
|
12
|
+
if ENV["GITHUB_REF"] == "refs/tags/v#{RemoteConfig::VERSION}"
|
13
|
+
puts "Release ref \"#{ENV["GITHUB_REF"]}\" matches gem version \"#{RemoteConfig::VERSION}\""
|
14
|
+
|
15
|
+
sh "gem build"
|
16
|
+
sh "ls *.gem | xargs gem push"
|
17
|
+
|
18
|
+
puts "Bult and pushed version #{RemoteConfig::VERSION} to rubygems"
|
19
|
+
exit 0
|
20
|
+
else
|
21
|
+
puts "Release ref \"#{ENV["GITHUB_REF"]}\" does not match gem version \"#{RemoteConfig::VERSION}\""
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
end
|
data/bin/rails
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails gems
|
3
|
+
# installed from the root of your application.
|
4
|
+
|
5
|
+
ENGINE_ROOT = File.expand_path("..", __dir__)
|
6
|
+
ENGINE_PATH = File.expand_path("../lib/remote-config/engine", __dir__)
|
7
|
+
APP_PATH = File.expand_path("../spec/rails_app/config/application", __dir__)
|
8
|
+
|
9
|
+
# Set up gems listed in the Gemfile.
|
10
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
11
|
+
require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
|
12
|
+
|
13
|
+
require "rails/all"
|
14
|
+
require "rails/engine/commands"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RemoteConfig
|
4
|
+
module Adapters
|
5
|
+
# Adapters are the interface for fetching the feature and release flags from
|
6
|
+
# varying sources.
|
7
|
+
class Base
|
8
|
+
attr_reader :options
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def fetch_feature_flag(key)
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
def fetch_release_flag(key)
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RemoteConfig
|
4
|
+
module Adapters
|
5
|
+
# Adapter for fetching feature and release flags from a set up config using
|
6
|
+
# the Config gem (see https://github.com/rubyconfig/config).
|
7
|
+
class RubyConfigAdapter < Base
|
8
|
+
def fetch_feature_flag(key)
|
9
|
+
fetch_flag(options[:feature_flags_key], key)
|
10
|
+
end
|
11
|
+
|
12
|
+
def fetch_release_flag(key)
|
13
|
+
fetch_flag(options[:release_flags_key], key)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def fetch_flag(root_key, key)
|
19
|
+
value = config_class.dig(root_key, *key.split("."))
|
20
|
+
return value._ if value.is_a? Config::Options
|
21
|
+
|
22
|
+
value
|
23
|
+
rescue TypeError
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def config_class
|
28
|
+
options[:const_name].constantize
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Style/Documentation
|
4
|
+
module RemoteConfig
|
5
|
+
class FlagError < StandardError
|
6
|
+
attr_reader :key
|
7
|
+
|
8
|
+
def initialize(key)
|
9
|
+
@key = key
|
10
|
+
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class UnknownFeatureFlagError < FlagError
|
16
|
+
def message
|
17
|
+
"Unknown feature flag: #{key}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class NonBooleanFeatureFlagError < FlagError
|
22
|
+
def message
|
23
|
+
"Non-boolean feature flag: #{key}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class UnknownReleaseFlagError < FlagError
|
28
|
+
def message
|
29
|
+
"Unknown release flag: #{key}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class UnknownReleaseStageError < FlagError
|
34
|
+
attr_reader :value
|
35
|
+
|
36
|
+
def initialize(key, value)
|
37
|
+
@value = value
|
38
|
+
|
39
|
+
super(key)
|
40
|
+
end
|
41
|
+
|
42
|
+
def message
|
43
|
+
"Unknown release stage \"#{value}\" for release flag: #{key}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
# rubocop:enable Style/Documentation
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RemoteConfig
|
4
|
+
# Module to be included into the using application to allow for checking
|
5
|
+
# for feature and release flags.
|
6
|
+
module Flagging
|
7
|
+
def feature_enabled?(key)
|
8
|
+
enabled = RemoteConfig.adapter.fetch_feature_flag(key)
|
9
|
+
raise RemoteConfig::UnknownFeatureFlagError, key if enabled.nil?
|
10
|
+
raise RemoteConfig::NonBooleanFeatureFlagError, key unless enabled.in? [true, false]
|
11
|
+
|
12
|
+
yield if block_given? && enabled
|
13
|
+
|
14
|
+
enabled
|
15
|
+
end
|
16
|
+
|
17
|
+
# rubocop:disable Metrics/AbcSize
|
18
|
+
def released?(key)
|
19
|
+
release_stage = RemoteConfig.adapter.fetch_release_flag(key)
|
20
|
+
raise RemoteConfig::UnknownReleaseFlagError, key if release_stage.nil?
|
21
|
+
|
22
|
+
release_stages_envs = RemoteConfig.configuration.release_stages[release_stage.to_sym]
|
23
|
+
raise RemoteConfig::UnknownReleaseStageError.new(key, release_stage) if release_stages_envs.nil?
|
24
|
+
|
25
|
+
is_released = release_stages_envs.map(&:to_s).include? Rails.env
|
26
|
+
|
27
|
+
yield if block_given? && is_released
|
28
|
+
|
29
|
+
is_released
|
30
|
+
end
|
31
|
+
# rubocop:enable Metrics/AbcSize
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "remote_config/version"
|
4
|
+
require "remote_config/engine"
|
5
|
+
require "remote_config/flagging"
|
6
|
+
require "remote_config/exceptions"
|
7
|
+
require "remote_config/adapters/base"
|
8
|
+
require "remote_config/adapters/ruby_config_adapter"
|
9
|
+
|
10
|
+
# Root gem module containing config and adapter setup.
|
11
|
+
module RemoteConfig
|
12
|
+
Configuration = Struct.new(
|
13
|
+
# The adapter to be used for fetching the flags.
|
14
|
+
:adapter,
|
15
|
+
# The options hash to be passed to the adapter at initialization.
|
16
|
+
:adapter_options,
|
17
|
+
# An hash of release stages to an array of rails environments that will have
|
18
|
+
# the it will release to.
|
19
|
+
:release_stages,
|
20
|
+
keyword_init: true
|
21
|
+
)
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def configure
|
25
|
+
yield configuration
|
26
|
+
end
|
27
|
+
|
28
|
+
def configuration
|
29
|
+
@configuration ||= Configuration.new(
|
30
|
+
adapter: Adapters::RubyConfigAdapter,
|
31
|
+
adapter_options: {
|
32
|
+
const_name: "Settings",
|
33
|
+
feature_flags_key: "feature_flags",
|
34
|
+
release_flags_key: "release_flags"
|
35
|
+
},
|
36
|
+
|
37
|
+
release_stages: {
|
38
|
+
production: %i[production development],
|
39
|
+
development: %i[development]
|
40
|
+
}
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def adapter
|
45
|
+
@adapter ||= configuration.adapter.new(configuration.adapter_options)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
require "remote_config/rails/routes" if defined? ::Rails
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "remote_config/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "remote_config"
|
9
|
+
spec.version = RemoteConfig::VERSION
|
10
|
+
spec.authors = ["Montgomery Anderson"]
|
11
|
+
spec.email = "montgomery.c.anderson@gmail.com"
|
12
|
+
|
13
|
+
spec.summary = "Remote Config for Ruby on Rails"
|
14
|
+
spec.description = "Remote Config for Ruby on Rails"
|
15
|
+
spec.homepage = "https://github.com/paperkite/rails-remote-config"
|
16
|
+
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
spec.required_ruby_version = ">= 2.5.0"
|
19
|
+
|
20
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
21
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
File without changes
|