ops_team 0.18.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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