ops_team 1.21.1 → 2.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/ops +4 -40
- data/build/darwin_amd64/ops +0 -0
- data/build/darwin_arm64/ops +0 -0
- data/build/linux_amd64/ops +0 -0
- metadata +12 -224
- data/Gemfile +0 -30
- data/bin/benchmark +0 -185
- data/bin/print_config +0 -4
- data/bin/print_secrets +0 -4
- data/bin/tag +0 -16
- data/etc/ops.template.yml +0 -13
- data/etc/ruby.template.yml +0 -37
- data/etc/terraform.template.yml +0 -36
- data/lib/action.rb +0 -103
- data/lib/action_list.rb +0 -55
- data/lib/action_suggester.rb +0 -17
- data/lib/app_config.rb +0 -69
- data/lib/builtin.rb +0 -51
- data/lib/builtins/background.rb +0 -46
- data/lib/builtins/background_log.rb +0 -34
- data/lib/builtins/common/up_down.rb +0 -67
- data/lib/builtins/countdown.rb +0 -73
- data/lib/builtins/down.rb +0 -9
- data/lib/builtins/env.rb +0 -21
- data/lib/builtins/envdiff.rb +0 -127
- data/lib/builtins/exec.rb +0 -24
- data/lib/builtins/help.rb +0 -66
- data/lib/builtins/helpers/dependency_handler.rb +0 -27
- data/lib/builtins/helpers/enumerator.rb +0 -34
- data/lib/builtins/init.rb +0 -64
- data/lib/builtins/up.rb +0 -9
- data/lib/builtins/version.rb +0 -17
- data/lib/dependencies/apk.rb +0 -24
- data/lib/dependencies/apt.rb +0 -42
- data/lib/dependencies/brew.rb +0 -22
- data/lib/dependencies/cask.rb +0 -13
- data/lib/dependencies/custom.rb +0 -45
- data/lib/dependencies/dir.rb +0 -22
- data/lib/dependencies/docker.rb +0 -17
- data/lib/dependencies/gem.rb +0 -36
- data/lib/dependencies/helpers/apt_cache_policy.rb +0 -43
- data/lib/dependencies/pip.rb +0 -32
- data/lib/dependencies/snap.rb +0 -32
- data/lib/dependencies/sshkey.rb +0 -121
- data/lib/dependencies/versioned_dependency.rb +0 -25
- data/lib/dependency.rb +0 -69
- data/lib/environment.rb +0 -47
- data/lib/executor.rb +0 -20
- data/lib/forward.rb +0 -15
- data/lib/forwards.rb +0 -16
- data/lib/hook_handler.rb +0 -41
- data/lib/ops.rb +0 -129
- data/lib/options.rb +0 -22
- data/lib/output.rb +0 -71
- data/lib/profiler.rb +0 -47
- data/lib/runner.rb +0 -110
- data/lib/secrets.rb +0 -55
- data/lib/version.rb +0 -38
- data/loader.rb +0 -10
- data/ops_team.gemspec +0 -36
data/lib/action.rb
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# represents one action to be performed in the shell
|
4
|
-
# can assemble a command line from a command and args
|
5
|
-
class Action
|
6
|
-
attr_reader :name
|
7
|
-
|
8
|
-
def initialize(name, config, args)
|
9
|
-
@name = name
|
10
|
-
@config = config || {}
|
11
|
-
@args = args
|
12
|
-
end
|
13
|
-
|
14
|
-
def run
|
15
|
-
Output.error(Profiler.summary) if Profiler.summary
|
16
|
-
|
17
|
-
if perform_shell_expansion?
|
18
|
-
Kernel.exec(to_s)
|
19
|
-
else
|
20
|
-
Kernel.exec(*to_a)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def to_s
|
25
|
-
"#{command} #{@args.join(' ')}".strip
|
26
|
-
end
|
27
|
-
|
28
|
-
def alias
|
29
|
-
@config["alias"] || @config["aliases"]&.first
|
30
|
-
end
|
31
|
-
|
32
|
-
def aliases
|
33
|
-
return [@config["alias"]].compact unless @config["aliases"]
|
34
|
-
|
35
|
-
([@config["alias"]] + @config["aliases"]).compact
|
36
|
-
end
|
37
|
-
|
38
|
-
def command
|
39
|
-
return @config if @config.is_a?(String)
|
40
|
-
|
41
|
-
@config["command"]
|
42
|
-
end
|
43
|
-
|
44
|
-
def description
|
45
|
-
@config["description"]
|
46
|
-
end
|
47
|
-
|
48
|
-
def skip_hooks?(name)
|
49
|
-
@config["skip_#{name}_hooks"]
|
50
|
-
end
|
51
|
-
|
52
|
-
def config_valid?
|
53
|
-
config_errors.empty?
|
54
|
-
end
|
55
|
-
|
56
|
-
def config_errors
|
57
|
-
@config_errors ||= begin
|
58
|
-
errors = []
|
59
|
-
|
60
|
-
errors << "No 'command' specified in 'action'." unless command
|
61
|
-
|
62
|
-
errors
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def load_secrets?
|
67
|
-
@config["load_secrets"].nil? ? false : @config["load_secrets"]
|
68
|
-
end
|
69
|
-
|
70
|
-
def execute_in_env?(env)
|
71
|
-
!skip_in_envs.include?(env)
|
72
|
-
end
|
73
|
-
|
74
|
-
def allowed_in_env?(env)
|
75
|
-
return false if not_in_envs.include?(env)
|
76
|
-
|
77
|
-
return false if in_envs.any? && !in_envs.include?(env)
|
78
|
-
|
79
|
-
true
|
80
|
-
end
|
81
|
-
|
82
|
-
private
|
83
|
-
|
84
|
-
def to_a
|
85
|
-
command.split(" ").reject(&:nil?) | @args
|
86
|
-
end
|
87
|
-
|
88
|
-
def not_in_envs
|
89
|
-
@config["not_in_envs"] || []
|
90
|
-
end
|
91
|
-
|
92
|
-
def in_envs
|
93
|
-
@config["in_envs"] || []
|
94
|
-
end
|
95
|
-
|
96
|
-
def skip_in_envs
|
97
|
-
@config["skip_in_envs"] || []
|
98
|
-
end
|
99
|
-
|
100
|
-
def perform_shell_expansion?
|
101
|
-
@config["shell_expansion"].nil? ? true : @config["shell_expansion"]
|
102
|
-
end
|
103
|
-
end
|
data/lib/action_list.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActionList
|
4
|
-
class UnknownActionError < StandardError; end
|
5
|
-
|
6
|
-
def initialize(actions_list, args)
|
7
|
-
@actions_list = actions_list
|
8
|
-
@args = args
|
9
|
-
|
10
|
-
process_action_list
|
11
|
-
end
|
12
|
-
|
13
|
-
def get(name)
|
14
|
-
@actions[name]
|
15
|
-
end
|
16
|
-
|
17
|
-
def get_by_alias(name)
|
18
|
-
@aliases[name]
|
19
|
-
end
|
20
|
-
|
21
|
-
def names
|
22
|
-
@actions.keys
|
23
|
-
end
|
24
|
-
|
25
|
-
def aliases
|
26
|
-
@aliases.keys
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def actions_list
|
32
|
-
@actions_list ||= []
|
33
|
-
end
|
34
|
-
|
35
|
-
def process_action_list
|
36
|
-
@actions = {}
|
37
|
-
@aliases = {}
|
38
|
-
|
39
|
-
actions_list.each do |name, config|
|
40
|
-
action = Action.new(name, config, @args)
|
41
|
-
|
42
|
-
@actions[name] = action
|
43
|
-
action.aliases.each do |aliaz|
|
44
|
-
check_duplicate_alias(name, aliaz)
|
45
|
-
@aliases[aliaz] = action
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def check_duplicate_alias(name, aliaz)
|
51
|
-
return if @aliases[aliaz].nil?
|
52
|
-
|
53
|
-
Output.warn("Duplicate alias '#{aliaz}' detected in action '#{name}'.")
|
54
|
-
end
|
55
|
-
end
|
data/lib/action_suggester.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActionSuggester
|
4
|
-
def initialize(dictionary)
|
5
|
-
@dictionary = dictionary
|
6
|
-
end
|
7
|
-
|
8
|
-
def check(word)
|
9
|
-
spellchecker.correct(word)
|
10
|
-
end
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def spellchecker
|
15
|
-
@spellchecker ||= DidYouMean::SpellChecker.new(dictionary: @dictionary)
|
16
|
-
end
|
17
|
-
end
|
data/lib/app_config.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'json'
|
4
|
-
|
5
|
-
class AppConfig
|
6
|
-
class ParsingError < StandardError; end
|
7
|
-
|
8
|
-
class << self
|
9
|
-
def load
|
10
|
-
new(app_config_path).load
|
11
|
-
end
|
12
|
-
|
13
|
-
def default_filename
|
14
|
-
config_path_for(Environment.environment)
|
15
|
-
end
|
16
|
-
|
17
|
-
def config_path_for(env)
|
18
|
-
"config/#{env}/config.json"
|
19
|
-
end
|
20
|
-
|
21
|
-
def app_config_path
|
22
|
-
expand_path(Options.get("config.path") || default_filename)
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def expand_path(path)
|
28
|
-
`echo #{path}`.chomp
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def load
|
33
|
-
config['environment']&.each do |key, value|
|
34
|
-
if Options.get("config.preserve_existing_env_vars") && ENV[key]
|
35
|
-
Output.debug("Environment variable '$#{key}' already set; skipping...")
|
36
|
-
next
|
37
|
-
end
|
38
|
-
|
39
|
-
ENV[key] = value.is_a?(Hash) || value.is_a?(Array) ? value.to_json : value.to_s
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def initialize(filename = "")
|
46
|
-
@filename = filename
|
47
|
-
end
|
48
|
-
|
49
|
-
def config
|
50
|
-
@config ||= if file_contents == ""
|
51
|
-
Output.warn("Config file '#{@filename}' exists but is empty.")
|
52
|
-
{}
|
53
|
-
elsif file_contents
|
54
|
-
YAML.safe_load(file_contents)
|
55
|
-
else
|
56
|
-
{}
|
57
|
-
end
|
58
|
-
rescue YAML::SyntaxError => e
|
59
|
-
raise ParsingError, "#{@filename}: #{e}"
|
60
|
-
end
|
61
|
-
|
62
|
-
def file_contents
|
63
|
-
@file_contents ||= begin
|
64
|
-
File.open(@filename).read
|
65
|
-
rescue Errno::ENOENT
|
66
|
-
nil
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
data/lib/builtin.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Builtin
|
4
|
-
class ArgumentError < StandardError; end
|
5
|
-
|
6
|
-
attr_reader :args, :config
|
7
|
-
|
8
|
-
class << self
|
9
|
-
BUILTIN_DIR = "builtins"
|
10
|
-
|
11
|
-
def description
|
12
|
-
"no description"
|
13
|
-
end
|
14
|
-
|
15
|
-
def class_for(name:)
|
16
|
-
file = file_for(name: name)
|
17
|
-
unless File.exist?(file)
|
18
|
-
require 'require_all'
|
19
|
-
require_rel "builtins"
|
20
|
-
end
|
21
|
-
|
22
|
-
get_const(name: builtin_class_name_for(name: name))
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def get_const(name:)
|
28
|
-
Builtins.const_get(name, false)
|
29
|
-
rescue NameError
|
30
|
-
# no such constant
|
31
|
-
nil
|
32
|
-
end
|
33
|
-
|
34
|
-
def file_for(name:)
|
35
|
-
File.join(File.dirname(__FILE__), BUILTIN_DIR, "#{name}.rb")
|
36
|
-
end
|
37
|
-
|
38
|
-
def builtin_class_name_for(name:)
|
39
|
-
name.capitalize.to_sym
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def initialize(args, config)
|
44
|
-
@args = args
|
45
|
-
@config = config
|
46
|
-
end
|
47
|
-
|
48
|
-
def run
|
49
|
-
raise NotImplementedError
|
50
|
-
end
|
51
|
-
end
|
data/lib/builtins/background.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Builtins
|
4
|
-
class Background < ::Builtin
|
5
|
-
DEFAULT_LOG_FILE_PREFIX = "/tmp/ops_bglog_"
|
6
|
-
|
7
|
-
class << self
|
8
|
-
def description
|
9
|
-
"runs the given command in a background session"
|
10
|
-
end
|
11
|
-
|
12
|
-
def log_filename
|
13
|
-
Options.get("background.log_filename") || "#{DEFAULT_LOG_FILE_PREFIX}#{Ops.project_name}"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def run
|
18
|
-
subprocess = fork do
|
19
|
-
set_bglog_file_permissions
|
20
|
-
run_ops(args)
|
21
|
-
end
|
22
|
-
|
23
|
-
Process.detach(subprocess)
|
24
|
-
|
25
|
-
true
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def set_bglog_file_permissions
|
31
|
-
File.new(Background.log_filename, "w").chmod(0o600)
|
32
|
-
end
|
33
|
-
|
34
|
-
def run_ops(args)
|
35
|
-
Output.notice("Running '#{args.join(' ')}' with stderr and stdout redirected to '#{Background.log_filename}'")
|
36
|
-
$stdout.sync = $stderr.sync = true
|
37
|
-
$stdout.reopen(Background.log_filename, "w")
|
38
|
-
$stderr.reopen($stdout)
|
39
|
-
|
40
|
-
Ops.new(args).run
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# set an alias
|
45
|
-
Bg = Background
|
46
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Builtins
|
4
|
-
class BackgroundLog < Builtin
|
5
|
-
class << self
|
6
|
-
def description
|
7
|
-
"displays the log from the current or most recent background task from this project"
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def run
|
12
|
-
unless File.exist?(Background.log_filename)
|
13
|
-
Output.warn("No background log found at '#{Background.log_filename}'.")
|
14
|
-
return 0
|
15
|
-
end
|
16
|
-
|
17
|
-
Output.notice("Displaying background log '#{Background.log_filename}'...")
|
18
|
-
display_file
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def display_file
|
24
|
-
if args.any?
|
25
|
-
exec("tail #{args.join(' ')} '#{Background.log_filename}'")
|
26
|
-
else
|
27
|
-
exec("cat '#{Background.log_filename}'")
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# set an alias
|
33
|
-
Bglog = BackgroundLog
|
34
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Builtins
|
4
|
-
module Common
|
5
|
-
class UpDown < Builtin
|
6
|
-
class << self
|
7
|
-
def description
|
8
|
-
"attempts to meet dependencies listed in ops.yml"
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def run
|
13
|
-
meet_dependencies
|
14
|
-
|
15
|
-
return true unless fail_on_error?
|
16
|
-
|
17
|
-
deps_to_meet.all?(&:success?)
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def meet_dependencies
|
23
|
-
deps_to_meet.each do |dependency|
|
24
|
-
Output.status("[#{dependency.type}] #{dependency.name}")
|
25
|
-
|
26
|
-
meet_dependency(dependency)
|
27
|
-
|
28
|
-
break if dependency.failure? && exit_on_error?
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def meet_dependency(dependency)
|
33
|
-
handle_dependency(dependency) if !dependency.met? || dependency.always_act?
|
34
|
-
|
35
|
-
if dependency.success?
|
36
|
-
Output.okay
|
37
|
-
else
|
38
|
-
Output.failed
|
39
|
-
Output.error("Error meeting #{dependency.type} dependency '#{dependency.name}':")
|
40
|
-
Output.out(dependency.output)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def deps_to_meet
|
45
|
-
@deps_to_meet ||= dependency_handler.dependencies.select(&:should_meet?)
|
46
|
-
end
|
47
|
-
|
48
|
-
def dependency_handler
|
49
|
-
Helpers::DependencyHandler.new(dependencies)
|
50
|
-
end
|
51
|
-
|
52
|
-
def dependencies
|
53
|
-
return @config["dependencies"] if @args.empty?
|
54
|
-
|
55
|
-
@config["dependencies"].select { |dep, _names| @args.include?(dep) }
|
56
|
-
end
|
57
|
-
|
58
|
-
def fail_on_error?
|
59
|
-
Options.get("up.fail_on_error") || false
|
60
|
-
end
|
61
|
-
|
62
|
-
def exit_on_error?
|
63
|
-
Options.get("up.exit_on_error") || false
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
data/lib/builtins/countdown.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'concurrent'
|
4
|
-
|
5
|
-
module Builtins
|
6
|
-
class Countdown < Builtin
|
7
|
-
USAGE_STRING = "Usage: ops countdown <seconds>"
|
8
|
-
|
9
|
-
class << self
|
10
|
-
def description
|
11
|
-
"Like `sleep`, but displays time remaining in terminal."
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def run
|
16
|
-
check_args
|
17
|
-
|
18
|
-
timer_task.execute
|
19
|
-
|
20
|
-
while timer_task.running?
|
21
|
-
sleep(1)
|
22
|
-
timer_task.shutdown if task_complete?
|
23
|
-
end
|
24
|
-
Output.out("\rCountdown complete after #{sleep_seconds}s.")
|
25
|
-
|
26
|
-
true
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def check_args
|
32
|
-
check_arg_count
|
33
|
-
check_arg_is_positive_int
|
34
|
-
end
|
35
|
-
|
36
|
-
def check_arg_count
|
37
|
-
raise Builtin::ArgumentError, USAGE_STRING unless args.length == 1
|
38
|
-
end
|
39
|
-
|
40
|
-
def check_arg_is_positive_int
|
41
|
-
raise Builtin::ArgumentError, USAGE_STRING unless sleep_seconds.positive?
|
42
|
-
# raised when the arg is not an int
|
43
|
-
rescue ::ArgumentError
|
44
|
-
raise Builtin::ArgumentError, USAGE_STRING
|
45
|
-
end
|
46
|
-
|
47
|
-
def timer_task
|
48
|
-
@timer_task ||= Concurrent::TimerTask.new(run_now: true, execution_interval: 1) do
|
49
|
-
Output.print("\r \r#{seconds_left}")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def sleep_seconds
|
54
|
-
Integer(args.first)
|
55
|
-
end
|
56
|
-
|
57
|
-
def task_start_time
|
58
|
-
@task_start_time ||= Time.now
|
59
|
-
end
|
60
|
-
|
61
|
-
def task_end_time
|
62
|
-
@task_end_time ||= task_start_time + sleep_seconds
|
63
|
-
end
|
64
|
-
|
65
|
-
def task_complete?
|
66
|
-
Time.now > task_end_time
|
67
|
-
end
|
68
|
-
|
69
|
-
def seconds_left
|
70
|
-
Integer(task_end_time - Time.now + 1)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
data/lib/builtins/down.rb
DELETED
data/lib/builtins/env.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Builtins
|
4
|
-
class Env < Builtin
|
5
|
-
class << self
|
6
|
-
def description
|
7
|
-
"prints the current environment, e.g. 'dev', 'production', 'staging', etc."
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def run
|
12
|
-
Output.print(environment)
|
13
|
-
|
14
|
-
true
|
15
|
-
end
|
16
|
-
|
17
|
-
def environment
|
18
|
-
ENV['environment']
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
data/lib/builtins/envdiff.rb
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Builtins
|
4
|
-
class Envdiff < Builtin
|
5
|
-
class << self
|
6
|
-
def description
|
7
|
-
"compares keys present in config and secrets between different environments"
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def run
|
12
|
-
check_args
|
13
|
-
|
14
|
-
if source_only_keys.empty? && dest_only_keys.empty?
|
15
|
-
Output.out("Environments '#{source_env}' and '#{dest_env}' define the same #{source_keys.length} key(s).")
|
16
|
-
return
|
17
|
-
end
|
18
|
-
|
19
|
-
output_key_summary(source_only_keys, source_env, dest_env) if source_only_keys.any?
|
20
|
-
output_key_summary(dest_only_keys, dest_env, source_env) if dest_only_keys.any?
|
21
|
-
|
22
|
-
true
|
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
|
-
tagged_config_keys_for(env) + tagged_secrets_keys_for(env)
|
53
|
-
end
|
54
|
-
|
55
|
-
def tagged_config_keys_for(env)
|
56
|
-
config_keys_for(env).map do |key|
|
57
|
-
"[CONFIG] #{key}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def tagged_secrets_keys_for(env)
|
62
|
-
secrets_keys_for(env).map do |key|
|
63
|
-
"[SECRET] #{key}"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def config_keys_for(env)
|
68
|
-
(config_for(env)["environment"]&.keys || []) - ignored_keys
|
69
|
-
end
|
70
|
-
|
71
|
-
def secrets_keys_for(env)
|
72
|
-
(secrets_for(env)["environment"]&.keys || []) - ignored_keys
|
73
|
-
end
|
74
|
-
|
75
|
-
def config_for(env)
|
76
|
-
YAML.load_file(config_path_for(env))
|
77
|
-
end
|
78
|
-
|
79
|
-
def secrets_for(env)
|
80
|
-
YAML.load_file(secrets_path_for(env))
|
81
|
-
end
|
82
|
-
|
83
|
-
def check_args
|
84
|
-
raise Builtin::ArgumentError, "Usage: ops envdiff <env_one> <env_two>" unless args.length == 2
|
85
|
-
|
86
|
-
check_environment(source_env)
|
87
|
-
check_environment(dest_env)
|
88
|
-
end
|
89
|
-
|
90
|
-
def source_env
|
91
|
-
args[0]
|
92
|
-
end
|
93
|
-
|
94
|
-
def dest_env
|
95
|
-
args[1]
|
96
|
-
end
|
97
|
-
|
98
|
-
def check_environment(name)
|
99
|
-
raise_missing_file_error(config_path_for(name)) unless config_file_exists?(name)
|
100
|
-
raise_missing_file_error(secrets_path_for(name)) unless secrets_file_exists?(name)
|
101
|
-
end
|
102
|
-
|
103
|
-
def raise_missing_file_error(path)
|
104
|
-
raise Builtin::ArgumentError, "File '#{path}' does not exist."
|
105
|
-
end
|
106
|
-
|
107
|
-
def config_file_exists?(env)
|
108
|
-
File.exist?(config_path_for(env))
|
109
|
-
end
|
110
|
-
|
111
|
-
def secrets_file_exists?(env)
|
112
|
-
File.exist?(secrets_path_for(env))
|
113
|
-
end
|
114
|
-
|
115
|
-
def config_path_for(env)
|
116
|
-
AppConfig.config_path_for(env)
|
117
|
-
end
|
118
|
-
|
119
|
-
def secrets_path_for(env)
|
120
|
-
Secrets.config_path_for(env)
|
121
|
-
end
|
122
|
-
|
123
|
-
def ignored_keys
|
124
|
-
Options.get("envdiff.ignored_keys") || []
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
data/lib/builtins/exec.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Builtins
|
4
|
-
class Exec < Builtin
|
5
|
-
class << self
|
6
|
-
def description
|
7
|
-
"executes the given command in the `ops` environment, i.e. with environment variables set"
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def run
|
12
|
-
Secrets.load if Options.get("exec.load_secrets")
|
13
|
-
|
14
|
-
if args.any?
|
15
|
-
Output.error(Profiler.summary) if Profiler.summary
|
16
|
-
Kernel.exec(args.join(" "))
|
17
|
-
else
|
18
|
-
Output.error("Usage: ops exec '<command>'")
|
19
|
-
|
20
|
-
false
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|