ops_team 0.13.3 → 0.15.0
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.
- checksums.yaml +4 -4
- data/lib/action.rb +14 -0
- data/lib/app_config.rb +9 -9
- data/lib/builtin.rb +2 -0
- data/lib/builtins/envdiff.rb +117 -0
- data/lib/dependencies/apk.rb +1 -1
- data/lib/dependencies/apt.rb +14 -22
- data/lib/dependencies/gem.rb +19 -7
- data/lib/dependencies/versioned_dependency.rb +25 -0
- data/lib/environment.rb +9 -7
- data/lib/ops.rb +11 -0
- data/lib/output.rb +1 -1
- data/lib/secrets.rb +17 -13
- data/ops_team.gemspec +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3beee0325741d140b711ee3f939306452b176b9be9f7d9094c1e578ed780373
|
4
|
+
data.tar.gz: 33aef85445dd2494967e246c1b4ebfe7433d76b9b09512756cb2a086321438cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0d69fca7b243d34d4c14cf53d8b10942b212cd53fd897c136079d9883e939670f3b74c3383df547d6c2f9a7c1d25f0ce4ba11e3337e566cdab010a6ebe81ef9
|
7
|
+
data.tar.gz: 96e25352e3b8b337a53632e560e1f494c38d2fc09b0b314c4a4e6e07aec92324b52051ac0c5235a4ab8d394247683890230dd5b29fe86b8ec26102af0482c559
|
data/lib/action.rb
CHANGED
@@ -36,6 +36,20 @@ class Action
|
|
36
36
|
@config["skip_#{name}_hooks"]
|
37
37
|
end
|
38
38
|
|
39
|
+
def config_valid?
|
40
|
+
config_errors.empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
def config_errors
|
44
|
+
@config_errors ||= begin
|
45
|
+
errors = []
|
46
|
+
|
47
|
+
errors << "No 'command' specified in 'action'." unless @config['command']
|
48
|
+
|
49
|
+
errors
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
39
53
|
private
|
40
54
|
|
41
55
|
def load_secrets?
|
data/lib/app_config.rb
CHANGED
@@ -8,6 +8,14 @@ class AppConfig
|
|
8
8
|
new(app_config_path).load
|
9
9
|
end
|
10
10
|
|
11
|
+
def default_filename
|
12
|
+
config_path_for(Environment.environment)
|
13
|
+
end
|
14
|
+
|
15
|
+
def config_path_for(env)
|
16
|
+
"config/#{env}/config.json"
|
17
|
+
end
|
18
|
+
|
11
19
|
private
|
12
20
|
|
13
21
|
def app_config_path
|
@@ -20,7 +28,7 @@ class AppConfig
|
|
20
28
|
end
|
21
29
|
|
22
30
|
def initialize(filename = "")
|
23
|
-
@filename = filename.empty? ? default_filename : filename
|
31
|
+
@filename = filename.empty? ? AppConfig.default_filename : filename
|
24
32
|
end
|
25
33
|
|
26
34
|
def load
|
@@ -31,10 +39,6 @@ class AppConfig
|
|
31
39
|
|
32
40
|
private
|
33
41
|
|
34
|
-
def default_filename
|
35
|
-
"config/#{environment}/config.json"
|
36
|
-
end
|
37
|
-
|
38
42
|
def config
|
39
43
|
@config ||= file_contents ? YAML.safe_load(file_contents) : {}
|
40
44
|
rescue YAML::SyntaxError => e
|
@@ -48,8 +52,4 @@ class AppConfig
|
|
48
52
|
nil
|
49
53
|
end
|
50
54
|
end
|
51
|
-
|
52
|
-
def environment
|
53
|
-
ENV['environment']
|
54
|
-
end
|
55
55
|
end
|
data/lib/builtin.rb
CHANGED
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'builtin'
|
4
|
+
|
5
|
+
module Builtins
|
6
|
+
class EnvDiff < Builtin
|
7
|
+
class << self
|
8
|
+
def description
|
9
|
+
"compares keys present in config and secrets between different environments"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
check_args
|
15
|
+
|
16
|
+
if source_only_keys.empty? && dest_only_keys.empty?
|
17
|
+
Output.out("Environments '#{source_env}' and '#{dest_env}' define the same #{source_keys.length} key(s).")
|
18
|
+
return
|
19
|
+
end
|
20
|
+
|
21
|
+
output_key_summary(source_only_keys, source_env, dest_env) if source_only_keys.any?
|
22
|
+
output_key_summary(dest_only_keys, dest_env, source_env) if dest_only_keys.any?
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def output_key_summary(keys, in_env, not_in_env)
|
28
|
+
Output.warn("Environment '#{in_env}' defines keys that '#{not_in_env}' does not:\n")
|
29
|
+
keys.each do |key|
|
30
|
+
Output.warn(" - #{key}")
|
31
|
+
end
|
32
|
+
Output.out("")
|
33
|
+
end
|
34
|
+
|
35
|
+
def source_only_keys
|
36
|
+
@source_only_keys ||= source_keys - dest_keys
|
37
|
+
end
|
38
|
+
|
39
|
+
def dest_only_keys
|
40
|
+
@dest_only_keys ||= dest_keys - source_keys
|
41
|
+
end
|
42
|
+
|
43
|
+
def source_keys
|
44
|
+
@source_keys ||= keys_for(source_env)
|
45
|
+
end
|
46
|
+
|
47
|
+
def dest_keys
|
48
|
+
@dest_keys ||= keys_for(dest_env)
|
49
|
+
end
|
50
|
+
|
51
|
+
def keys_for(env)
|
52
|
+
config_keys_for(env) | secrets_keys_for(env)
|
53
|
+
end
|
54
|
+
|
55
|
+
def config_keys_for(env)
|
56
|
+
(config_for(env)["environment"]&.keys || []).map do |key|
|
57
|
+
"[CONFIG] #{key}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def secrets_keys_for(env)
|
62
|
+
(secrets_for(env)["environment"]&.keys || []).map do |key|
|
63
|
+
"[SECRET] #{key}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def config_for(env)
|
68
|
+
YAML.load_file(config_path_for(env))
|
69
|
+
end
|
70
|
+
|
71
|
+
def secrets_for(env)
|
72
|
+
YAML.load_file(secrets_path_for(env))
|
73
|
+
end
|
74
|
+
|
75
|
+
def check_args
|
76
|
+
raise Builtin::ArgumentError, "Usage: ops envdiff <env_one> <env_two>" unless args.length == 2
|
77
|
+
|
78
|
+
check_environment(source_env)
|
79
|
+
check_environment(dest_env)
|
80
|
+
end
|
81
|
+
|
82
|
+
def source_env
|
83
|
+
args[0]
|
84
|
+
end
|
85
|
+
|
86
|
+
def dest_env
|
87
|
+
args[1]
|
88
|
+
end
|
89
|
+
|
90
|
+
def check_environment(name)
|
91
|
+
raise_missing_file_error(config_path_for(name)) unless config_file_exists?(name)
|
92
|
+
raise_missing_file_error(secrets_path_for(name)) unless secrets_file_exists?(name)
|
93
|
+
end
|
94
|
+
|
95
|
+
def raise_missing_file_error(path)
|
96
|
+
raise Builtin::ArgumentError, "File '#{path}' does not exist."
|
97
|
+
end
|
98
|
+
|
99
|
+
def config_file_exists?(env)
|
100
|
+
File.exist?(config_path_for(env))
|
101
|
+
end
|
102
|
+
|
103
|
+
def secrets_file_exists?(env)
|
104
|
+
File.exist?(secrets_path_for(env))
|
105
|
+
end
|
106
|
+
|
107
|
+
def config_path_for(env)
|
108
|
+
AppConfig.config_path_for(env)
|
109
|
+
end
|
110
|
+
|
111
|
+
def secrets_path_for(env)
|
112
|
+
Secrets.config_path_for(env)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
Envdiff = EnvDiff
|
117
|
+
end
|
data/lib/dependencies/apk.rb
CHANGED
data/lib/dependencies/apt.rb
CHANGED
@@ -1,20 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'dependencies/versioned_dependency'
|
4
4
|
require 'dependencies/helpers/apt_cache_policy'
|
5
5
|
|
6
6
|
module Dependencies
|
7
|
-
class Apt <
|
8
|
-
PACKAGE_NAME_SEPARATOR = "/"
|
9
|
-
|
7
|
+
class Apt < VersionedDependency
|
10
8
|
def met?
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
if versioned?
|
10
|
+
apt_cache_policy.installed_version == dep_version
|
11
|
+
else
|
12
|
+
apt_cache_policy.installed?
|
13
|
+
end
|
14
14
|
end
|
15
15
|
|
16
16
|
def meet
|
17
|
-
|
17
|
+
if versioned?
|
18
|
+
execute("#{sudo_string}apt-get install -y #{dep_name}=#{dep_version}")
|
19
|
+
else
|
20
|
+
execute("#{sudo_string}apt-get install -y #{name}")
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
def unmeet
|
@@ -23,25 +27,13 @@ module Dependencies
|
|
23
27
|
end
|
24
28
|
|
25
29
|
def should_meet?
|
26
|
-
`uname`.chomp == "Linux" && system("which apt-get")
|
30
|
+
`uname`.chomp == "Linux" && system("which apt-get", out: File::NULL, err: File::NULL)
|
27
31
|
end
|
28
32
|
|
29
33
|
private
|
30
34
|
|
31
|
-
def package_name
|
32
|
-
name_components[0]
|
33
|
-
end
|
34
|
-
|
35
|
-
def package_version
|
36
|
-
name_components[1]
|
37
|
-
end
|
38
|
-
|
39
|
-
def name_components
|
40
|
-
name.split(PACKAGE_NAME_SEPARATOR, 2)
|
41
|
-
end
|
42
|
-
|
43
35
|
def apt_cache_policy
|
44
|
-
@apt_cache_policy ||= Dependencies::Helpers::AptCachePolicy.new(
|
36
|
+
@apt_cache_policy ||= Dependencies::Helpers::AptCachePolicy.new(dep_name)
|
45
37
|
end
|
46
38
|
|
47
39
|
def sudo_string
|
data/lib/dependencies/gem.rb
CHANGED
@@ -4,18 +4,20 @@ require 'dependency'
|
|
4
4
|
require 'options'
|
5
5
|
|
6
6
|
module Dependencies
|
7
|
-
class Gem <
|
7
|
+
class Gem < VersionedDependency
|
8
8
|
def met?
|
9
|
-
|
9
|
+
if versioned?
|
10
|
+
execute("gem list -i '^#{dep_name}$' -v '#{dep_version}'") if versioned?
|
11
|
+
else
|
12
|
+
execute("gem list -i '^#{name}$'")
|
13
|
+
end
|
10
14
|
end
|
11
15
|
|
12
16
|
def meet
|
13
|
-
if
|
14
|
-
execute("
|
15
|
-
elsif Options.get("gem.user_install")
|
16
|
-
execute("gem install --user-install #{name}")
|
17
|
+
if versioned?
|
18
|
+
execute("#{sudo_string}gem install #{user_install_string}'#{dep_name}' -v '#{dep_version}'")
|
17
19
|
else
|
18
|
-
execute("gem install #{name}")
|
20
|
+
execute("#{sudo_string}gem install #{user_install_string}'#{name}'")
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
@@ -23,5 +25,15 @@ module Dependencies
|
|
23
25
|
# do nothing; we don't want to uninstall packages and reinstall them every time
|
24
26
|
true
|
25
27
|
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def sudo_string
|
32
|
+
Options.get("gem.use_sudo") ? "sudo " : ""
|
33
|
+
end
|
34
|
+
|
35
|
+
def user_install_string
|
36
|
+
Options.get("gem.user_install") ? "--user-install " : ""
|
37
|
+
end
|
26
38
|
end
|
27
39
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dependencies
|
4
|
+
class VersionedDependency < Dependency
|
5
|
+
VERSION_SEPARATOR = " "
|
6
|
+
|
7
|
+
def dep_name
|
8
|
+
name_components[0]
|
9
|
+
end
|
10
|
+
|
11
|
+
def dep_version
|
12
|
+
name_components[1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def versioned?
|
16
|
+
!!dep_version
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def name_components
|
22
|
+
name.split(VERSION_SEPARATOR, 2)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/environment.rb
CHANGED
@@ -3,6 +3,14 @@
|
|
3
3
|
require 'version'
|
4
4
|
|
5
5
|
class Environment
|
6
|
+
class << self
|
7
|
+
def environment
|
8
|
+
return 'dev' if ENV['environment'].nil? || ENV['environment'].empty?
|
9
|
+
|
10
|
+
ENV['environment']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
6
14
|
def initialize(env_hash)
|
7
15
|
@env_hash = env_hash
|
8
16
|
end
|
@@ -13,12 +21,6 @@ class Environment
|
|
13
21
|
set_configured_variables
|
14
22
|
end
|
15
23
|
|
16
|
-
def environment
|
17
|
-
return 'dev' if ENV['environment'].nil? || ENV['environment'].empty?
|
18
|
-
|
19
|
-
ENV['environment']
|
20
|
-
end
|
21
|
-
|
22
24
|
private
|
23
25
|
|
24
26
|
def set_ops_variables
|
@@ -28,7 +30,7 @@ class Environment
|
|
28
30
|
|
29
31
|
def set_environment_aliases
|
30
32
|
environment_aliases.each do |alias_name|
|
31
|
-
ENV[alias_name] = environment
|
33
|
+
ENV[alias_name] = Environment.environment
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
data/lib/ops.rb
CHANGED
@@ -19,6 +19,7 @@ require_rel "builtins"
|
|
19
19
|
# executes commands based on local `ops.yml`
|
20
20
|
class Ops
|
21
21
|
class UnknownActionError < StandardError; end
|
22
|
+
class ActionConfigError < StandardError; end
|
22
23
|
|
23
24
|
CONFIG_FILE = "ops.yml"
|
24
25
|
|
@@ -26,6 +27,8 @@ class Ops
|
|
26
27
|
UNKNOWN_ACTION_EXIT_CODE = 65
|
27
28
|
ERROR_LOADING_APP_CONFIG_EXIT_CODE = 66
|
28
29
|
MIN_VERSION_NOT_MET_EXIT_CODE = 67
|
30
|
+
ACTION_CONFIG_ERROR_EXIT_CODE = 68
|
31
|
+
BUILTIN_SYNTAX_ERROR_EXIT_CODE = 69
|
29
32
|
|
30
33
|
RECOMMEND_HELP_TEXT = "Run 'ops help' for a list of builtins and actions."
|
31
34
|
|
@@ -52,6 +55,9 @@ class Ops
|
|
52
55
|
Output.error(e.to_s)
|
53
56
|
Output.out(RECOMMEND_HELP_TEXT) unless print_did_you_mean
|
54
57
|
exit(UNKNOWN_ACTION_EXIT_CODE)
|
58
|
+
rescue ActionConfigError => e
|
59
|
+
Output.error("Error(s) running action '#{@action_name}': #{e}")
|
60
|
+
exit(ACTION_CONFIG_ERROR_EXIT_CODE)
|
55
61
|
end
|
56
62
|
|
57
63
|
private
|
@@ -98,9 +104,14 @@ class Ops
|
|
98
104
|
|
99
105
|
return builtin.run if builtin
|
100
106
|
|
107
|
+
raise ActionConfigError, action.config_errors.join("; ") unless action.config_valid?
|
108
|
+
|
101
109
|
do_before_action
|
102
110
|
Output.notice("Running '#{action}' from #{CONFIG_FILE} in environment '#{ENV['environment']}'...")
|
103
111
|
action.run
|
112
|
+
rescue Builtin::ArgumentError => e
|
113
|
+
Output.error("Error running builtin '#{@action_name}': #{e}")
|
114
|
+
exit(BUILTIN_SYNTAX_ERROR_EXIT_CODE)
|
104
115
|
rescue AppConfig::ParsingError => e
|
105
116
|
Output.error("Error parsing app config: #{e}")
|
106
117
|
exit(ERROR_LOADING_APP_CONFIG_EXIT_CODE)
|
data/lib/output.rb
CHANGED
data/lib/secrets.rb
CHANGED
@@ -9,31 +9,35 @@ require 'options'
|
|
9
9
|
|
10
10
|
class Secrets < AppConfig
|
11
11
|
class << self
|
12
|
+
def default_filename
|
13
|
+
config_path_for(Environment.environment)
|
14
|
+
end
|
15
|
+
|
16
|
+
def config_path_for(env)
|
17
|
+
File.exist?(ejson_path_for(env)) ? ejson_path_for(env) : json_path_for(env)
|
18
|
+
end
|
19
|
+
|
12
20
|
private
|
13
21
|
|
22
|
+
def ejson_path_for(env)
|
23
|
+
"config/#{env}/secrets.ejson"
|
24
|
+
end
|
25
|
+
|
26
|
+
def json_path_for(env)
|
27
|
+
"config/#{env}/secrets.json"
|
28
|
+
end
|
29
|
+
|
14
30
|
def app_config_path
|
15
31
|
expand_path(Options.get("secrets.path"))
|
16
32
|
end
|
17
33
|
end
|
18
34
|
|
19
35
|
def initialize(filename = "")
|
20
|
-
@filename = filename.empty? ? default_filename : actual_filename_for(filename)
|
36
|
+
@filename = filename.empty? ? Secrets.default_filename : actual_filename_for(filename)
|
21
37
|
end
|
22
38
|
|
23
39
|
private
|
24
40
|
|
25
|
-
def default_filename
|
26
|
-
File.exist?(default_ejson_filename) ? default_ejson_filename : default_json_filename
|
27
|
-
end
|
28
|
-
|
29
|
-
def default_ejson_filename
|
30
|
-
"config/#{environment}/secrets.ejson"
|
31
|
-
end
|
32
|
-
|
33
|
-
def default_json_filename
|
34
|
-
"config/#{environment}/secrets.json"
|
35
|
-
end
|
36
|
-
|
37
41
|
def actual_filename_for(filename)
|
38
42
|
File.exist?(filename) ? filename : filename.sub(".ejson", ".json")
|
39
43
|
end
|
data/ops_team.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ops_team
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nickthecook@gmail.com
|
@@ -154,6 +154,7 @@ files:
|
|
154
154
|
- lib/builtins/background_log.rb
|
155
155
|
- lib/builtins/down.rb
|
156
156
|
- lib/builtins/env.rb
|
157
|
+
- lib/builtins/envdiff.rb
|
157
158
|
- lib/builtins/exec.rb
|
158
159
|
- lib/builtins/help.rb
|
159
160
|
- lib/builtins/helpers/dependency_handler.rb
|
@@ -170,6 +171,7 @@ files:
|
|
170
171
|
- lib/dependencies/gem.rb
|
171
172
|
- lib/dependencies/helpers/apt_cache_policy.rb
|
172
173
|
- lib/dependencies/sshkey.rb
|
174
|
+
- lib/dependencies/versioned_dependency.rb
|
173
175
|
- lib/dependency.rb
|
174
176
|
- lib/environment.rb
|
175
177
|
- lib/executor.rb
|