qonfig 0.24.1 → 0.25.0
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 +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
|
- - ">="
|