Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: Setup
---

## Configuration

By default, Sagittarius loads `config/sagittarius.yml`. Set
`SAGITTARIUS_CONFIG_FILES` to a comma-separated list of configuration file
paths to load multiple files:

```shell
SAGITTARIUS_CONFIG_FILES=config/sagittarius.yml,/etc/sagittarius/config.yml,/run/secrets/sagittarius.yml
```

Files are deep merged from left to right. Values in later files take
precedence over earlier files and the built-in defaults.
19 changes: 16 additions & 3 deletions lib/sagittarius/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,28 @@ module Sagittarius
class Configuration
extend Code0::ZeroTrack::Memoize

CONFIG_FILES_ENV = 'SAGITTARIUS_CONFIG_FILES'

def self.config
memoize(:config) do
file_config = YAML.safe_load_file(Rails.root.join('config/sagittarius.yml')).deep_symbolize_keys
defaults.deep_merge(file_config)
rescue Errno::ENOENT # config file does not exist
configured_files = ENV.fetch(CONFIG_FILES_ENV, nil)
config_files(configured_files).reduce(defaults) do |config, config_file|
file_config = YAML.safe_load_file(config_file).deep_symbolize_keys
config.deep_merge(file_config)
end
rescue Errno::ENOENT
raise if configured_files.present?

defaults
end
end

def self.config_files(configured_files = ENV.fetch(CONFIG_FILES_ENV, nil))
return [Rails.root.join('config/sagittarius.yml')] if configured_files.blank?

configured_files.split(',').map(&:strip).reject(&:empty?)
end

def self.application_setting_overrides
config[:application_setting_overrides]
end
Expand Down
79 changes: 65 additions & 14 deletions spec/lib/sagittarius/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,83 @@

RSpec.describe Sagittarius::Configuration do
describe '.config' do
let(:yaml_config) do
<<~CONFIG
rails:
web:
threads: 4
grpc:
threads: 8
CONFIG
end
let(:default_config_file) { Rails.root.join('config/sagittarius.yml') }

before do
allow(File).to receive(:open).and_call_original
allow(File).to receive(:open)
.with(Rails.root.join('config/sagittarius.yml'), instance_of(String))
.and_yield(yaml_config)
allow(ENV).to receive(:fetch).and_call_original
allow(ENV).to receive(:fetch).with('SAGITTARIUS_CONFIG_FILES', nil).and_return(nil)
described_class.clear_memoize(:config)
end

it 'loads the config' do
it 'loads the default config file' do
allow(YAML).to receive(:safe_load_file).with(default_config_file).and_return(
'rails' => {
'web' => { 'threads' => 4 },
'grpc' => { 'threads' => 8 },
}
)

expect(described_class.config).to include(
rails: a_hash_including(
web: a_hash_including(threads: 4),
grpc: a_hash_including(threads: 8)
)
)
end

it 'uses built-in defaults when the default config file does not exist' do
allow(YAML).to receive(:safe_load_file).with(default_config_file).and_raise(Errno::ENOENT)

expect(described_class.config).to eq(described_class.defaults)
end

context 'when SAGITTARIUS_CONFIG_FILES contains multiple paths' do
before do
configured_files = ' config/base.yml,config/environment.yml, config/runtime.yml '
allow(ENV).to receive(:fetch).with('SAGITTARIUS_CONFIG_FILES', nil)
.and_return(configured_files)
allow(YAML).to receive(:safe_load_file).with('config/base.yml').and_return(
'rails' => {
'web' => { 'threads' => 4, 'port' => 4000 },
'grpc' => { 'threads' => 4 },
}
)
allow(YAML).to receive(:safe_load_file).with('config/environment.yml').and_return(
'rails' => {
'web' => { 'threads' => 8 },
'grpc' => { 'host' => 'environment:50051' },
}
)
allow(YAML).to receive(:safe_load_file).with('config/runtime.yml').and_return(
'rails' => {
'web' => { 'threads' => 16 },
}
)
end

it 'deep merges files in order with the last file taking precedence' do
expect(described_class.config).to include(
rails: a_hash_including(
web: a_hash_including(threads: 16, port: 4000),
grpc: a_hash_including(threads: 4, host: 'environment:50051')
)
)
end

it 'loads each configured file in order' do
described_class.config

expect(YAML).to have_received(:safe_load_file).ordered.with('config/base.yml')
expect(YAML).to have_received(:safe_load_file).ordered.with('config/environment.yml')
expect(YAML).to have_received(:safe_load_file).ordered.with('config/runtime.yml')
end

it 'raises when a configured file does not exist' do
allow(YAML).to receive(:safe_load_file).with('config/environment.yml').and_raise(Errno::ENOENT)

expect { described_class.config }.to raise_error(Errno::ENOENT)
end
end
end

describe '.defaults' do
Expand Down