conf_conf 1.0.2 → 2.0.2

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.
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