ops_team 1.21.1 → 2.0.0.rc3
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/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
@@ -1,25 +0,0 @@
|
|
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/dependency.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'open3'
|
4
|
-
require 'English'
|
5
|
-
|
6
|
-
class Dependency
|
7
|
-
DESCRIPTION_TYPE_WIDTH = 8
|
8
|
-
|
9
|
-
attr_reader :name
|
10
|
-
|
11
|
-
def initialize(name)
|
12
|
-
@name = name
|
13
|
-
end
|
14
|
-
|
15
|
-
def met?
|
16
|
-
raise NotImplementedError
|
17
|
-
end
|
18
|
-
|
19
|
-
def meet
|
20
|
-
raise NotImplementedError
|
21
|
-
end
|
22
|
-
|
23
|
-
def unmeet
|
24
|
-
raise NotImplementedError
|
25
|
-
end
|
26
|
-
|
27
|
-
# should_meet? can be used to implement dependencies that should only be met on some platforms,
|
28
|
-
# e.g. brew on Macs and apt on Linux
|
29
|
-
# it can be used to base a decision on anything else that can be read from the environment at
|
30
|
-
# runtime
|
31
|
-
def should_meet?
|
32
|
-
true
|
33
|
-
end
|
34
|
-
|
35
|
-
# if true, this type of resource must always have `meet` and `unmeet` called;
|
36
|
-
# useful for resources that can't easily be checked to see if they're met
|
37
|
-
def always_act?
|
38
|
-
false
|
39
|
-
end
|
40
|
-
|
41
|
-
def type
|
42
|
-
self.class.name.split('::').last
|
43
|
-
end
|
44
|
-
|
45
|
-
def success?
|
46
|
-
@executor.nil? ? true : @executor.success?
|
47
|
-
end
|
48
|
-
|
49
|
-
def failure?
|
50
|
-
!success?
|
51
|
-
end
|
52
|
-
|
53
|
-
def output
|
54
|
-
@executor&.output
|
55
|
-
end
|
56
|
-
|
57
|
-
def exit_code
|
58
|
-
@executor&.exit_code
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
def execute(cmd)
|
64
|
-
@executor = Executor.new(cmd)
|
65
|
-
@executor.execute
|
66
|
-
|
67
|
-
@executor.success?
|
68
|
-
end
|
69
|
-
end
|
data/lib/environment.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Environment
|
4
|
-
class << self
|
5
|
-
def environment
|
6
|
-
return 'dev' if ENV['environment'].nil? || ENV['environment'].empty?
|
7
|
-
|
8
|
-
ENV['environment']
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(env_hash, config_path)
|
13
|
-
@env_hash = env_hash
|
14
|
-
@config_path = config_path
|
15
|
-
end
|
16
|
-
|
17
|
-
def set_variables
|
18
|
-
set_ops_variables
|
19
|
-
set_environment_aliases
|
20
|
-
set_configured_variables
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def set_ops_variables
|
26
|
-
ENV["OPS_YML_DIR"] = File.dirname(@config_path)
|
27
|
-
ENV["OPS_VERSION"] = Version.version.to_s
|
28
|
-
ENV["OPS_SECRETS_FILE"] = Secrets.app_config_path
|
29
|
-
ENV["OPS_CONFIG_FILE"] = AppConfig.app_config_path
|
30
|
-
end
|
31
|
-
|
32
|
-
def set_environment_aliases
|
33
|
-
environment_aliases.each do |alias_name|
|
34
|
-
ENV[alias_name] = Environment.environment
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def environment_aliases
|
39
|
-
Options.get("environment_aliases") || ['environment']
|
40
|
-
end
|
41
|
-
|
42
|
-
def set_configured_variables
|
43
|
-
@env_hash.each do |key, value|
|
44
|
-
ENV[key] = `echo #{value}`.chomp
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
data/lib/executor.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Executor
|
4
|
-
attr_reader :output, :exit_code
|
5
|
-
|
6
|
-
def initialize(command)
|
7
|
-
@command = command
|
8
|
-
end
|
9
|
-
|
10
|
-
def execute
|
11
|
-
@output, status = Open3.capture2e(@command)
|
12
|
-
@exit_code = status.exitstatus
|
13
|
-
|
14
|
-
success?
|
15
|
-
end
|
16
|
-
|
17
|
-
def success?
|
18
|
-
@exit_code.nil? ? true : @exit_code.zero?
|
19
|
-
end
|
20
|
-
end
|
data/lib/forward.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Forward
|
4
|
-
def initialize(dir, args)
|
5
|
-
@dir = dir
|
6
|
-
@args = args
|
7
|
-
end
|
8
|
-
|
9
|
-
def run
|
10
|
-
Output.notice("Forwarding 'ops #{@args.join(" ")}' to '#{@dir}/'...")
|
11
|
-
|
12
|
-
Dir.chdir(@dir)
|
13
|
-
Ops.new(@args).run
|
14
|
-
end
|
15
|
-
end
|
data/lib/forwards.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Forwards
|
4
|
-
def initialize(config, args = [])
|
5
|
-
@config = config
|
6
|
-
@args = args
|
7
|
-
end
|
8
|
-
|
9
|
-
def get(name)
|
10
|
-
Forward.new(forwards[name], @args) if forwards[name]
|
11
|
-
end
|
12
|
-
|
13
|
-
def forwards
|
14
|
-
@forwards ||= @config["forwards"] || {}
|
15
|
-
end
|
16
|
-
end
|
data/lib/hook_handler.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class HookHandler
|
4
|
-
class HookConfigError < StandardError; end
|
5
|
-
|
6
|
-
class HookExecError < StandardError; end
|
7
|
-
|
8
|
-
def initialize(config)
|
9
|
-
@config = config
|
10
|
-
end
|
11
|
-
|
12
|
-
def do_hooks(name)
|
13
|
-
raise HookConfigError, "'hooks.#{name}' must be a list" unless hooks(name).is_a?(Array)
|
14
|
-
|
15
|
-
execute_hooks(name)
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def hooks(name)
|
21
|
-
@config.dig("hooks", name) || []
|
22
|
-
end
|
23
|
-
|
24
|
-
def execute_hooks(name)
|
25
|
-
hooks(name).each do |hook|
|
26
|
-
Output.notice("Running #{name} hook: #{hook}")
|
27
|
-
output, exit_code = execute_hook(hook)
|
28
|
-
|
29
|
-
next if exit_code.zero?
|
30
|
-
|
31
|
-
raise HookExecError, "#{name} hook '#{hook}' failed with exit code #{exit_code}:\n#{output}"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def execute_hook(name)
|
36
|
-
executor = Executor.new(name)
|
37
|
-
executor.execute
|
38
|
-
|
39
|
-
[executor.output, executor.exit_code]
|
40
|
-
end
|
41
|
-
end
|
data/lib/ops.rb
DELETED
@@ -1,129 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
Profiler.measure("ops:requires_external") do
|
5
|
-
require 'yaml'
|
6
|
-
require "rubygems"
|
7
|
-
end
|
8
|
-
|
9
|
-
Profiler.measure("ops:requires_internal") do
|
10
|
-
end
|
11
|
-
|
12
|
-
CONFIG_FILES = ["ops.yaml", "ops.yml"].freeze
|
13
|
-
|
14
|
-
# executes commands based on local `ops.yml`
|
15
|
-
class Ops
|
16
|
-
INVALID_SYNTAX_EXIT_CODE = 64
|
17
|
-
UNKNOWN_ACTION_EXIT_CODE = 65
|
18
|
-
ERROR_LOADING_APP_CONFIG_EXIT_CODE = 66
|
19
|
-
MIN_VERSION_NOT_MET_EXIT_CODE = 67
|
20
|
-
ACTION_CONFIG_ERROR_EXIT_CODE = 68
|
21
|
-
BUILTIN_SYNTAX_ERROR_EXIT_CODE = 69
|
22
|
-
ACTION_NOT_ALLOWED_IN_ENV_EXIT_CODE = 70
|
23
|
-
|
24
|
-
RECOMMEND_HELP_TEXT = "Run 'ops help' for a list of builtins and actions."
|
25
|
-
|
26
|
-
class << self
|
27
|
-
def project_name
|
28
|
-
File.basename(::Dir.pwd)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def initialize(argv, config_file: nil)
|
33
|
-
@action_name = argv[0]
|
34
|
-
@args = argv[1..-1]
|
35
|
-
@config_file = config_file || CONFIG_FILES.find { |file| File.exist?(file) } || "ops.yml"
|
36
|
-
|
37
|
-
Options.set(config["options"] || {})
|
38
|
-
end
|
39
|
-
|
40
|
-
# rubocop:disable Metrics/MethodLength
|
41
|
-
# better to have all the rescues in one place
|
42
|
-
def run
|
43
|
-
# "return" is here to allow specs to stub "exit" without executing everything after it
|
44
|
-
return exit(INVALID_SYNTAX_EXIT_CODE) unless syntax_valid?
|
45
|
-
return exit(MIN_VERSION_NOT_MET_EXIT_CODE) unless min_version_met?
|
46
|
-
|
47
|
-
Profiler.measure("runner:run") do
|
48
|
-
runner.run
|
49
|
-
end
|
50
|
-
rescue Runner::UnknownActionError => e
|
51
|
-
Output.error(e.to_s)
|
52
|
-
Output.out(RECOMMEND_HELP_TEXT) unless print_did_you_mean
|
53
|
-
exit(UNKNOWN_ACTION_EXIT_CODE)
|
54
|
-
rescue Runner::ActionConfigError => e
|
55
|
-
Output.error("Error(s) running action '#{@action_name}': #{e}")
|
56
|
-
exit(ACTION_CONFIG_ERROR_EXIT_CODE)
|
57
|
-
rescue Builtin::ArgumentError => e
|
58
|
-
Output.error("Error running builtin '#{@action_name}': #{e}")
|
59
|
-
exit(BUILTIN_SYNTAX_ERROR_EXIT_CODE)
|
60
|
-
rescue AppConfig::ParsingError => e
|
61
|
-
Output.error("Error parsing app config: #{e}")
|
62
|
-
exit(ERROR_LOADING_APP_CONFIG_EXIT_CODE)
|
63
|
-
rescue Runner::NotAllowedInEnvError => e
|
64
|
-
Output.error("Error running action #{@action_name}: #{e}")
|
65
|
-
exit(ACTION_NOT_ALLOWED_IN_ENV_EXIT_CODE)
|
66
|
-
end
|
67
|
-
# rubocop:enable Metrics/MethodLength
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def syntax_valid?
|
72
|
-
return true unless @action_name.nil?
|
73
|
-
|
74
|
-
Output.error("Usage: ops <action>")
|
75
|
-
Output.out(RECOMMEND_HELP_TEXT)
|
76
|
-
false
|
77
|
-
end
|
78
|
-
|
79
|
-
def print_did_you_mean
|
80
|
-
Output.out("Did you mean '#{runner.suggestions.join(", ")}'?") if runner.suggestions.any?
|
81
|
-
|
82
|
-
runner.suggestions.any?
|
83
|
-
end
|
84
|
-
|
85
|
-
def min_version_met?
|
86
|
-
return true unless min_version
|
87
|
-
|
88
|
-
if Version.min_version_met?(min_version)
|
89
|
-
true
|
90
|
-
else
|
91
|
-
Output.error("ops.yml specifies minimum version of #{min_version}, but ops version is #{Version.version}")
|
92
|
-
false
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def min_version
|
97
|
-
config["min_version"]
|
98
|
-
end
|
99
|
-
|
100
|
-
def runner
|
101
|
-
@runner ||= Runner.new(@action_name, @args, config, config_file_absolute_path)
|
102
|
-
end
|
103
|
-
|
104
|
-
def config
|
105
|
-
@config ||= if config_file_exists?
|
106
|
-
parsed_config_contents
|
107
|
-
else
|
108
|
-
Output.warn("File '#{@config_file}' does not exist.") unless @action_name == "init"
|
109
|
-
{}
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def parsed_config_contents
|
114
|
-
YAML.load_file(@config_file)
|
115
|
-
rescue StandardError => e
|
116
|
-
Output.warn("Error parsing '#{@config_file}': #{e}")
|
117
|
-
{}
|
118
|
-
end
|
119
|
-
|
120
|
-
def config_file_exists?
|
121
|
-
File.exist?(@config_file)
|
122
|
-
end
|
123
|
-
|
124
|
-
def config_file_absolute_path
|
125
|
-
File.expand_path(@config_file)
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
Ops.new(ARGV).run if $PROGRAM_NAME == __FILE__
|
data/lib/options.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Options
|
4
|
-
class << self
|
5
|
-
def get(path)
|
6
|
-
env_var = ENV[env_var(path)]
|
7
|
-
return YAML.safe_load(env_var) unless env_var.nil?
|
8
|
-
|
9
|
-
@options&.dig(*path.split('.'))
|
10
|
-
end
|
11
|
-
|
12
|
-
def set(options)
|
13
|
-
@options = options
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def env_var(path)
|
19
|
-
"OPS__#{path.upcase.gsub(".", "__")}"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
data/lib/output.rb
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'colorize'
|
4
|
-
|
5
|
-
class Output
|
6
|
-
@out = STDOUT
|
7
|
-
@err = STDERR
|
8
|
-
|
9
|
-
STATUS_WIDTH = "50"
|
10
|
-
|
11
|
-
OKAY = "OK"
|
12
|
-
SKIPPED = "SKIPPED"
|
13
|
-
FAILED = "FAILED"
|
14
|
-
|
15
|
-
# used to silence output, e.g. in testing
|
16
|
-
class DummyOutput
|
17
|
-
def print(*_); end
|
18
|
-
|
19
|
-
def puts(*_); end
|
20
|
-
end
|
21
|
-
|
22
|
-
class << self
|
23
|
-
def status(name)
|
24
|
-
@out.print(format("%-#{STATUS_WIDTH}<name>s ", name: name))
|
25
|
-
end
|
26
|
-
|
27
|
-
def okay
|
28
|
-
@out.puts(OKAY.green)
|
29
|
-
end
|
30
|
-
|
31
|
-
def skipped
|
32
|
-
@out.puts(SKIPPED.yellow)
|
33
|
-
end
|
34
|
-
|
35
|
-
def failed
|
36
|
-
@out.puts(FAILED.red)
|
37
|
-
end
|
38
|
-
|
39
|
-
def warn(msg)
|
40
|
-
@err.puts(msg.yellow)
|
41
|
-
end
|
42
|
-
|
43
|
-
alias notice warn
|
44
|
-
|
45
|
-
def error(msg)
|
46
|
-
@err.puts(msg.red)
|
47
|
-
end
|
48
|
-
|
49
|
-
def out(msg)
|
50
|
-
@out.puts(msg)
|
51
|
-
end
|
52
|
-
|
53
|
-
def print(msg)
|
54
|
-
@out.print(msg)
|
55
|
-
end
|
56
|
-
|
57
|
-
def debug(msg)
|
58
|
-
return unless ENV["OPS_DEBUG_OUTPUT"]
|
59
|
-
|
60
|
-
@err.puts(msg.blue)
|
61
|
-
end
|
62
|
-
|
63
|
-
def silence
|
64
|
-
@out = @err = dummy_output
|
65
|
-
end
|
66
|
-
|
67
|
-
def dummy_output
|
68
|
-
@dummy_output ||= DummyOutput.new
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
data/lib/profiler.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Profiler
|
4
|
-
INDENT = " "
|
5
|
-
|
6
|
-
@measurements = {}
|
7
|
-
|
8
|
-
class << self
|
9
|
-
attr_reader :measurements
|
10
|
-
|
11
|
-
def measure(tag)
|
12
|
-
start = time_now
|
13
|
-
result = yield
|
14
|
-
add_measurement(tag, time_now - start)
|
15
|
-
|
16
|
-
result
|
17
|
-
end
|
18
|
-
|
19
|
-
def add_measurement(tag, seconds)
|
20
|
-
return unless profiling?
|
21
|
-
|
22
|
-
@measurements[tag] ||= []
|
23
|
-
|
24
|
-
@measurements[tag] << seconds
|
25
|
-
end
|
26
|
-
|
27
|
-
def summary
|
28
|
-
return unless profiling?
|
29
|
-
|
30
|
-
@summary ||= measurements.reverse_each.each_with_object([]) do |(tag, values), output|
|
31
|
-
output << "#{tag}:\n"
|
32
|
-
values.sort.reverse.each do |value|
|
33
|
-
value_str = format("%.3f", value * 1000)
|
34
|
-
output << format("%<indent>s%9<value>sms\n", indent: INDENT, value: value_str)
|
35
|
-
end
|
36
|
-
end.join
|
37
|
-
end
|
38
|
-
|
39
|
-
def profiling?
|
40
|
-
!ENV["OPS_PROFILE"].nil?
|
41
|
-
end
|
42
|
-
|
43
|
-
def time_now
|
44
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
data/lib/runner.rb
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Builtins
|
4
|
-
end
|
5
|
-
|
6
|
-
class Runner
|
7
|
-
class UnknownActionError < StandardError; end
|
8
|
-
|
9
|
-
class ActionConfigError < StandardError; end
|
10
|
-
|
11
|
-
class NotAllowedInEnvError < StandardError; end
|
12
|
-
|
13
|
-
def initialize(action_name, args, config, config_path)
|
14
|
-
@action_name = action_name
|
15
|
-
@args = args
|
16
|
-
@config = config
|
17
|
-
@config_path = config_path
|
18
|
-
end
|
19
|
-
|
20
|
-
def run
|
21
|
-
return forward.run if forward
|
22
|
-
|
23
|
-
do_before_all
|
24
|
-
|
25
|
-
return builtin.run if builtin
|
26
|
-
|
27
|
-
raise UnknownActionError, "Unknown action: #{@action_name}" unless action
|
28
|
-
raise ActionConfigError, action.config_errors.join("; ") unless action.config_valid?
|
29
|
-
|
30
|
-
do_before_action
|
31
|
-
|
32
|
-
run_action
|
33
|
-
end
|
34
|
-
|
35
|
-
def suggestions
|
36
|
-
@suggestions ||= ActionSuggester.new(action_list.names + action_list.aliases + builtin_names).check(@action_name)
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def do_before_all
|
42
|
-
AppConfig.load
|
43
|
-
Secrets.load if action&.load_secrets?
|
44
|
-
environment.set_variables
|
45
|
-
end
|
46
|
-
|
47
|
-
def do_before_action
|
48
|
-
return if ENV["OPS_RUNNING"] || action.skip_hooks?("before")
|
49
|
-
|
50
|
-
# this prevents before hooks from running in ops executed by ops
|
51
|
-
ENV["OPS_RUNNING"] = "1"
|
52
|
-
hook_handler.do_hooks("before")
|
53
|
-
end
|
54
|
-
|
55
|
-
def hook_handler
|
56
|
-
@hook_handler ||= HookHandler.new(@config)
|
57
|
-
end
|
58
|
-
|
59
|
-
def builtin
|
60
|
-
Profiler.measure("runner:require_builtin") do
|
61
|
-
@builtin ||= Builtin.class_for(name: @action_name)&.new(@args, @config)
|
62
|
-
end
|
63
|
-
rescue NameError
|
64
|
-
# this means there isn't a builtin with that name in that module
|
65
|
-
nil
|
66
|
-
end
|
67
|
-
|
68
|
-
def builtin_names
|
69
|
-
Builtins.constants.select { |c| Builtins.const_get(c).is_a? Class }.map(&:downcase)
|
70
|
-
end
|
71
|
-
|
72
|
-
def forward
|
73
|
-
@forward ||= Forwards.new(@config, @args).get(@action_name)
|
74
|
-
end
|
75
|
-
|
76
|
-
def run_action
|
77
|
-
unless action.allowed_in_env?(Environment.environment)
|
78
|
-
raise NotAllowedInEnvError, "Action not allowed in #{Environment.environment} environment."
|
79
|
-
end
|
80
|
-
|
81
|
-
unless action.execute_in_env?(Environment.environment)
|
82
|
-
Output.warn("Skipping action '#{action.name}' in environment #{Environment.environment}.")
|
83
|
-
return true
|
84
|
-
end
|
85
|
-
|
86
|
-
Output.notice("Running '#{action}' in environment '#{ENV['environment']}'...")
|
87
|
-
action.run
|
88
|
-
end
|
89
|
-
|
90
|
-
def action
|
91
|
-
return action_list.get(@action_name) if action_list.get(@action_name)
|
92
|
-
return action_list.get_by_alias(@action_name) if action_list.get_by_alias(@action_name)
|
93
|
-
end
|
94
|
-
|
95
|
-
def action_list
|
96
|
-
@action_list ||= begin
|
97
|
-
Output.warn("'ops.yml' has no 'actions' defined.") if @config.any? && @config["actions"].nil?
|
98
|
-
|
99
|
-
ActionList.new(@config["actions"], @args)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def env_vars
|
104
|
-
@config.dig("options", "environment") || {}
|
105
|
-
end
|
106
|
-
|
107
|
-
def environment
|
108
|
-
@environment ||= Environment.new(env_vars, @config_path)
|
109
|
-
end
|
110
|
-
end
|
data/lib/secrets.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'json'
|
4
|
-
require 'open3'
|
5
|
-
|
6
|
-
class Secrets < AppConfig
|
7
|
-
class << self
|
8
|
-
def default_filename
|
9
|
-
config_path_for(Environment.environment)
|
10
|
-
end
|
11
|
-
|
12
|
-
def config_path_for(env)
|
13
|
-
File.exist?(ejson_path_for(env)) ? ejson_path_for(env) : json_path_for(env)
|
14
|
-
end
|
15
|
-
|
16
|
-
def app_config_path
|
17
|
-
expand_path(Options.get("secrets.path") || default_filename)
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
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
|
-
end
|
30
|
-
|
31
|
-
def initialize(filename = "")
|
32
|
-
@filename = filename.empty? ? Secrets.default_filename : actual_filename_for(filename)
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def actual_filename_for(filename)
|
38
|
-
File.exist?(filename) ? filename : filename.sub(".ejson", ".json")
|
39
|
-
end
|
40
|
-
|
41
|
-
def file_contents
|
42
|
-
@file_contents ||= @filename.match(/\.ejson$/) ? ejson_contents : super
|
43
|
-
end
|
44
|
-
|
45
|
-
def ejson_contents
|
46
|
-
@ejson_contents ||= begin
|
47
|
-
out, err, _status = Open3.capture3("ejson decrypt #{@filename}")
|
48
|
-
|
49
|
-
# TODO: err is only nil in testing, but I can't figure out why the stubbing isn't working
|
50
|
-
raise ParsingError, "#{@filename}: #{err}" unless err.nil? || err.empty?
|
51
|
-
|
52
|
-
out
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
data/lib/version.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "rubygems"
|
4
|
-
|
5
|
-
class Version
|
6
|
-
GEMSPEC_FILE = "#{__dir__}/../ops_team.gemspec"
|
7
|
-
|
8
|
-
class << self
|
9
|
-
# these class methods exist because I don't want to have to call `Version.new.version` elsewhere
|
10
|
-
def version
|
11
|
-
new.send(:version)
|
12
|
-
end
|
13
|
-
|
14
|
-
def min_version_met?(min_version)
|
15
|
-
new.send(:min_version_met?, min_version)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
# these instance methods exist so that I don't have to clear class variables between tests
|
22
|
-
def version
|
23
|
-
unless gemspec
|
24
|
-
Output.error("Unable to load gemspec at '#{GEMSPEC_FILE}")
|
25
|
-
return nil
|
26
|
-
end
|
27
|
-
|
28
|
-
gemspec.version
|
29
|
-
end
|
30
|
-
|
31
|
-
def min_version_met?(min_version)
|
32
|
-
Gem::Version.new(version) >= Gem::Version.new(min_version)
|
33
|
-
end
|
34
|
-
|
35
|
-
def gemspec
|
36
|
-
@gemspec ||= Gem::Specification.load(GEMSPEC_FILE)
|
37
|
-
end
|
38
|
-
end
|