-
-
Notifications
You must be signed in to change notification settings - Fork 234
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Natalie Tay <[email protected]> Signed-off-by: Alan Yeo <[email protected]> Signed-off-by: Benjamin Tan <[email protected]>
- Loading branch information
Showing
16 changed files
with
385 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
require 'bundler' | ||
require 'yaml' | ||
require_relative '../../../lib/config/integrations/helpers/cf_manifest_merger' | ||
|
||
module Config | ||
module Integrations | ||
class CloudFoundry < Struct.new(:target_env, :file_path) | ||
|
||
def invoke | ||
|
||
manifest_path = file_path | ||
file_name, _ext = manifest_path.split('.yml') | ||
|
||
manifest_hash = YAML.load(IO.read(File.join(::Rails.root, manifest_path))) | ||
|
||
puts "Generating manifest... (base cf manifest: #{manifest_path})" | ||
|
||
merged_hash = Config::CFManifestMerger.new(target_env, manifest_hash).add_to_env | ||
|
||
target_manifest_path = File.join(::Rails.root, "#{file_name}-merged.yml") | ||
IO.write(target_manifest_path, merged_hash.to_yaml) | ||
|
||
puts "File #{target_manifest_path} generated." | ||
end | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
require_relative 'helpers' | ||
|
||
module Config | ||
class CFManifestMerger | ||
include Integrations::Helpers | ||
|
||
def initialize(target_env, manifest_hash) | ||
@manifest_hash = manifest_hash.dup | ||
|
||
raise ArgumentError.new('Target environment & manifest path must be specified') unless target_env && @manifest_hash | ||
|
||
config_setting_files = Config.setting_files(Rails.root, target_env) | ||
@settings_hash = Config.load_files(config_setting_files).to_hash.stringify_keys | ||
end | ||
|
||
def add_to_env | ||
|
||
prefix_keys_with_const_name_hash = to_dotted_hash(@settings_hash, namespace: Config.const_name) | ||
|
||
apps = @manifest_hash['applications'] | ||
|
||
apps.each do |app| | ||
check_conflicting_keys(app['env'], @settings_hash) | ||
app['env'].merge!(prefix_keys_with_const_name_hash) | ||
end | ||
|
||
@manifest_hash | ||
end | ||
|
||
private | ||
|
||
def check_conflicting_keys(env_hash, settings_hash) | ||
conflicting_keys = env_hash.keys & settings_hash.keys | ||
raise ArgumentError.new("Conflicting keys: #{conflicting_keys.join(', ')}") if conflicting_keys.any? | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
module Config::Integrations::Helpers | ||
|
||
def to_dotted_hash(source, target: {}, namespace: nil) | ||
raise ArgumentError, "target must be a hash (given: #{target.class.name})" unless target.kind_of? Hash | ||
prefix = "#{namespace}." if namespace | ||
case source | ||
when Hash | ||
source.each do |key, value| | ||
to_dotted_hash(value, target: target, namespace: "#{prefix}#{key}") | ||
end | ||
when Array | ||
source.each_with_index do |value, index| | ||
to_dotted_hash(value, target: target, namespace: "#{prefix}#{index}") | ||
end | ||
else | ||
target[namespace] = source | ||
end | ||
target | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
require 'config/integrations/cloud_foundry' | ||
|
||
namespace 'config' do | ||
|
||
desc 'Create a cf manifest with the env variables defined by config under current environment' | ||
task 'cf', [:target_env, :file_path] => [:environment] do |_, args| | ||
|
||
raise ArgumentError, 'Both target_env and file_path arguments must be specified' if args.length == 1 | ||
|
||
default_args = {:target_env => Rails.env, :file_path => 'manifest.yml'} | ||
merged_args = default_args.merge(args) | ||
|
||
Config::Integrations::CloudFoundry.new(*merged_args.values).invoke | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
require 'config/integrations/heroku' | ||
|
||
namespace 'config' do | ||
|
||
desc 'Upload to Heroku all env variables defined by config under current environment' | ||
task :heroku, [:app] => :environment do |_, args| | ||
Config::Integrations::Heroku.new(args[:app]).invoke | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
applications: | ||
- name: some-cf-app | ||
instances: 1 | ||
env: | ||
DEFAULT_HOST: host | ||
DEFAULT_PORT: port | ||
FOO: BAR | ||
|
||
- name: app_name | ||
env: | ||
DEFAULT_HOST: host |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
DEFAULT_HOST: host | ||
DEFAULT_PORT: port |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
world: | ||
capitals: | ||
europe: | ||
germany: 'Berlin' | ||
poland: 'Warsaw' | ||
array: | ||
- name: 'Alan' | ||
- name: 'Gam' | ||
array_with_index: | ||
0: | ||
name: 'Bob' | ||
1: | ||
name: 'William' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
require 'spec_helper' | ||
require_relative '../../../lib/config/integrations/helpers/cf_manifest_merger' | ||
|
||
describe Config::CFManifestMerger do | ||
|
||
let(:mocked_rails_root_path) { "#{fixture_path}/cf/" } | ||
let(:manifest_hash) { load_manifest('cf_manifest.yml') } | ||
|
||
it 'raises an argument error if you do not specify a target environment' do | ||
expect { | ||
Config::CFManifestMerger.new(nil, manifest_hash) | ||
}.to raise_error(ArgumentError, 'Target environment & manifest path must be specified') | ||
end | ||
|
||
it 'returns the cf manifest unmodified if no settings are available' do | ||
merger = Config::CFManifestMerger.new('test', manifest_hash) | ||
|
||
resulting_hash = merger.add_to_env | ||
expect(resulting_hash).to eq(manifest_hash) | ||
end | ||
|
||
it 'adds the settings for the target_env to the manifest_hash' do | ||
allow(Rails).to receive(:root).and_return(mocked_rails_root_path) | ||
|
||
merger = Config::CFManifestMerger.new('multilevel_settings', manifest_hash) | ||
|
||
resulting_hash = merger.add_to_env | ||
expect(resulting_hash).to eq({ | ||
'applications' => [ | ||
{ | ||
'name' => 'some-cf-app', | ||
'instances' => 1, | ||
'env' => { | ||
'DEFAULT_HOST' => 'host', | ||
'DEFAULT_PORT' => 'port', | ||
'FOO' => 'BAR', | ||
'Settings.world.capitals.europe.germany' => 'Berlin', | ||
'Settings.world.capitals.europe.poland' => 'Warsaw', | ||
'Settings.world.array.0.name' => 'Alan', | ||
'Settings.world.array.1.name' => 'Gam', | ||
'Settings.world.array_with_index.0.name' => 'Bob', | ||
'Settings.world.array_with_index.1.name' => 'William' | ||
} | ||
}, | ||
{ | ||
'name' => 'app_name', | ||
'env' => { | ||
'DEFAULT_HOST' => 'host', | ||
'Settings.world.capitals.europe.germany' => 'Berlin', | ||
'Settings.world.capitals.europe.poland' => 'Warsaw', | ||
'Settings.world.array.0.name' => 'Alan', | ||
'Settings.world.array.1.name' => 'Gam', | ||
'Settings.world.array_with_index.0.name' => 'Bob', | ||
'Settings.world.array_with_index.1.name' => 'William' | ||
} | ||
} | ||
] | ||
}) | ||
end | ||
|
||
it 'raises an exception if there is conflicting keys' do | ||
allow(Rails).to receive(:root).and_return(mocked_rails_root_path) | ||
|
||
merger = Config::CFManifestMerger.new('conflict_settings', manifest_hash) | ||
|
||
# Config.load_and_set_settings "#{fixture_path}/cf/conflict_settings.yml" | ||
expect { | ||
merger.add_to_env | ||
}.to raise_error(ArgumentError, 'Conflicting keys: DEFAULT_HOST, DEFAULT_PORT') | ||
end | ||
|
||
def load_manifest filename | ||
YAML.load(IO.read("#{fixture_path}/cf/#{filename}")) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
require 'spec_helper' | ||
require_relative '../../../lib/config/integrations/helpers/helpers' | ||
|
||
describe 'Helpers' do | ||
|
||
subject { Class.new.send(:include, Config::Integrations::Helpers).new } | ||
|
||
describe '#to_dotted_hash' do | ||
|
||
context 'only the source is specified' do | ||
|
||
it 'returns a hash with a nil key (default)' do | ||
expect(subject.to_dotted_hash 3).to eq({nil => 3}) | ||
end | ||
end | ||
|
||
context 'with invalid arguments' do | ||
it 'raises an error' do | ||
expect { subject.to_dotted_hash(3, target: [1, 2, 7], namespace: 2) } | ||
.to raise_error(ArgumentError, 'target must be a hash (given: Array)') | ||
end | ||
end | ||
|
||
context 'all arguments specified' do | ||
|
||
it 'returns a hash with the namespace as the key' do | ||
expect(subject.to_dotted_hash(3, namespace: 'ns')).to eq({'ns' => 3}) | ||
end | ||
|
||
it 'returns a new hash with a dotted string key prefixed with namespace' do | ||
expect(subject.to_dotted_hash({hello: {cruel: 'world'}}, namespace: 'ns')) | ||
.to eq({'ns.hello.cruel' => 'world'}) | ||
end | ||
|
||
it 'returns the same hash as passed as a parameter' do | ||
target = {something: 'inside'} | ||
target_id = target.object_id | ||
result = subject.to_dotted_hash(2, target: target, namespace: 'ns') | ||
expect(result).to eq({:something => 'inside', 'ns' => 2}) | ||
expect(result.object_id).to eq target_id | ||
end | ||
|
||
it 'returns a hash when given a source with mixed nested types (hashes & arrays)' do | ||
expect(subject.to_dotted_hash( | ||
{hello: {evil: [:cruel, 'world', and: {dark: 'universe'}]}}, namespace: 'ns')) | ||
.to eq( | ||
{"ns.hello.evil.0" => :cruel, | ||
"ns.hello.evil.1" => "world", | ||
"ns.hello.evil.2.and.dark" => "universe"} | ||
) | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.