conf_conf 1.0.2 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/conf_conf.gemspec CHANGED
@@ -3,15 +3,23 @@ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = "conf_conf"
7
- s.version = "1.0.2"
8
- s.licenses = ["MIT"]
9
- s.authors = ["James Kassemi"]
10
- s.email = ["jkassemi@gmail.com"]
11
- s.homepage = "https://github.com/jkassemi/conf_conf"
12
- s.description = "Verify correctness of environment variables"
13
- s.summary = "A simple pattern and utility for verifying the correctness of the environment variables at application boot so we can fail fast when there's a configuration problem."
14
- s.files = `git ls-files`.split($/)
6
+ s.name = 'conf_conf'
7
+ s.version = '2.0.2'
8
+ s.licenses = ['MIT']
9
+ s.authors = ['James Kassemi']
10
+ s.email = ['jkassemi@gmail.com']
11
+ s.homepage = 'https://github.com/jkassemi/conf_conf'
12
+ s.description = 'Verify correctness of environment variables'
13
+ s.summary = 'A simple pattern and utility for verifying the correctness of the environment variables at application boot so we can fail fast when there\'s a configuration problem.'
14
+ s.files = `git ls-files`.split($/)
15
+ s.executables = ['conf_conf']
15
16
 
16
- s.add_development_dependency 'rspec', '~> 3.0'
17
+ s.add_runtime_dependency 'httpi', '~> 2.2.4'
18
+ s.add_runtime_dependency 'thor', '~> 0.19.1'
19
+ s.add_runtime_dependency 'colorize', '~> 0.7.3'
20
+ s.add_runtime_dependency 'highline', '~> 1.6.21'
21
+ s.add_runtime_dependency 'rbnacl-libsodium', '~> 0.5.0.1'
22
+ s.add_runtime_dependency 'multi_json', '~> 1.10.1'
23
+ s.add_runtime_dependency 'dotenv', '~> 0.11.1'
24
+ s.add_development_dependency 'rspec', '~> 3.0'
17
25
  end
data/lib/conf_conf.rb CHANGED
@@ -1,68 +1,77 @@
1
+ require 'multi_json'
1
2
  require 'ostruct'
2
3
 
3
- Dir["tasks/**/*.rake"].each { |ext| load ext } if defined?(Rake)
4
+ require 'conf_conf/project'
5
+ require 'conf_conf/configuration'
6
+ require 'conf_conf/project/developer'
7
+ require 'conf_conf/project/developers'
8
+ require 'conf_conf/project/environment'
9
+ require 'conf_conf/project/environment/storage'
10
+ require 'conf_conf/project/environments'
4
11
 
5
12
  module ConfConf
13
+ VERSION = '2.0.2'
14
+
6
15
  class MissingConfigurationValueError < StandardError; end;
16
+ class InconsistentConfigurationError < StandardError
17
+ attr_reader :inconsistencies
7
18
 
8
- class << self
9
- def configuration(&block)
10
- OpenStruct.new(Configuration.new(&block).parsed_values)
19
+ def initialize(inconsistencies)
20
+ @inconsistencies = inconsistencies
11
21
  end
22
+ end
12
23
 
13
- def rails_configuration(&block)
14
- configuration = Configuration.new
15
- configuration.run(block)
24
+ class << self
25
+ #TODO: This could be cleaned up considerably.
26
+ def configuration(environment_name=nil, &block)
27
+ if environment_name
28
+ # Load ENV
29
+ project = ConfConf::Project.new
30
+ environment = project.environments[environment_name]
16
31
 
17
- configuration.parsed_values.each do |key, value|
18
- Rails.configuration.send("#{key}=", value)
32
+ environment.variables.each do |name, value|
33
+ ENV[name] = value
34
+ end
19
35
  end
20
- end
21
- end
22
36
 
23
- class Configuration
24
- attr_reader :parsed_values
37
+ # Run configuration block, if given
38
+ configuration = ConfConf::Configuration.new
25
39
 
26
- def initialize(&block)
27
- @parsed_values = {}
28
- run(block) if block
29
- end
40
+ if block
41
+ configuration.run(block)
42
+ references = configuration.references
43
+ else
44
+ references = {}
45
+ end
30
46
 
31
- def run(block)
32
- instance_eval(&block)
33
- end
47
+ if environment_name
48
+ # Find references to variables that aren't defaulted here
49
+ inconsistencies = project.inconsistencies(environment)
34
50
 
35
- def config(key, options={})
36
- value = Reference.new(key, options).value
51
+ inconsistencies.each do |inconsistency|
52
+ if references[inconsistency] && references[inconsistency].default_value?
53
+ inconsistencies.delete(inconsistency)
54
+ end
55
+ end
37
56
 
38
- if block_given?
39
- value = yield(value)
57
+ if inconsistencies.length > 0
58
+ raise ConfConf::InconsistentConfigurationError.new(inconsistencies)
59
+ end
40
60
  end
41
61
 
42
- @parsed_values[key] = value
62
+ OpenStruct.new(configuration.parsed_values)
43
63
  end
44
- end
45
64
 
46
- class Reference < Struct.new(:key, :options)
47
- def value
48
- environment_value || default_value
49
- end
65
+ def rails_configuration(environment_name=nil, &block)
66
+ configuration = configuration(environment_name, block)
50
67
 
51
- private
52
- def default_value
53
- if options.has_key? :default
54
- options[:default]
55
- else
56
- raise MissingConfigurationValueError.new("Please set #{environment_key} or supply a default value")
68
+ configuration.parsed_values.each do |name, value|
69
+ Rails.configuration.send("#{key}=", value)
57
70
  end
58
71
  end
59
72
 
60
- def environment_value
61
- ENV[environment_key]
62
- end
63
-
64
- def environment_key
65
- options[:from] || key.to_s.upcase
73
+ def load(environment_name)
74
+ configuration(environment_name)
66
75
  end
67
76
  end
68
77
  end
@@ -0,0 +1,9 @@
1
+ require 'conf_conf'
2
+
3
+ module ConfConf::CLI
4
+ end
5
+
6
+ require 'conf_conf/cli/variables'
7
+ require 'conf_conf/cli/developers'
8
+ require 'conf_conf/cli/environments'
9
+ require 'conf_conf/cli/root'
@@ -0,0 +1,48 @@
1
+ class ConfConf::CLI::Developers < Thor
2
+ desc 'key', 'Your developer key'
3
+ def key
4
+ developer = ConfConf::Project::Developer.current
5
+
6
+ puts MultiJson.dump(developer.pretty_public_key, pretty: true)
7
+ end
8
+
9
+ desc 'permit <key>', 'Give <key> access to environment configurations'
10
+ def permit(key)
11
+ project = ConfConf::Project.new
12
+ developer = ConfConf::Project::Developer.new(key)
13
+ developers = project.developers
14
+
15
+ developers.add(developer)
16
+ developers.save
17
+
18
+ project.environments.to_a.each do |environment|
19
+ environment.save
20
+ end
21
+
22
+ puts MultiJson.dump(developers.keys.to_a, pretty: true)
23
+ end
24
+
25
+ desc 'revoke <key>', 'Deny <key> access to the environment configurations'
26
+ def revoke(key)
27
+ project = ConfConf::Project.new
28
+ developer = ConfConf::Project::Developer.new(key)
29
+ developers = project.developers
30
+
31
+ developers.remove(developer)
32
+ developers.save
33
+
34
+ project.environments.to_a.each do |environment|
35
+ environment.save
36
+ end
37
+
38
+ puts MultiJson.dump(developers.keys.to_a, pretty: true)
39
+ end
40
+
41
+ desc 'list', 'List of keys with access to the environment configurations'
42
+ def list
43
+ project = ConfConf::Project.new
44
+ developers = project.developers
45
+
46
+ puts MultiJson.dump(developers.keys.to_a, pretty: true)
47
+ end
48
+ end
@@ -0,0 +1,61 @@
1
+ module ConfConf::CLI
2
+ class Environments < Thor
3
+ desc 'list', 'Show environments'
4
+ def list
5
+ project = ConfConf::Project.new
6
+ puts MultiJson.dump(project.environments.to_a.collect(&:name), pretty: true)
7
+ end
8
+
9
+ desc 'add <environment>', 'Set up new environment'
10
+ long_desc <<-LONG
11
+ > $ conf_conf env add staging
12
+ LONG
13
+ def add(environment_name)
14
+ project = ConfConf::Project.new
15
+ environment = project.environments[environment_name]
16
+ environment.save
17
+
18
+ puts MultiJson.dump(project.environments.to_a.collect(&:name), pretty: true)
19
+ end
20
+
21
+ desc 'remove <environment>', 'Removes an existing environment'
22
+ def remove(environment_name)
23
+ project = ConfConf::Project.new
24
+ project.environments.remove(environment_name)
25
+
26
+ puts MultiJson.dump(project.environments.to_a.collect(&:name), pretty: true)
27
+ end
28
+
29
+ desc 'check (<environment>)', 'Check environment consistency'
30
+ def check(environment_name=nil)
31
+ project = ConfConf::Project.new
32
+
33
+ all_environment_variable_names = Set.new
34
+
35
+ project.environments.to_a.each do |environment|
36
+ all_environment_variable_names += environment.variables.keys
37
+ end
38
+
39
+ if environment_name.nil?
40
+ environments = project.environments.to_a
41
+ else
42
+ environments = [project.environments[environment_name]]
43
+ end
44
+
45
+ environment_warnings = {}
46
+
47
+ environments.each do |environment|
48
+ diff = all_environment_variable_names - environment.variables.keys
49
+
50
+ if diff.length > 0
51
+ diff.each do |key|
52
+ environment_warnings[environment.name] ||= {:missing => []}
53
+ environment_warnings[environment.name][:missing] << key
54
+ end
55
+ end
56
+ end
57
+
58
+ puts MultiJson.dump(environment_warnings, pretty: true)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,72 @@
1
+ module ConfConf
2
+ module CLI
3
+ class Root < Thor
4
+ desc 'environments', 'Manage available environments'
5
+ subcommand 'environments', ConfConf::CLI::Environments
6
+
7
+ desc 'variables', 'Configure environment variables'
8
+ subcommand 'variables', ConfConf::CLI::Variables
9
+
10
+ desc 'developers', 'Configure access credentials'
11
+ subcommand 'developers', ConfConf::CLI::Developers
12
+
13
+ desc 'init', 'Initialize conf_conf project'
14
+ long_desc <<-LONG
15
+ > $ conf_conf init
16
+
17
+ Initialize this system user's ~/.conf_conf.json
18
+ LONG
19
+ def init
20
+ account = ConfConf::Project::Developer.current
21
+ FileUtils.mkdir_p('config/conf_conf')
22
+ FileUtils.mkdir_p('config/conf_conf/environments')
23
+ puts MultiJson.dump(account: account, pretty: true)
24
+ end
25
+
26
+ desc 'export <environment>', '.env compatible export for <environment>'
27
+ def export(environment_name)
28
+ project = ConfConf::Project.new
29
+ environment = project.environments[environment_name]
30
+
31
+ environment.variables.each do |variable_name, variable_value|
32
+ puts "#{variable_name}=#{variable_value}"
33
+ end
34
+ end
35
+
36
+ desc 'import <environment>', 'Import from .env into <environment>'
37
+ option :dotenv, default: true
38
+ def import(environment_name)
39
+ require 'dotenv'
40
+
41
+ project = ConfConf::Project.new
42
+ environment = project.environments[environment_name]
43
+ dotenv_environment = Dotenv::Environment.new('.env')
44
+
45
+ dotenv_environment.each do |k,v|
46
+ environment.set(k, v)
47
+ end
48
+
49
+ environment.save
50
+ puts MultiJson.dump(environment.variables, pretty: true)
51
+ end
52
+
53
+ desc 'info', 'Summary of configurations'
54
+ def info
55
+ project = ConfConf::Project.new
56
+
57
+ summary = {}
58
+ summary[:environments] = project.environments.to_a.collect(&:name)
59
+ summary[:variables] = {}
60
+
61
+ project.environments.to_a.each do |environment|
62
+ environment.variables.each do |variable_name, variable_value|
63
+ summary[:variables][variable_name] ||= []
64
+ summary[:variables][variable_name] << environment.name
65
+ end
66
+ end
67
+
68
+ puts MultiJson.dump(summary, pretty: true)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,85 @@
1
+ class ConfConf::CLI::Variables < Thor
2
+ desc 'set', 'Set configuration values in the given environment'
3
+ option :env, default: false, desc: 'environment to set the config var'
4
+ long_desc <<-LONG
5
+ Sets Config Values in the given Environment.
6
+
7
+ Examples:
8
+
9
+ > $ conf_conf set X=1
10
+
11
+ Sets the Config Key `X` with Config Value `1` for all Environments.
12
+
13
+ > $ conf_conf set --env=production X=1
14
+
15
+ Sets the Config Key `X` with Config Value `1` for `production` Environment.
16
+ Sets the Config Key `X` with the Config Value `1` for the
17
+ `production` Environment.
18
+
19
+ > $ conf_conf set --env=production X=1 Y=2 Z=3
20
+
21
+ Sets the Config Keys `X`, `Y`, and `Z` with the Config
22
+ Values `1`, `2`, and `3`, respectively. Config Values are saved to
23
+ the `production` Environment.
24
+ LONG
25
+ def set(*env_variable_args)
26
+ project = ConfConf::Project.new
27
+ developers = project.developers
28
+
29
+ developer = ConfConf::Project::Developer.current
30
+ developers.add(developer)
31
+
32
+ if options[:env]
33
+ environments = [project.environments[options[:env]]]
34
+ else
35
+ environments = project.environments.to_a
36
+ end
37
+
38
+ return if environments.length == 0
39
+
40
+ env_variable_args.each do |env_variable|
41
+ config_key, config_value = env_variable.split("=").map(&:strip)
42
+
43
+ environments.each do |environment|
44
+ environment.set(config_key, config_value)
45
+ end
46
+ end
47
+
48
+ environments.map(&:save)
49
+ end
50
+
51
+ desc 'remove', 'Remove a configuration value'
52
+ option :env, default: 'development', desc: 'environment to remove the config var from'
53
+ long_desc <<-LONG
54
+ Examples:
55
+
56
+ > $ conf_conf remove X
57
+
58
+ Removes the `X` Environment Variable
59
+
60
+ > $ conf_conf remove --env=production X
61
+
62
+ Removes `X` from production only
63
+ LONG
64
+ def remove(*name_args)
65
+ project = ConfConf::Project.new
66
+
67
+ all_environments = project.environments.to_a
68
+
69
+ if options[:env]
70
+ environments = [project.environments[options[:env]]]
71
+ else
72
+ environments = all_environments
73
+ end
74
+
75
+ return if environments.length == 0
76
+
77
+ name_args.each do |name|
78
+ environments.each do |environment|
79
+ environment.remove(name)
80
+ end
81
+ end
82
+
83
+ environments.map(&:save)
84
+ end
85
+ end
@@ -0,0 +1,57 @@
1
+ module ConfConf
2
+ class Configuration
3
+ attr_reader :parsed_values
4
+ attr_reader :references
5
+
6
+ def initialize
7
+ @parsed_values = {}
8
+ @references = {}
9
+ end
10
+
11
+ def run(block)
12
+ instance_eval(&block)
13
+ end
14
+
15
+ def config(key, options={})
16
+ reference = Reference.new(key, options)
17
+ @references[reference.environment_key] = reference
18
+
19
+ value = reference.value
20
+
21
+ if block_given?
22
+ value = yield(value)
23
+ end
24
+
25
+ @parsed_values[key] = value
26
+ end
27
+ end
28
+
29
+ private
30
+ class Reference < Struct.new(:key, :options)
31
+ def value
32
+ environment_value || default_value
33
+ end
34
+
35
+ def default_value?
36
+ options[:default]
37
+ end
38
+
39
+ def environment_key
40
+ options[:from] || key.to_s.upcase
41
+ end
42
+
43
+ private
44
+ def default_value
45
+ if options.has_key? :default
46
+ options[:default]
47
+ else
48
+ raise ConfConf::MissingConfigurationValueError.new("Please set #{environment_key} or supply a default value")
49
+ end
50
+ end
51
+
52
+ def environment_value
53
+ ENV[environment_key]
54
+ end
55
+
56
+ end
57
+ end