remote_config 1.0.0.pre.beta.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 +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
|