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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/bin/ops +4 -40
  3. data/build/darwin_amd64/ops +0 -0
  4. data/build/darwin_arm64/ops +0 -0
  5. data/build/linux_amd64/ops +0 -0
  6. metadata +12 -224
  7. data/Gemfile +0 -30
  8. data/bin/benchmark +0 -185
  9. data/bin/print_config +0 -4
  10. data/bin/print_secrets +0 -4
  11. data/bin/tag +0 -16
  12. data/etc/ops.template.yml +0 -13
  13. data/etc/ruby.template.yml +0 -37
  14. data/etc/terraform.template.yml +0 -36
  15. data/lib/action.rb +0 -103
  16. data/lib/action_list.rb +0 -55
  17. data/lib/action_suggester.rb +0 -17
  18. data/lib/app_config.rb +0 -69
  19. data/lib/builtin.rb +0 -51
  20. data/lib/builtins/background.rb +0 -46
  21. data/lib/builtins/background_log.rb +0 -34
  22. data/lib/builtins/common/up_down.rb +0 -67
  23. data/lib/builtins/countdown.rb +0 -73
  24. data/lib/builtins/down.rb +0 -9
  25. data/lib/builtins/env.rb +0 -21
  26. data/lib/builtins/envdiff.rb +0 -127
  27. data/lib/builtins/exec.rb +0 -24
  28. data/lib/builtins/help.rb +0 -66
  29. data/lib/builtins/helpers/dependency_handler.rb +0 -27
  30. data/lib/builtins/helpers/enumerator.rb +0 -34
  31. data/lib/builtins/init.rb +0 -64
  32. data/lib/builtins/up.rb +0 -9
  33. data/lib/builtins/version.rb +0 -17
  34. data/lib/dependencies/apk.rb +0 -24
  35. data/lib/dependencies/apt.rb +0 -42
  36. data/lib/dependencies/brew.rb +0 -22
  37. data/lib/dependencies/cask.rb +0 -13
  38. data/lib/dependencies/custom.rb +0 -45
  39. data/lib/dependencies/dir.rb +0 -22
  40. data/lib/dependencies/docker.rb +0 -17
  41. data/lib/dependencies/gem.rb +0 -36
  42. data/lib/dependencies/helpers/apt_cache_policy.rb +0 -43
  43. data/lib/dependencies/pip.rb +0 -32
  44. data/lib/dependencies/snap.rb +0 -32
  45. data/lib/dependencies/sshkey.rb +0 -121
  46. data/lib/dependencies/versioned_dependency.rb +0 -25
  47. data/lib/dependency.rb +0 -69
  48. data/lib/environment.rb +0 -47
  49. data/lib/executor.rb +0 -20
  50. data/lib/forward.rb +0 -15
  51. data/lib/forwards.rb +0 -16
  52. data/lib/hook_handler.rb +0 -41
  53. data/lib/ops.rb +0 -129
  54. data/lib/options.rb +0 -22
  55. data/lib/output.rb +0 -71
  56. data/lib/profiler.rb +0 -47
  57. data/lib/runner.rb +0 -110
  58. data/lib/secrets.rb +0 -55
  59. data/lib/version.rb +0 -38
  60. data/loader.rb +0 -10
  61. 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
@@ -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
@@ -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
@@ -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
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Builtins
4
- class Down < Common::UpDown
5
- def handle_dependency(dependency)
6
- dependency.unmeet
7
- end
8
- end
9
- end
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
@@ -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