ops_team 0.18.1 → 1.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d591b58dad032824721105b4ce3e45c63ef40078273d77fbb85ddf50c3224f27
4
- data.tar.gz: f3f72de653d0ad2d3b87ef1ac6c75bfe0543b6030b37954fae1ddf4dd2981e17
3
+ metadata.gz: bf2a309a88bc396994795bca23a308043e8e8ec6c16a5e7b85baf0b66e15ed83
4
+ data.tar.gz: 526857c4d776fddf9d20d96c81cf4ab6905a364601d32fb5989467439f366aea
5
5
  SHA512:
6
- metadata.gz: 42df63cce2068a86cbe127da74fdf4af2dfb33f3bb4d7ed176354566b11adc1ba3adbbc941b0df8440bcdc1cfaf76f4e9e7182c41618cee1ca9695d8fa1bdca7
7
- data.tar.gz: 451205a2bde8e20689f2b5b1b76d60f3cf3d2db5d74d18c2f71cc21219863bc4a87373c5980833e90d647314eb937b4dc02f13ad940636603d7dd37faf4764e4
6
+ metadata.gz: 815571122a732fcc85046f386ae9918c961033dc1c6141ad8d32334b2beb09ee9775b83640dad88d100d67a463468667a9dd9bbc5875e2b8612dc64fcc0d53e0
7
+ data.tar.gz: 6c4146afc51d45f1f80f91c57093750160589d0d6bf89cd6df2c2f79f6d58e30525edee2a122e3b0059d7bfd2a2f0f2a1b0e3f4ceefe4f1373ad0c1892fead77
@@ -17,8 +17,6 @@ class Action
17
17
  raise NotAllowedInEnvError, "Action not allowed in #{Environment.environment} environment."
18
18
  end
19
19
 
20
- Secrets.load if load_secrets?
21
-
22
20
  Kernel.exec(to_s)
23
21
  end
24
22
 
@@ -56,12 +54,12 @@ class Action
56
54
  end
57
55
  end
58
56
 
59
- private
60
-
61
57
  def load_secrets?
62
- @config["load_secrets"]
58
+ @config["load_secrets"].nil? ? false : @config["load_secrets"]
63
59
  end
64
60
 
61
+ private
62
+
65
63
  def not_in_envs
66
64
  @config["not_in_envs"] || []
67
65
  end
@@ -3,12 +3,15 @@
3
3
  require 'colorize'
4
4
 
5
5
  require 'builtin'
6
+ require 'forwards'
6
7
 
7
8
  module Builtins
8
9
  class Help < Builtin
10
+ NAME_WIDTH = 35
11
+
9
12
  class << self
10
13
  def description
11
- "displays available builtins and actions"
14
+ "displays available builtins, actions, and forwards"
12
15
  end
13
16
  end
14
17
 
@@ -16,15 +19,24 @@ module Builtins
16
19
  Output.out("Builtins:")
17
20
  Output.out(" #{builtins.join("\n ")}")
18
21
  Output.out("")
22
+ Output.out("Forwards:")
23
+ Output.out(" #{forwards.join("\n ")}")
24
+ Output.out("")
19
25
  Output.out("Actions:")
20
26
  Output.out(" #{actions.join("\n ")}")
21
27
  end
22
28
 
23
29
  private
24
30
 
31
+ def forwards
32
+ Forwards.new(@config).forwards.map do |name, dir|
33
+ format("%<name>-#{NAME_WIDTH}s %<desc>s" , name: name.yellow, desc: "#{dir}")
34
+ end
35
+ end
36
+
25
37
  def builtins
26
38
  builtin_class_map.map do |klass, name|
27
- format("%<name>-35s %<desc>s", name: name.downcase.to_s.yellow, desc: klass.description)
39
+ format("%<name>-#{NAME_WIDTH}s %<desc>s", name: name.downcase.to_s.yellow, desc: klass.description)
28
40
  end
29
41
  end
30
42
 
@@ -55,7 +67,7 @@ module Builtins
55
67
  return [] unless @config["actions"]
56
68
 
57
69
  @config["actions"].map do |name, action_config|
58
- format("%<name>-40s %<desc>s",
70
+ format("%<name>-#{NAME_WIDTH}s %<desc>s",
59
71
  name: "#{name.yellow} #{alias_string_for(action_config)}",
60
72
  desc: action_config["description"] || action_config["command"]
61
73
  )
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'output'
4
+
5
+ class Forward
6
+ def initialize(dir, args)
7
+ @dir = dir
8
+ @args = args
9
+ end
10
+
11
+ def run
12
+ Output.notice("Forwarding 'ops #{@args.join(" ")}' to '#{@dir}/'...")
13
+
14
+ Dir.chdir(@dir)
15
+ Ops.new(@args).run
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forward'
4
+
5
+ class Forwards
6
+ def initialize(config, args = [])
7
+ @config = config
8
+ @args = args
9
+ end
10
+
11
+ def get(name)
12
+ Forward.new(forwards[name], @args) if forwards[name]
13
+ end
14
+
15
+ def forwards
16
+ @forwards ||= @config["forwards"] || {}
17
+ end
18
+ end
data/lib/ops.rb CHANGED
@@ -5,22 +5,15 @@ require 'yaml'
5
5
  require 'require_all'
6
6
  require "rubygems"
7
7
 
8
- require 'hook_handler'
9
- require 'action'
10
8
  require 'output'
11
9
  require 'options'
12
- require 'environment'
13
10
  require 'version'
14
- require 'action_list'
15
- require 'action_suggester'
11
+ require 'runner'
16
12
 
17
13
  require_rel "builtins"
18
14
 
19
15
  # executes commands based on local `ops.yml`
20
16
  class Ops
21
- class UnknownActionError < StandardError; end
22
- class ActionConfigError < StandardError; end
23
-
24
17
  CONFIG_FILE = "ops.yml"
25
18
 
26
19
  INVALID_SYNTAX_EXIT_CODE = 64
@@ -46,43 +39,47 @@ class Ops
46
39
  Options.set(config["options"] || {})
47
40
  end
48
41
 
42
+ # rubocop:disable Metrics/MethodLength
43
+ # better to have all the rescues in one place
49
44
  def run
50
45
  # "return" is here to allow specs to stub "exit" without executing everything after it
51
46
  return exit(INVALID_SYNTAX_EXIT_CODE) unless syntax_valid?
52
47
  return exit(MIN_VERSION_NOT_MET_EXIT_CODE) unless min_version_met?
53
48
 
54
- run_action
55
- rescue UnknownActionError => e
49
+ runner.run
50
+ rescue Runner::UnknownActionError => e
56
51
  Output.error(e.to_s)
57
52
  Output.out(RECOMMEND_HELP_TEXT) unless print_did_you_mean
58
53
  exit(UNKNOWN_ACTION_EXIT_CODE)
59
- rescue ActionConfigError => e
54
+ rescue Runner::ActionConfigError => e
60
55
  Output.error("Error(s) running action '#{@action_name}': #{e}")
61
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 Action::NotAllowedInEnvError => e
64
+ Output.error("Error running action #{@action_name}: #{e}")
65
+ exit(ACTION_NOT_ALLOWED_IN_ENV_EXIT_CODE)
62
66
  end
67
+ # rubocop:enable Metrics/MethodLength
63
68
 
64
69
  private
65
70
 
66
71
  def syntax_valid?
67
- if @action_name.nil?
68
- Output.error("Usage: ops <action>")
69
- Output.out(RECOMMEND_HELP_TEXT)
70
- false
71
- else
72
- true
73
- end
72
+ return true unless @action_name.nil?
73
+
74
+ Output.error("Usage: ops <action>")
75
+ Output.out(RECOMMEND_HELP_TEXT)
76
+ false
74
77
  end
75
78
 
76
79
  def print_did_you_mean
77
- suggestions = did_you_mean.check(@action_name)
78
-
79
- Output.out("Did you mean '#{suggestions.join(", ")}'?") if suggestions.any?
80
-
81
- suggestions.any?
82
- end
80
+ Output.out("Did you mean '#{runner.suggestions.join(", ")}'?") if runner.suggestions.any?
83
81
 
84
- def did_you_mean
85
- ActionSuggester.new(action_list.names + action_list.aliases + builtin_names)
82
+ runner.suggestions.any?
86
83
  end
87
84
 
88
85
  def min_version_met?
@@ -100,90 +97,30 @@ class Ops
100
97
  config["min_version"]
101
98
  end
102
99
 
103
- def run_action
104
- do_before_all
105
-
106
- return builtin.run if builtin
107
-
108
- raise ActionConfigError, action.config_errors.join("; ") unless action.config_valid?
109
-
110
- do_before_action
111
- Output.notice("Running '#{action}' from #{CONFIG_FILE} in environment '#{ENV['environment']}'...")
112
- action.run
113
- rescue Builtin::ArgumentError => e
114
- Output.error("Error running builtin '#{@action_name}': #{e}")
115
- exit(BUILTIN_SYNTAX_ERROR_EXIT_CODE)
116
- rescue AppConfig::ParsingError => e
117
- Output.error("Error parsing app config: #{e}")
118
- exit(ERROR_LOADING_APP_CONFIG_EXIT_CODE)
119
- rescue Action::NotAllowedInEnvError => e
120
- Output.error("Error running action #{@action_name}: #{e}")
121
- exit(ACTION_NOT_ALLOWED_IN_ENV_EXIT_CODE)
122
- end
123
-
124
- def do_before_all
125
- environment.set_variables
126
- AppConfig.load
127
- end
128
-
129
- def do_before_action
130
- return if ENV["OPS_RUNNING"] || action.skip_hooks?("before")
131
-
132
- # this prevents before hooks from running in ops executed by ops
133
- ENV["OPS_RUNNING"] = "1"
134
- hook_handler.do_hooks("before")
135
- end
136
-
137
- def hook_handler
138
- @hook_handler ||= HookHandler.new(config)
139
- end
140
-
141
- def builtin
142
- @builtin ||= Builtin.class_for(name: @action_name).new(@args, config)
143
- rescue NameError
144
- # this means there isn't a builtin with that name in that module
145
- nil
146
- end
147
-
148
- def builtin_names
149
- Builtins.constants.select { |c| Builtins.const_get(c).is_a? Class }.map(&:downcase)
150
- end
151
-
152
- def action
153
- return action_list.get(@action_name) if action_list.get(@action_name)
154
- return action_list.get_by_alias(@action_name) if action_list.get_by_alias(@action_name)
155
-
156
- raise UnknownActionError, "Unknown action: #{@action_name}"
157
- end
158
-
159
- def action_list
160
- @action_list ||= begin
161
- Output.warn("'ops.yml' has no 'actions' defined.") if config.any? && config["actions"].nil?
162
-
163
- ActionList.new(config["actions"], @args)
164
- end
100
+ def runner
101
+ @runner ||= Runner.new(@action_name, @args, config)
165
102
  end
166
103
 
167
104
  def config
168
105
  @config ||= begin
169
- if File.exist?(CONFIG_FILE)
170
- YAML.load_file(CONFIG_FILE)
106
+ if config_file_exists?
107
+ parsed_config_contents
171
108
  else
172
109
  Output.warn("File '#{CONFIG_FILE}' does not exist.") unless @action_name == "init"
173
110
  {}
174
111
  end
175
- rescue StandardError => e
176
- Output.warn("Error parsing '#{CONFIG_FILE}': #{e}")
177
- {}
178
112
  end
179
113
  end
180
114
 
181
- def env_vars
182
- config.dig("options", "environment") || {}
115
+ def parsed_config_contents
116
+ YAML.load_file(CONFIG_FILE)
117
+ rescue StandardError => e
118
+ Output.warn("Error parsing '#{CONFIG_FILE}': #{e}")
119
+ {}
183
120
  end
184
121
 
185
- def environment
186
- @environment ||= Environment.new(env_vars)
122
+ def config_file_exists?
123
+ File.exist?(CONFIG_FILE)
187
124
  end
188
125
  end
189
126
 
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hook_handler'
4
+ require 'action'
5
+ require 'action_list'
6
+ require 'action_suggester'
7
+ require 'forwards'
8
+ require 'environment'
9
+
10
+ class Runner
11
+ class UnknownActionError < StandardError; end
12
+ class ActionConfigError < StandardError; end
13
+
14
+ def initialize(action_name, args, config)
15
+ @action_name = action_name
16
+ @args = args
17
+ @config = config
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
+ Output.notice("Running '#{action}' in environment '#{ENV['environment']}'...")
32
+ action.run
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
+ @builtin ||= Builtin.class_for(name: @action_name).new(@args, @config)
61
+ rescue NameError
62
+ # this means there isn't a builtin with that name in that module
63
+ nil
64
+ end
65
+
66
+ def builtin_names
67
+ Builtins.constants.select { |c| Builtins.const_get(c).is_a? Class }.map(&:downcase)
68
+ end
69
+
70
+ def forward
71
+ @forward ||= Forwards.new(@config, @args).get(@action_name)
72
+ end
73
+
74
+ def action
75
+ return action_list.get(@action_name) if action_list.get(@action_name)
76
+ return action_list.get_by_alias(@action_name) if action_list.get_by_alias(@action_name)
77
+ end
78
+
79
+ def action_list
80
+ @action_list ||= begin
81
+ Output.warn("'ops.yml' has no 'actions' defined.") if @config.any? && @config["actions"].nil?
82
+
83
+ ActionList.new(@config["actions"], @args)
84
+ end
85
+ end
86
+
87
+ def env_vars
88
+ @config.dig("options", "environment") || {}
89
+ end
90
+
91
+ def environment
92
+ @environment ||= Environment.new(env_vars)
93
+ end
94
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'ops_team'
5
- s.version = '0.18.1'
5
+ s.version = '1.0.1'
6
6
  s.authors = [
7
7
  'nickthecook@gmail.com'
8
8
  ]
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.18.1
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - nickthecook@gmail.com
@@ -175,10 +175,13 @@ files:
175
175
  - lib/dependency.rb
176
176
  - lib/environment.rb
177
177
  - lib/executor.rb
178
+ - lib/forward.rb
179
+ - lib/forwards.rb
178
180
  - lib/hook_handler.rb
179
181
  - lib/ops.rb
180
182
  - lib/options.rb
181
183
  - lib/output.rb
184
+ - lib/runner.rb
182
185
  - lib/secrets.rb
183
186
  - lib/version.rb
184
187
  - loader.rb