qonfig 0.24.1 → 0.25.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +14 -13
- data/CHANGELOG.md +35 -1
- data/LICENSE.txt +1 -1
- data/README.md +98 -2
- data/Rakefile +0 -1
- data/gemfiles/with_external_deps.gemfile +2 -0
- data/lib/qonfig.rb +2 -0
- data/lib/qonfig/data_set.rb +3 -0
- data/lib/qonfig/plugins.rb +1 -0
- data/lib/qonfig/plugins/toml/commands/definition/expose_toml.rb +3 -3
- data/lib/qonfig/plugins/vault.rb +24 -0
- data/lib/qonfig/plugins/vault/commands/definition/expose_vault.rb +142 -0
- data/lib/qonfig/plugins/vault/commands/definition/load_from_vault.rb +53 -0
- data/lib/qonfig/plugins/vault/dsl.rb +35 -0
- data/lib/qonfig/plugins/vault/errors.rb +9 -0
- data/lib/qonfig/plugins/vault/loaders/vault.rb +73 -0
- data/lib/qonfig/settings.rb +64 -20
- data/lib/qonfig/settings/key_matcher.rb +2 -0
- data/lib/qonfig/version.rb +1 -1
- data/qonfig.gemspec +3 -3
- metadata +13 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b875f81a892a041c391457b18989daa2626ce3b04afb3e0290314a0fafeb8ad
|
4
|
+
data.tar.gz: f7eb3ff0d6801364070e22a8560fdfcc10e08bec59d8e876834b800682832394
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0ea42e1bcaed282dee699f798eb8b21e188afb2f37720b9645c97dc9a791596604f65de2d81b34e83102a8f94a5a5fbb7892bd20184c0141884e3e4ac86a024
|
7
|
+
data.tar.gz: 6657ab2f25a10c86bda9c87cb32ccaa494fd831f1d237bd30f561f7c8e14da50e173de18ec2cca3a400d16769f8001397160b4ef33a9154da599d69317385ef9
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -1,17 +1,22 @@
|
|
1
1
|
language: ruby
|
2
|
-
|
2
|
+
os: linux
|
3
|
+
dist: xenial
|
4
|
+
cache: bundler
|
5
|
+
before_install: gem install bundler
|
6
|
+
script: bundle exec rspec
|
7
|
+
jobs:
|
3
8
|
fast_finish: true
|
4
9
|
include:
|
5
|
-
- rvm: 2.4.
|
10
|
+
- rvm: 2.4.10
|
6
11
|
gemfile: gemfiles/with_external_deps.gemfile
|
7
12
|
env: TEST_PLUGINS=true FULL_TEST_COVERAGE_CHECK=true
|
8
|
-
- rvm: 2.5.
|
13
|
+
- rvm: 2.5.8
|
9
14
|
gemfile: gemfiles/with_external_deps.gemfile
|
10
15
|
env: TEST_PLUGINS=true FULL_TEST_COVERAGE_CHECK=true
|
11
|
-
- rvm: 2.6.
|
16
|
+
- rvm: 2.6.6
|
12
17
|
gemfile: gemfiles/with_external_deps.gemfile
|
13
18
|
env: TEST_PLUGINS=true FULL_TEST_COVERAGE_CHECK=true
|
14
|
-
- rvm: 2.7.
|
19
|
+
- rvm: 2.7.1
|
15
20
|
gemfile: gemfiles/with_external_deps.gemfile
|
16
21
|
env: TEST_PLUGINS=true FULL_TEST_COVERAGE_CHECK=true
|
17
22
|
- rvm: ruby-head
|
@@ -23,13 +28,13 @@ matrix:
|
|
23
28
|
- rvm: truffleruby
|
24
29
|
gemfile: gemfiles/with_external_deps.gemfile
|
25
30
|
env: TEST_PLUGINS=true FULL_TEST_COVERAGE_CHECK=true
|
26
|
-
- rvm: 2.4.
|
31
|
+
- rvm: 2.4.10
|
27
32
|
gemfile: gemfiles/without_external_deps.gemfile
|
28
|
-
- rvm: 2.5.
|
33
|
+
- rvm: 2.5.8
|
29
34
|
gemfile: gemfiles/without_external_deps.gemfile
|
30
|
-
- rvm: 2.6.
|
35
|
+
- rvm: 2.6.6
|
31
36
|
gemfile: gemfiles/without_external_deps.gemfile
|
32
|
-
- rvm: 2.7.
|
37
|
+
- rvm: 2.7.1
|
33
38
|
gemfile: gemfiles/without_external_deps.gemfile
|
34
39
|
- rvm: ruby-head
|
35
40
|
gemfile: gemfiles/without_external_deps.gemfile
|
@@ -41,7 +46,3 @@ matrix:
|
|
41
46
|
- rvm: ruby-head
|
42
47
|
- rvm: jruby-head
|
43
48
|
- rvm: truffleruby
|
44
|
-
sudo: false
|
45
|
-
cache: bundler
|
46
|
-
before_install: gem install bundler
|
47
|
-
script: bundle exec rspec
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,40 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [0.25.0] - 2020-09-15
|
5
|
+
### Added
|
6
|
+
- Support for **Vault** config provider:
|
7
|
+
- realized as a plugin (`Qonfig.plugin(:vault)`);
|
8
|
+
- provides `#load_from_vault`, `#expose_vault` methods and works in `#*_yaml`-like manner);
|
9
|
+
- depends on `gem vault (>= 0.1)`
|
10
|
+
- `Qonfig::Settings#[]` behave like `Qonfig::Settings#__dig__`;
|
11
|
+
- An ability to represent the config hash in dot-notated style (all config keys are represented in dot-notated format):
|
12
|
+
- works via `#to_h(dot_style: true)`;
|
13
|
+
- `key_transformer:` and `value_transfomer:` options are supported too;
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
class Config << Qonfig::DataSet
|
17
|
+
setting :database do
|
18
|
+
setting :host, 'localhost'
|
19
|
+
setting :port, 6432
|
20
|
+
end
|
21
|
+
|
22
|
+
setting :api do
|
23
|
+
setting :rest_enabled, true
|
24
|
+
setting :rpc_enabled, false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Config.new.to_h(dot_style: true)
|
29
|
+
# =>
|
30
|
+
{
|
31
|
+
'database.host' => 'localhost',
|
32
|
+
'database.port' => 6432,
|
33
|
+
'api.rest_enabled' => true,
|
34
|
+
'api.rpc_enabled' => false,
|
35
|
+
}
|
36
|
+
```
|
37
|
+
|
4
38
|
## [0.24.1] - 2020-03-10
|
5
39
|
### Changed
|
6
40
|
- Enhanced dot-notated key resolving algorithm: now it goes through the all dot-notated key parts
|
@@ -9,7 +43,7 @@ All notable changes to this project will be documented in this file.
|
|
9
43
|
### Fixed
|
10
44
|
- (**Pretty-Print Plugin**):
|
11
45
|
- dot-noted setting keys can not be pretty-printed (they raise `Qonfig::UnknownSettingKeyError`);
|
12
|
-
- added `set` and `pp`
|
46
|
+
- added `set` and `pp` as preloaded dependencies;
|
13
47
|
|
14
48
|
## [0.24.0] - 2019-12-29
|
15
49
|
### Added
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2018-
|
3
|
+
Copyright (c) 2018-2020 Rustam Ibragimov
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -40,6 +40,9 @@ require 'qonfig'
|
|
40
40
|
- [Inheritance](#inheritance)
|
41
41
|
- [Composition](#composition)
|
42
42
|
- [Hash representation](#hash-representation)
|
43
|
+
- [Default behaviour (without options)](#default-behavior-without-options)
|
44
|
+
- [With transformations](#with-transformations)
|
45
|
+
- [Dot-style format](#dot-style-format)
|
43
46
|
- [Smart Mixin](#smart-mixin) (`Qonfig::Configurable`)
|
44
47
|
- [Instantiation without class definition](#instantiation-without-class-definition) (`Qonfig::DataSet.build(&definitions)`)
|
45
48
|
- [Compacted config](#compacted-config)
|
@@ -102,6 +105,7 @@ require 'qonfig'
|
|
102
105
|
- [Plugins](#plugins)
|
103
106
|
- [toml](#plugins-toml) (support for `TOML` format)
|
104
107
|
- [pretty_print](#plugins-pretty_print) (beautified/prettified console output)
|
108
|
+
- [vault](#plugins-vault) (support for `Vault` store)
|
105
109
|
- [Roadmap](#roadmap)
|
106
110
|
- [Build](#build)
|
107
111
|
---
|
@@ -188,6 +192,10 @@ config.settings['vendor_api']['domain'] # => 'app.service.com'
|
|
188
192
|
config.settings['vendor_api']['login'] # => 'test_user'
|
189
193
|
config.settings['enable_graphql'] # => false
|
190
194
|
|
195
|
+
# dig to value
|
196
|
+
config.settings[:vendor_api, :domain] # => 'app.service.com'
|
197
|
+
config.settings[:vendor_api, 'login'] # => 'test_user'
|
198
|
+
|
191
199
|
# get option value directly via index (with indifferent access)
|
192
200
|
config['project_id'] # => nil
|
193
201
|
config['enable_graphql'] # => false
|
@@ -271,7 +279,7 @@ config.slice_value('vendor_api.port') # => Qonfig::UnknownSettingError # (key do
|
|
271
279
|
# - get a subset (a set of sets) of config settings represented as a hash;
|
272
280
|
# - each key (or key set) represents a requirement of a certain setting key;
|
273
281
|
|
274
|
-
config.
|
282
|
+
config.subset(:vendor_api, :enable_graphql)
|
275
283
|
# => { 'vendor_api' => { 'login' => ..., 'domain' => ... }, 'enable_graphql' => false }
|
276
284
|
|
277
285
|
config.subset(:project_id, [:vendor_api, :domain], [:credentials, :user, :login])
|
@@ -436,6 +444,12 @@ project_config.settings.db.password # => 'testpaswd'
|
|
436
444
|
|
437
445
|
### Hash representation
|
438
446
|
|
447
|
+
- works via `#to_h` and `#to_hash`;
|
448
|
+
- supported options:
|
449
|
+
- `key_transformer:` - an optional proc that accepts setting key and makes your custom transformations;
|
450
|
+
- `value_transformer:` - an optional proc that accepts setting value and makes your custom transformations;
|
451
|
+
- `dot_style:` - (`false` by default) represent setting keys in dot-notation (transformations are supported too);
|
452
|
+
|
439
453
|
```ruby
|
440
454
|
class Config < Qonfig::DataSet
|
441
455
|
setting :serializers do
|
@@ -454,9 +468,13 @@ class Config < Qonfig::DataSet
|
|
454
468
|
|
455
469
|
setting :logger, Logger.new(STDOUT)
|
456
470
|
end
|
471
|
+
```
|
457
472
|
|
458
|
-
|
473
|
+
#### Default behavior (without-options)
|
459
474
|
|
475
|
+
```ruby
|
476
|
+
Config.new.to_h
|
477
|
+
# =>
|
460
478
|
{
|
461
479
|
"serializers": {
|
462
480
|
"json" => { "engine" => :ok },
|
@@ -467,6 +485,55 @@ Config.new.to_h
|
|
467
485
|
}
|
468
486
|
```
|
469
487
|
|
488
|
+
#### With transformations
|
489
|
+
|
490
|
+
- with `key_transformer` and/or `value_transformer`;
|
491
|
+
|
492
|
+
```ruby
|
493
|
+
key_transformer = -> (key) { "#{key}!!" }
|
494
|
+
value_transformer = -> (value) { "#{value}??" }
|
495
|
+
|
496
|
+
Config.new.to_h(key_transformer: key_transformer, value_transformer: value_transformer)
|
497
|
+
# =>
|
498
|
+
{
|
499
|
+
"serializers!!": {
|
500
|
+
"json!!" => { "engine!!" => "ok??" },
|
501
|
+
"hash!!" => { "engine!!" => "native??" },
|
502
|
+
},
|
503
|
+
"adapter!!" => { "default!!" => "memory_sync??" },
|
504
|
+
"logger!!" => "#<Logger:0x00007fcde799f158>??"
|
505
|
+
}
|
506
|
+
```
|
507
|
+
|
508
|
+
#### Dot-style format
|
509
|
+
|
510
|
+
- transformations are supported too (`key_transformer` and `value_transformer`);
|
511
|
+
|
512
|
+
```ruby
|
513
|
+
Config.new.to_h(dot_style: true)
|
514
|
+
# =>
|
515
|
+
{
|
516
|
+
"serializers.json.engine" => :ok,
|
517
|
+
"serializers.hash.engine" => :native,
|
518
|
+
"adapter.default" => :memory_sync,
|
519
|
+
"logger" => #<Logger:0x4b0d79fc>,
|
520
|
+
}
|
521
|
+
```
|
522
|
+
|
523
|
+
```ruby
|
524
|
+
transformer = -> (value) { "$$#{value}$$" }
|
525
|
+
|
526
|
+
Config.new.to_h(dot_style: true, key_transformer: transformer, value_transformer: transformer)
|
527
|
+
|
528
|
+
# => "#<Logger:0x00007fcde799f158>??"
|
529
|
+
{
|
530
|
+
"$$serializers.json.engine$$" => "$$ok$$",
|
531
|
+
"$$serializers.hash.engine$$" => "$$native$$",
|
532
|
+
"$$adapter.default$$" => "$$memory_sync$$",
|
533
|
+
"$$logger$$" => "$$#<Logger:0x00007fcde799f158>$$",
|
534
|
+
}
|
535
|
+
```
|
536
|
+
|
470
537
|
---
|
471
538
|
|
472
539
|
### Smart Mixin
|
@@ -3091,6 +3158,7 @@ dynamic: 10
|
|
3091
3158
|
|
3092
3159
|
- [toml](#plugins-toml) (provides `load_from_toml`, `save_to_toml`, `expose_toml`);
|
3093
3160
|
- [pretty_print](#plugins-pretty_print) (beautified/prettified console output);
|
3161
|
+
- [vault](#plugins-vault) (provides `load_from_vault`, `expose_vault`)
|
3094
3162
|
|
3095
3163
|
---
|
3096
3164
|
|
@@ -3214,6 +3282,31 @@ config = Config.new
|
|
3214
3282
|
|
3215
3283
|
---
|
3216
3284
|
|
3285
|
+
### Plugins: vault
|
3286
|
+
|
3287
|
+
- `Qonfig.plugin(:vault)`
|
3288
|
+
- adds support for `vault kv store`, [more info](https://www.vaultproject.io/docs/secrets/kv/kv-v2)
|
3289
|
+
- depends on `vault` gem ([link](https://github.com/hashicorp/vault-ruby)) (tested on `>= 0.1`);
|
3290
|
+
- provides `.load_from_vault` (works in `.load_from_yaml` manner ([doc](#load-from-yaml-file)));
|
3291
|
+
- provides `.expose_vault` (works in `.expose_yaml` manner ([doc](#expose-yaml)));
|
3292
|
+
|
3293
|
+
```ruby
|
3294
|
+
# 1) require external dependency
|
3295
|
+
require 'vault'
|
3296
|
+
|
3297
|
+
# 2) Setup vault client
|
3298
|
+
|
3299
|
+
Vault.address = 'http://localhost:8200'
|
3300
|
+
Vault.token = 'super-duper-token-here'
|
3301
|
+
|
3302
|
+
# 3) enable plugin
|
3303
|
+
Qonfig.plugin(:vault)
|
3304
|
+
|
3305
|
+
# 3) use vault :)
|
3306
|
+
```
|
3307
|
+
|
3308
|
+
---
|
3309
|
+
|
3217
3310
|
## Roadmap
|
3218
3311
|
|
3219
3312
|
- **Major**:
|
@@ -3223,7 +3316,10 @@ config = Config.new
|
|
3223
3316
|
- support for pattern matching;
|
3224
3317
|
- **Minor**:
|
3225
3318
|
- An ability to flag `Qonfig::Configurable`'s config object as `compacted` (`Qonfig::Compacted`);
|
3319
|
+
- Instance-based behavior for `Vault` plugin, also use instance of `Vault` client instead of `Singleton`;
|
3226
3320
|
- External validation class with an importing api for better custom validations;
|
3321
|
+
- Setting value changement trace (in `anyway_config` manner);
|
3322
|
+
- Instantiation and reloading callbacks;
|
3227
3323
|
|
3228
3324
|
## Build
|
3229
3325
|
|
data/Rakefile
CHANGED
data/lib/qonfig.rb
CHANGED
data/lib/qonfig/data_set.rb
CHANGED
@@ -184,6 +184,7 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
|
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
187
|
+
# @option dot_style [Boolean]
|
187
188
|
# @option key_transformer [Proc]
|
188
189
|
# @option value_transformer [Proc]
|
189
190
|
# @return [Hash]
|
@@ -191,11 +192,13 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
|
|
191
192
|
# @api public
|
192
193
|
# @since 0.1.0
|
193
194
|
def to_h(
|
195
|
+
dot_style: Qonfig::Settings::REPRESENT_HASH_IN_DOT_STYLE,
|
194
196
|
key_transformer: Qonfig::Settings::BASIC_SETTING_KEY_TRANSFORMER,
|
195
197
|
value_transformer: Qonfig::Settings::BASIC_SETTING_VALUE_TRANSFORMER
|
196
198
|
)
|
197
199
|
thread_safe_access do
|
198
200
|
settings.__to_hash__(
|
201
|
+
dot_notation: dot_style,
|
199
202
|
transform_key: key_transformer,
|
200
203
|
transform_value: value_transformer
|
201
204
|
)
|
data/lib/qonfig/plugins.rb
CHANGED
@@ -101,7 +101,7 @@ class Qonfig::Commands::Definition::ExposeTOML < Qonfig::Commands::Base
|
|
101
101
|
realfile = dirname.join(envfile).to_s
|
102
102
|
|
103
103
|
toml_data = load_toml_data(realfile)
|
104
|
-
toml_based_settings =
|
104
|
+
toml_based_settings = build_data_set_klass(toml_data).new.settings
|
105
105
|
|
106
106
|
settings.__append_settings__(toml_based_settings)
|
107
107
|
end
|
@@ -125,7 +125,7 @@ class Qonfig::Commands::Definition::ExposeTOML < Qonfig::Commands::Base
|
|
125
125
|
"#{file_path} file does not contain settings with <#{env}> environment key!"
|
126
126
|
) unless toml_data_slice
|
127
127
|
|
128
|
-
toml_based_settings =
|
128
|
+
toml_based_settings = build_data_set_klass(toml_data_slice).new.settings
|
129
129
|
|
130
130
|
settings.__append_settings__(toml_based_settings)
|
131
131
|
end
|
@@ -145,7 +145,7 @@ class Qonfig::Commands::Definition::ExposeTOML < Qonfig::Commands::Base
|
|
145
145
|
#
|
146
146
|
# @api private
|
147
147
|
# @since 0.12.0
|
148
|
-
def
|
148
|
+
def build_data_set_klass(toml_data)
|
149
149
|
Qonfig::DataSet::ClassBuilder.build_from_hash(toml_data)
|
150
150
|
end
|
151
151
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.25.0
|
5
|
+
class Qonfig::Plugins::Vault < Qonfig::Plugins::Abstract
|
6
|
+
class << self
|
7
|
+
# @return [void]
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
# @since 0.25.0
|
11
|
+
def install!
|
12
|
+
raise(
|
13
|
+
Qonfig::UnresolvedPluginDependencyError,
|
14
|
+
'::Vault does not exist or "vault" gem is not loaded'
|
15
|
+
) unless const_defined?('::Vault')
|
16
|
+
|
17
|
+
require_relative 'vault/errors'
|
18
|
+
require_relative 'vault/loaders/vault'
|
19
|
+
require_relative 'vault/commands/definition/load_from_vault'
|
20
|
+
require_relative 'vault/commands/definition/expose_vault'
|
21
|
+
require_relative 'vault/dsl'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.25.0
|
5
|
+
class Qonfig::Commands::Definition::ExposeVault < Qonfig::Commands::Base
|
6
|
+
# @since 0.25.0
|
7
|
+
self.inheritable = true
|
8
|
+
|
9
|
+
# @return [Hash<Symbol,Symbol>]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 0.25.0
|
13
|
+
EXPOSERS = { path: :path, env_key: :env_key }.freeze
|
14
|
+
|
15
|
+
# @return [Hash]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
# @since 0.25.0
|
19
|
+
EMPTY_VAULT_DATA = {}.freeze
|
20
|
+
|
21
|
+
# @return [String, Pathname]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
# @since 0.25.0
|
25
|
+
attr_reader :path
|
26
|
+
|
27
|
+
# @return [Boolean]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
# @since 0.25.0
|
31
|
+
attr_reader :strict
|
32
|
+
|
33
|
+
# @return [Symbol]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
# @since 0.25.0
|
37
|
+
attr_reader :via
|
38
|
+
|
39
|
+
# @return [Symbol, String]
|
40
|
+
#
|
41
|
+
# @api private
|
42
|
+
# @since 0.25.0
|
43
|
+
attr_reader :env
|
44
|
+
|
45
|
+
# @param path [String Pathname]
|
46
|
+
# @option strict [Boolean]
|
47
|
+
# @option via [Symbol]
|
48
|
+
# @option env [String, Symbol]
|
49
|
+
# @return [void]
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
# @since 0.25.0
|
53
|
+
def initialize(path, strict: true, via:, env:)
|
54
|
+
unless env.is_a?(Symbol) || env.is_a?(String) || env.is_a?(Numeric)
|
55
|
+
raise Qonfig::ArgumentError, ':env should be a string or a symbol'
|
56
|
+
end
|
57
|
+
|
58
|
+
raise Qonfig::ArgumentError, ':env should be provided' if env.to_s.empty?
|
59
|
+
raise Qonfig::ArgumentError, 'used :via is unsupported' unless EXPOSERS.key?(via)
|
60
|
+
|
61
|
+
@path = path
|
62
|
+
@strict = strict
|
63
|
+
@via = via
|
64
|
+
@env = env
|
65
|
+
end
|
66
|
+
|
67
|
+
# @param data_set [Qonfig::DataSet]
|
68
|
+
# @param settings [Qonfig::Settings]
|
69
|
+
# @return [void]
|
70
|
+
#
|
71
|
+
# @api private
|
72
|
+
# @since 0.25.0
|
73
|
+
def call(_data_set, settings)
|
74
|
+
case via
|
75
|
+
when EXPOSERS[:path]
|
76
|
+
expose_path!(settings)
|
77
|
+
when EXPOSERS[:env_key]
|
78
|
+
expose_env_key!(settings)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# @param settings [Qonfig::Settings]
|
85
|
+
# @return [void]
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
# @since 0.25.0
|
89
|
+
def expose_path!(settings)
|
90
|
+
# NOTE: transform path (insert environment name into a secret name)
|
91
|
+
# from: kv/data/secret_name
|
92
|
+
# to: kv/data/env_name/secret_name
|
93
|
+
|
94
|
+
splitted_path = path.split('/')
|
95
|
+
real_path = splitted_path.insert(-2, env.to_s).join('/')
|
96
|
+
|
97
|
+
vault_data = load_vault_data(real_path)
|
98
|
+
vault_based_settings = build_data_set_class(vault_data).new.settings
|
99
|
+
|
100
|
+
settings.__append_settings__(vault_based_settings)
|
101
|
+
end
|
102
|
+
|
103
|
+
# @param settings [Qonfig::Settings]
|
104
|
+
# @return [void]
|
105
|
+
#
|
106
|
+
# @raise [Qonfig::ExposeError]
|
107
|
+
#
|
108
|
+
# @api private
|
109
|
+
# @since 0.25.0
|
110
|
+
def expose_env_key!(settings)
|
111
|
+
vault_data = load_vault_data(path)
|
112
|
+
vault_data_slice = vault_data[env.to_sym]
|
113
|
+
vault_data_slice = EMPTY_VAULT_DATA.dup if vault_data_slice.nil? && !strict
|
114
|
+
|
115
|
+
raise(
|
116
|
+
Qonfig::ExposeError,
|
117
|
+
"#{path} does not contain settings with <#{env}> environment key!"
|
118
|
+
) unless vault_data_slice
|
119
|
+
|
120
|
+
vault_based_settings = build_data_set_class(vault_data_slice).new.settings
|
121
|
+
|
122
|
+
settings.__append_settings__(vault_based_settings)
|
123
|
+
end
|
124
|
+
|
125
|
+
# @param path [String]
|
126
|
+
# @return [Hash]
|
127
|
+
#
|
128
|
+
# @api private
|
129
|
+
# @since 0.25.0
|
130
|
+
def load_vault_data(path)
|
131
|
+
Qonfig::Loaders::Vault.load_file(path, fail_on_unexist: strict)
|
132
|
+
end
|
133
|
+
|
134
|
+
# @param vault_data [Hash]
|
135
|
+
# @return [Class<Qonfig::DataSet>]
|
136
|
+
#
|
137
|
+
# @api private
|
138
|
+
# @since 0.25.0
|
139
|
+
def build_data_set_class(vault_data)
|
140
|
+
Qonfig::DataSet::ClassBuilder.build_from_hash(vault_data)
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.25.0
|
5
|
+
class Qonfig::Commands::Definition::LoadFromVault < Qonfig::Commands::Base
|
6
|
+
# @since 0.25.0
|
7
|
+
self.inheritable = true
|
8
|
+
|
9
|
+
# @return [String, Pathname]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 0.25.0
|
13
|
+
attr_reader :path
|
14
|
+
|
15
|
+
# @return [Boolean]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
# @since 0.25.0
|
19
|
+
attr_reader :strict
|
20
|
+
|
21
|
+
# @param path [String]
|
22
|
+
# @option strict [Boolean]
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
# @since 0.25.0
|
26
|
+
def initialize(path, strict: true)
|
27
|
+
@path = path
|
28
|
+
@strict = strict
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param data_set [Qonfig::DataSet]
|
32
|
+
# @param settings [Qonfig::Settings]
|
33
|
+
# @return [void]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
# @since 0.25.0
|
37
|
+
def call(_data_set, settings)
|
38
|
+
vault_data = Qonfig::Loaders::Vault.load_file(path, fail_on_unexist: strict)
|
39
|
+
vault_based_settings = build_data_set_klass(vault_data).new.settings
|
40
|
+
settings.__append_settings__(vault_based_settings)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# @param toml_data [Hash]
|
46
|
+
# @return [Class<Qonfig::DataSet>]
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
# @since 0.25.0
|
50
|
+
def build_data_set_klass(toml_data)
|
51
|
+
Qonfig::DataSet::ClassBuilder.build_from_hash(toml_data)
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.25.0
|
5
|
+
module Qonfig::DSL
|
6
|
+
# @param path [String, Pathname]
|
7
|
+
# @option strict [Boolean]
|
8
|
+
# @return [void]
|
9
|
+
#
|
10
|
+
# @see Qonfig::Commands::Definition::LoadFromVault
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
# @since 0.25.0
|
14
|
+
def load_from_vault(path, strict: true)
|
15
|
+
definition_commands << Qonfig::Commands::Definition::LoadFromVault.new(
|
16
|
+
path, strict: strict
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param path [String, Pathname]
|
21
|
+
# @option strict [Boolean]
|
22
|
+
# @option via [Symbol]
|
23
|
+
# @option env [Symbol, String]
|
24
|
+
# @return [void]
|
25
|
+
#
|
26
|
+
# @see Qonfig::Commands::Definition::ExposeVault
|
27
|
+
#
|
28
|
+
# @api public
|
29
|
+
# @since 0.25.0
|
30
|
+
def expose_vault(path, strict: true, via:, env:)
|
31
|
+
definition_commands << Qonfig::Commands::Definition::ExposeVault.new(
|
32
|
+
path, strict: strict, via: via, env: env
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.25.0
|
5
|
+
class Qonfig::Loaders::Vault < Qonfig::Loaders::Basic
|
6
|
+
# @return [Binding]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.25.0
|
10
|
+
VAULT_EXPR_EVAL_SCOPE = BasicObject.new.__binding__.tap do |binding|
|
11
|
+
Object.new.method(:freeze).unbind.bind(binding.receiver).call
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# @param path [String, Pathname]
|
16
|
+
# @option fail_on_unexist [Boolean]
|
17
|
+
# @return [Object]
|
18
|
+
#
|
19
|
+
# @raise [Qonfig::FileNotFoundError]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
# @since 0.25.0
|
23
|
+
def load_file(path, fail_on_unexist: true)
|
24
|
+
data = ::Vault.with_retries(Vault::HTTPError) do
|
25
|
+
::Vault.logical.read(path.to_s)&.data&.dig(:data)
|
26
|
+
end
|
27
|
+
raise Qonfig::FileNotFoundError, "Path #{path} not exist" if data.nil? && fail_on_unexist
|
28
|
+
result = data || empty_data
|
29
|
+
deep_transform_values(result)
|
30
|
+
rescue Vault::VaultError => error
|
31
|
+
raise(Qonfig::VaultLoaderError.new(error.message).tap do |exception|
|
32
|
+
exception.set_backtrace(error.backtrace)
|
33
|
+
end)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Hash]
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
# @since 0.25.0
|
40
|
+
def empty_data
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# @param vault_data [Hash<Object,Object>]
|
47
|
+
# @return [Object]
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
# @since 0.25.0
|
51
|
+
def deep_transform_values(vault_data)
|
52
|
+
return vault_data unless vault_data.is_a?(Hash)
|
53
|
+
|
54
|
+
vault_data.transform_values do |value|
|
55
|
+
next safely_evaluate(value) if value.is_a?(String)
|
56
|
+
|
57
|
+
deep_transform_values(value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param vault_expr [String]
|
62
|
+
# @return [Object]
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
# @since 0.25.0
|
66
|
+
def safely_evaluate(vault_expr)
|
67
|
+
parsed_expr = ::ERB.new(vault_expr).result
|
68
|
+
VAULT_EXPR_EVAL_SCOPE.eval(parsed_expr)
|
69
|
+
rescue StandardError, ScriptError
|
70
|
+
parsed_expr
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/qonfig/settings.rb
CHANGED
@@ -22,6 +22,12 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
22
22
|
# @since 0.11.0
|
23
23
|
BASIC_SETTING_VALUE_TRANSFORMER = (proc { |value| value }).freeze
|
24
24
|
|
25
|
+
# @return [Boolean]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
# @since 0.25.0
|
29
|
+
REPRESENT_HASH_IN_DOT_STYLE = false
|
30
|
+
|
25
31
|
# @return [String]
|
26
32
|
#
|
27
33
|
# @api private
|
@@ -133,16 +139,13 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
133
139
|
# @param key [Symbol, String]
|
134
140
|
# @return [Object]
|
135
141
|
#
|
142
|
+
# @raise [Qonfig::ArgumentError]
|
143
|
+
#
|
136
144
|
# @api public
|
137
145
|
# @since 0.1.0
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
__get_value__(key)
|
142
|
-
rescue Qonfig::UnknownSettingError
|
143
|
-
__deep_access__(*__parse_dot_notated_key__(key))
|
144
|
-
end
|
145
|
-
end
|
146
|
+
# @version 0.25.0
|
147
|
+
def [](*keys)
|
148
|
+
__dig__(*keys)
|
146
149
|
end
|
147
150
|
|
148
151
|
# @param key [String, Symbol]
|
@@ -211,27 +214,47 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
211
214
|
__lock__.thread_safe_access { __deep_subset__(*keys) }
|
212
215
|
end
|
213
216
|
|
217
|
+
# @option dot_notation [Boolean]
|
214
218
|
# @option transform_key [Proc]
|
215
219
|
# @option transform_value [Proc]
|
216
220
|
# @return [Hash]
|
217
221
|
#
|
218
222
|
# @api private
|
219
223
|
# @since 0.1.0
|
220
|
-
#
|
221
|
-
def __to_hash__(
|
224
|
+
# @version 0.25.0
|
225
|
+
def __to_hash__(
|
226
|
+
dot_notation: REPRESENT_HASH_IN_DOT_STYLE,
|
227
|
+
transform_key: BASIC_SETTING_KEY_TRANSFORMER,
|
228
|
+
transform_value: BASIC_SETTING_VALUE_TRANSFORMER
|
229
|
+
)
|
222
230
|
unless transform_key.is_a?(Proc)
|
223
|
-
::Kernel.raise(
|
231
|
+
::Kernel.raise(
|
232
|
+
Qonfig::IncorrectKeyTransformerError,
|
233
|
+
'Key transformer should be a type of proc'
|
234
|
+
)
|
224
235
|
end
|
225
236
|
|
226
237
|
unless transform_value.is_a?(Proc)
|
227
|
-
::Kernel.raise(
|
238
|
+
::Kernel.raise(
|
239
|
+
Qonfig::IncorrectValueTransformerError,
|
240
|
+
'Value transformer should be a type of proc'
|
241
|
+
)
|
228
242
|
end
|
229
243
|
|
230
244
|
__lock__.thread_safe_access do
|
231
|
-
|
245
|
+
if dot_notation
|
246
|
+
__build_dot_notated_hash_representation__(
|
247
|
+
transform_key: transform_key,
|
248
|
+
transform_value: transform_value
|
249
|
+
)
|
250
|
+
else
|
251
|
+
__build_basic_hash_representation__(
|
252
|
+
transform_key: transform_key,
|
253
|
+
transform_value: transform_value
|
254
|
+
)
|
255
|
+
end
|
232
256
|
end
|
233
257
|
end
|
234
|
-
# rubocop:enable Layout/LineLength
|
235
258
|
alias_method :__to_h__, :__to_hash__
|
236
259
|
|
237
260
|
# @option all_variants [Boolean]
|
@@ -496,7 +519,7 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
496
519
|
#
|
497
520
|
# @api private
|
498
521
|
# @since 0.21.0
|
499
|
-
# rubocop:disable Naming/RescuedExceptionsVariableName
|
522
|
+
# rubocop:disable Naming/RescuedExceptionsVariableName, Style/SlicingWithRange
|
500
523
|
def __assign_value__(key, value)
|
501
524
|
key = __indifferently_accessable_option_key__(key)
|
502
525
|
__set_value__(key, value)
|
@@ -515,7 +538,7 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
515
538
|
raise(initial_error)
|
516
539
|
end
|
517
540
|
end
|
518
|
-
# rubocop:enable Naming/RescuedExceptionsVariableName
|
541
|
+
# rubocop:enable Naming/RescuedExceptionsVariableName, Style/SlicingWithRange
|
519
542
|
|
520
543
|
# @param key [String, Symbol]
|
521
544
|
# @param value [Object]
|
@@ -558,7 +581,8 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
558
581
|
#
|
559
582
|
# @api private
|
560
583
|
# @since 0.2.0
|
561
|
-
|
584
|
+
# rubocop:disable Metrics/AbcSize, Style/SlicingWithRange
|
585
|
+
def __deep_access__(*keys)
|
562
586
|
::Kernel.raise(Qonfig::ArgumentError, 'Key list can not be empty') if keys.empty?
|
563
587
|
|
564
588
|
result = nil
|
@@ -588,6 +612,7 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
588
612
|
result.__dig__(*rest_keys)
|
589
613
|
end
|
590
614
|
end
|
615
|
+
# rubocop:enable Metrics/AbcSize, Style/SlicingWithRange
|
591
616
|
|
592
617
|
# @param keys [Array<Symbol, String>]
|
593
618
|
# @return [Hash]
|
@@ -680,14 +705,15 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
680
705
|
# @return [Hash]
|
681
706
|
#
|
682
707
|
# @api private
|
683
|
-
# @since 0.
|
684
|
-
|
708
|
+
# @since 0.25.0
|
709
|
+
# rubocop:disable Layout/LineLength
|
710
|
+
def __build_basic_hash_representation__(options_part = __options__, transform_key:, transform_value:)
|
685
711
|
options_part.each_with_object({}) do |(key, value), hash|
|
686
712
|
final_key = transform_key.call(key)
|
687
713
|
|
688
714
|
case
|
689
715
|
when value.is_a?(Hash)
|
690
|
-
hash[final_key] =
|
716
|
+
hash[final_key] = __build_basic_hash_representation__(
|
691
717
|
value,
|
692
718
|
transform_key: transform_key,
|
693
719
|
transform_value: transform_value
|
@@ -703,6 +729,24 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
703
729
|
end
|
704
730
|
end
|
705
731
|
end
|
732
|
+
# rubocop:enable Layout/LineLength
|
733
|
+
|
734
|
+
# @option transform_key [Proc]
|
735
|
+
# @option transform_value [Proc]
|
736
|
+
# @return [Hash]
|
737
|
+
#
|
738
|
+
# @api private
|
739
|
+
# @since 0.25.0
|
740
|
+
def __build_dot_notated_hash_representation__(transform_key:, transform_value:)
|
741
|
+
{}.tap do |hash|
|
742
|
+
__deep_each_key_value_pair__ do |setting_key, setting_value|
|
743
|
+
final_key = transform_key.call(setting_key)
|
744
|
+
final_value = transform_value.call(setting_value)
|
745
|
+
|
746
|
+
hash[final_key] = final_value
|
747
|
+
end
|
748
|
+
end
|
749
|
+
end
|
706
750
|
|
707
751
|
# @param key [Symbol, String]
|
708
752
|
# @return [void]
|
@@ -147,12 +147,14 @@ class Qonfig::Settings::KeyMatcher
|
|
147
147
|
#
|
148
148
|
# @api private
|
149
149
|
# @since 0.13.0
|
150
|
+
# rubocop:disable Style/SlicingWithRange
|
150
151
|
def strip_regexp_string(regexp_string, left: false, right: false)
|
151
152
|
pattern = regexp_string
|
152
153
|
pattern = pattern[2..-1] if left && pattern[0..1] == MATCHER_SCOPE_SPLITTER
|
153
154
|
pattern = pattern[0..-3] if right && pattern[-2..-1] == MATCHER_SCOPE_SPLITTER
|
154
155
|
pattern
|
155
156
|
end
|
157
|
+
# rubocop:enable Style/SlicingWithRange
|
156
158
|
|
157
159
|
# @param scope_pattern [String]
|
158
160
|
# @return [Regexp]
|
data/lib/qonfig/version.rb
CHANGED
data/qonfig.gemspec
CHANGED
@@ -6,7 +6,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
6
6
|
require 'qonfig/version'
|
7
7
|
|
8
8
|
Gem::Specification.new do |spec|
|
9
|
-
spec.required_ruby_version = '>= 2.4.
|
9
|
+
spec.required_ruby_version = '>= 2.4.10'
|
10
10
|
|
11
11
|
spec.name = 'qonfig'
|
12
12
|
spec.version = Qonfig::VERSION
|
@@ -29,9 +29,9 @@ Gem::Specification.new do |spec|
|
|
29
29
|
f.match(%r{^(test|spec|features)/})
|
30
30
|
end
|
31
31
|
|
32
|
-
spec.add_development_dependency 'simplecov', '~> 0.
|
32
|
+
spec.add_development_dependency 'simplecov', '~> 0.19'
|
33
33
|
spec.add_development_dependency 'rspec', '~> 3.9'
|
34
|
-
spec.add_development_dependency 'armitage-rubocop', '~> 0.
|
34
|
+
spec.add_development_dependency 'armitage-rubocop', '~> 0.89'
|
35
35
|
|
36
36
|
spec.add_development_dependency 'bundler'
|
37
37
|
spec.add_development_dependency 'rake', '>= 13'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qonfig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.25.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rustam Ibragimov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: simplecov
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.19'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.19'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0.
|
47
|
+
version: '0.89'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0.
|
54
|
+
version: '0.89'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,6 +184,12 @@ files:
|
|
184
184
|
- lib/qonfig/plugins/toml/loaders/toml.rb
|
185
185
|
- lib/qonfig/plugins/toml/tomlrb_fixes.rb
|
186
186
|
- lib/qonfig/plugins/toml/uploaders/toml.rb
|
187
|
+
- lib/qonfig/plugins/vault.rb
|
188
|
+
- lib/qonfig/plugins/vault/commands/definition/expose_vault.rb
|
189
|
+
- lib/qonfig/plugins/vault/commands/definition/load_from_vault.rb
|
190
|
+
- lib/qonfig/plugins/vault/dsl.rb
|
191
|
+
- lib/qonfig/plugins/vault/errors.rb
|
192
|
+
- lib/qonfig/plugins/vault/loaders/vault.rb
|
187
193
|
- lib/qonfig/settings.rb
|
188
194
|
- lib/qonfig/settings/builder.rb
|
189
195
|
- lib/qonfig/settings/callbacks.rb
|
@@ -225,7 +231,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
225
231
|
requirements:
|
226
232
|
- - ">="
|
227
233
|
- !ruby/object:Gem::Version
|
228
|
-
version: 2.4.
|
234
|
+
version: 2.4.10
|
229
235
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
230
236
|
requirements:
|
231
237
|
- - ">="
|