Skip to content

Commit 4eda783

Browse files
authored
Merge pull request #1103 from code0-tech/#845-seperate-config-per-env
added multiple config loader
2 parents 25d04a3 + 1ec5f64 commit 4eda783

3 files changed

Lines changed: 97 additions & 17 deletions

File tree

docs/setup.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
title: Setup
3+
---
4+
5+
## Configuration
6+
7+
By default, Sagittarius loads `config/sagittarius.yml`. Set
8+
`SAGITTARIUS_CONFIG_FILES` to a comma-separated list of configuration file
9+
paths to load multiple files:
10+
11+
```shell
12+
SAGITTARIUS_CONFIG_FILES=config/sagittarius.yml,/etc/sagittarius/config.yml,/run/secrets/sagittarius.yml
13+
```
14+
15+
Files are deep merged from left to right. Values in later files take
16+
precedence over earlier files and the built-in defaults.

lib/sagittarius/configuration.rb

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,28 @@ module Sagittarius
44
class Configuration
55
extend Code0::ZeroTrack::Memoize
66

7+
CONFIG_FILES_ENV = 'SAGITTARIUS_CONFIG_FILES'
8+
79
def self.config
810
memoize(:config) do
9-
file_config = YAML.safe_load_file(Rails.root.join('config/sagittarius.yml')).deep_symbolize_keys
10-
defaults.deep_merge(file_config)
11-
rescue Errno::ENOENT # config file does not exist
11+
configured_files = ENV.fetch(CONFIG_FILES_ENV, nil)
12+
config_files(configured_files).reduce(defaults) do |config, config_file|
13+
file_config = YAML.safe_load_file(config_file).deep_symbolize_keys
14+
config.deep_merge(file_config)
15+
end
16+
rescue Errno::ENOENT
17+
raise if configured_files.present?
18+
1219
defaults
1320
end
1421
end
1522

23+
def self.config_files(configured_files = ENV.fetch(CONFIG_FILES_ENV, nil))
24+
return [Rails.root.join('config/sagittarius.yml')] if configured_files.blank?
25+
26+
configured_files.split(',').map(&:strip).reject(&:empty?)
27+
end
28+
1629
def self.application_setting_overrides
1730
config[:application_setting_overrides]
1831
end

spec/lib/sagittarius/configuration_spec.rb

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,83 @@
44

55
RSpec.describe Sagittarius::Configuration do
66
describe '.config' do
7-
let(:yaml_config) do
8-
<<~CONFIG
9-
rails:
10-
web:
11-
threads: 4
12-
grpc:
13-
threads: 8
14-
CONFIG
15-
end
7+
let(:default_config_file) { Rails.root.join('config/sagittarius.yml') }
168

179
before do
18-
allow(File).to receive(:open).and_call_original
19-
allow(File).to receive(:open)
20-
.with(Rails.root.join('config/sagittarius.yml'), instance_of(String))
21-
.and_yield(yaml_config)
10+
allow(ENV).to receive(:fetch).and_call_original
11+
allow(ENV).to receive(:fetch).with('SAGITTARIUS_CONFIG_FILES', nil).and_return(nil)
2212
described_class.clear_memoize(:config)
2313
end
2414

25-
it 'loads the config' do
15+
it 'loads the default config file' do
16+
allow(YAML).to receive(:safe_load_file).with(default_config_file).and_return(
17+
'rails' => {
18+
'web' => { 'threads' => 4 },
19+
'grpc' => { 'threads' => 8 },
20+
}
21+
)
22+
2623
expect(described_class.config).to include(
2724
rails: a_hash_including(
2825
web: a_hash_including(threads: 4),
2926
grpc: a_hash_including(threads: 8)
3027
)
3128
)
3229
end
30+
31+
it 'uses built-in defaults when the default config file does not exist' do
32+
allow(YAML).to receive(:safe_load_file).with(default_config_file).and_raise(Errno::ENOENT)
33+
34+
expect(described_class.config).to eq(described_class.defaults)
35+
end
36+
37+
context 'when SAGITTARIUS_CONFIG_FILES contains multiple paths' do
38+
before do
39+
configured_files = ' config/base.yml,config/environment.yml, config/runtime.yml '
40+
allow(ENV).to receive(:fetch).with('SAGITTARIUS_CONFIG_FILES', nil)
41+
.and_return(configured_files)
42+
allow(YAML).to receive(:safe_load_file).with('config/base.yml').and_return(
43+
'rails' => {
44+
'web' => { 'threads' => 4, 'port' => 4000 },
45+
'grpc' => { 'threads' => 4 },
46+
}
47+
)
48+
allow(YAML).to receive(:safe_load_file).with('config/environment.yml').and_return(
49+
'rails' => {
50+
'web' => { 'threads' => 8 },
51+
'grpc' => { 'host' => 'environment:50051' },
52+
}
53+
)
54+
allow(YAML).to receive(:safe_load_file).with('config/runtime.yml').and_return(
55+
'rails' => {
56+
'web' => { 'threads' => 16 },
57+
}
58+
)
59+
end
60+
61+
it 'deep merges files in order with the last file taking precedence' do
62+
expect(described_class.config).to include(
63+
rails: a_hash_including(
64+
web: a_hash_including(threads: 16, port: 4000),
65+
grpc: a_hash_including(threads: 4, host: 'environment:50051')
66+
)
67+
)
68+
end
69+
70+
it 'loads each configured file in order' do
71+
described_class.config
72+
73+
expect(YAML).to have_received(:safe_load_file).ordered.with('config/base.yml')
74+
expect(YAML).to have_received(:safe_load_file).ordered.with('config/environment.yml')
75+
expect(YAML).to have_received(:safe_load_file).ordered.with('config/runtime.yml')
76+
end
77+
78+
it 'raises when a configured file does not exist' do
79+
allow(YAML).to receive(:safe_load_file).with('config/environment.yml').and_raise(Errno::ENOENT)
80+
81+
expect { described_class.config }.to raise_error(Errno::ENOENT)
82+
end
83+
end
3384
end
3485

3586
describe '.defaults' do

0 commit comments

Comments
 (0)