ops_team 0.12.3 → 0.14.0

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: 444384ee0931455838357c9bc2f720534e8fbda90d5d27a15c35b313cf676b4e
4
- data.tar.gz: 03ff8c264a9083987aac65d9a7ba78fdb8d118e757599c66267725178b8fc809
3
+ metadata.gz: 158077a8d8c025f32b231991165c500b93000422bfc411ff88124a86dad7af05
4
+ data.tar.gz: db0c44533b58f0a65b9d25921b77a5eb41f1a058f8ecae444c175a635d9f455d
5
5
  SHA512:
6
- metadata.gz: f596c660d5b7943258c3615a603f36f74ea5d98488d9171562c75593f3e5d5cbe93a349d687a417649dcb0be40de13c9c7d3c33c94b3d7686a43c3f2c94ea2cb
7
- data.tar.gz: 486531d3b6c027986cde18d88f3d43e6ffc7db44b4688a8528ccd33b1b0dcb0b883ff6b8048f0b168d3b9fa3d58d8f018722c12a95cdb3edf3e8820c5c3e4b02
6
+ metadata.gz: a5a7026cbb1b3eee2e16128d5f1f3d36f54197327bbe5562eb28ac2c7eb74a29feb5cc743cae4f4afaef40a9e5dabc5cf4cdc17eab5dd373ed826b87e1b6744f
7
+ data.tar.gz: 540a77c3f21b3c015bd45300bd50c0a42b6d467607b77869b141f3a03a15399e0f3d74a59aeef8a6b6781b6538783ce874dc00d6f0811c442bc36a88923d3602
data/Gemfile CHANGED
@@ -6,8 +6,12 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
6
 
7
7
  gem "bcrypt_pbkdf"
8
8
  gem "colorize"
9
+ gem "e2mmap"
9
10
  gem "ed25519"
10
11
  gem "ejson"
12
+ gem "etc"
13
+ gem "io-console"
14
+ gem "json", ">= 2.3.0"
11
15
  gem "net-ssh"
12
16
  gem "require_all"
13
17
 
@@ -17,6 +21,7 @@ group :test do
17
21
  end
18
22
 
19
23
  group :development do
24
+ gem "irb"
20
25
  gem "pry"
21
26
  gem "pry-byebug"
22
27
  gem "rerun"
@@ -0,0 +1,42 @@
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 process_action_list
32
+ @actions = {}
33
+ @aliases = {}
34
+
35
+ @actions_list.each do |name, config|
36
+ action = Action.new(config, @args)
37
+
38
+ @actions[name] = action
39
+ @aliases[action.alias] = action
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,17 @@
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
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dependency'
3
+ require 'dependencies/versioned_dependency'
4
4
  require 'dependencies/helpers/apt_cache_policy'
5
5
 
6
6
  module Dependencies
7
- class Apt < Dependency
8
- PACKAGE_NAME_SEPARATOR = "/"
9
-
7
+ class Apt < VersionedDependency
10
8
  def met?
11
- return apt_cache_policy.installed_version == package_version if package_version
9
+ return apt_cache_policy.installed_version == dep_version if dep_version
12
10
 
13
11
  apt_cache_policy.installed?
14
12
  end
@@ -28,20 +26,8 @@ module Dependencies
28
26
 
29
27
  private
30
28
 
31
- def package_name
32
- name_components[0]
33
- end
34
-
35
- def package_version
36
- name_components[1]
37
- end
38
-
39
- def name_components
40
- name.split(PACKAGE_NAME_SEPARATOR, 2)
41
- end
42
-
43
29
  def apt_cache_policy
44
- @apt_cache_policy ||= Dependencies::Helpers::AptCachePolicy.new(package_name)
30
+ @apt_cache_policy ||= Dependencies::Helpers::AptCachePolicy.new(dep_name)
45
31
  end
46
32
 
47
33
  def sudo_string
@@ -4,18 +4,20 @@ require 'dependency'
4
4
  require 'options'
5
5
 
6
6
  module Dependencies
7
- class Gem < Dependency
7
+ class Gem < VersionedDependency
8
8
  def met?
9
- execute("gem list -i '^#{name}$'")
9
+ if versioned?
10
+ execute("gem list -i '^#{dep_name}$' -v '#{dep_version}'") if versioned?
11
+ else
12
+ execute("gem list -i '^#{name}$'")
13
+ end
10
14
  end
11
15
 
12
16
  def meet
13
- if Options.get("gem.use_sudo")
14
- execute("sudo gem install #{name}")
15
- elsif Options.get("gem.user_install")
16
- execute("gem install --user-install #{name}")
17
+ if versioned?
18
+ execute("#{sudo_string}gem install #{user_install_string}'#{dep_name}' -v '#{dep_version}'")
17
19
  else
18
- execute("gem install #{name}")
20
+ execute("#{sudo_string}gem install #{user_install_string}'#{name}'")
19
21
  end
20
22
  end
21
23
 
@@ -23,5 +25,15 @@ module Dependencies
23
25
  # do nothing; we don't want to uninstall packages and reinstall them every time
24
26
  true
25
27
  end
28
+
29
+ private
30
+
31
+ def sudo_string
32
+ Options.get("gem.use_sudo") ? "sudo " : ""
33
+ end
34
+
35
+ def user_install_string
36
+ Options.get("gem.user_install") ? "--user-install " : ""
37
+ end
26
38
  end
27
39
  end
@@ -0,0 +1,25 @@
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/ops.rb CHANGED
@@ -11,6 +11,9 @@ require 'output'
11
11
  require 'options'
12
12
  require 'environment'
13
13
  require 'version'
14
+ require 'action_list'
15
+ require 'action_suggester'
16
+
14
17
  require_rel "builtins"
15
18
 
16
19
  # executes commands based on local `ops.yml`
@@ -24,6 +27,8 @@ class Ops
24
27
  ERROR_LOADING_APP_CONFIG_EXIT_CODE = 66
25
28
  MIN_VERSION_NOT_MET_EXIT_CODE = 67
26
29
 
30
+ RECOMMEND_HELP_TEXT = "Run 'ops help' for a list of builtins and actions."
31
+
27
32
  class << self
28
33
  def project_name
29
34
  File.basename(::Dir.pwd)
@@ -38,13 +43,14 @@ class Ops
38
43
  end
39
44
 
40
45
  def run
41
- # "return" is here to allow specs to stub "exit"
46
+ # "return" is here to allow specs to stub "exit" without executing everything after it
42
47
  return exit(INVALID_SYNTAX_EXIT_CODE) unless syntax_valid?
43
48
  return exit(MIN_VERSION_NOT_MET_EXIT_CODE) unless min_version_met?
44
49
 
45
50
  run_action
46
51
  rescue UnknownActionError => e
47
- Output.error("Error: #{e}")
52
+ Output.error(e.to_s)
53
+ Output.out(RECOMMEND_HELP_TEXT) unless print_did_you_mean
48
54
  exit(UNKNOWN_ACTION_EXIT_CODE)
49
55
  end
50
56
 
@@ -53,12 +59,25 @@ class Ops
53
59
  def syntax_valid?
54
60
  if @action_name.nil?
55
61
  Output.error("Usage: ops <action>")
62
+ Output.out(RECOMMEND_HELP_TEXT)
56
63
  false
57
64
  else
58
65
  true
59
66
  end
60
67
  end
61
68
 
69
+ def print_did_you_mean
70
+ suggestions = did_you_mean.check(@action_name)
71
+
72
+ Output.out("Did you mean '#{suggestions.join(", ")}'?") if suggestions.any?
73
+
74
+ suggestions.any?
75
+ end
76
+
77
+ def did_you_mean
78
+ ActionSuggester.new(action_list.names + action_list.aliases + builtin_names)
79
+ end
80
+
62
81
  def min_version_met?
63
82
  return true unless min_version
64
83
 
@@ -80,7 +99,6 @@ class Ops
80
99
  return builtin.run if builtin
81
100
 
82
101
  do_before_action
83
-
84
102
  Output.notice("Running '#{action}' from #{CONFIG_FILE} in environment '#{ENV['environment']}'...")
85
103
  action.run
86
104
  rescue AppConfig::ParsingError => e
@@ -111,24 +129,22 @@ class Ops
111
129
  nil
112
130
  end
113
131
 
132
+ def builtin_names
133
+ Builtins.constants.select { |c| Builtins.const_get(c).is_a? Class }.map(&:downcase)
134
+ end
135
+
114
136
  def action
115
- return actions[@action_name] if actions[@action_name]
116
- return aliases[@action_name] if aliases[@action_name]
137
+ return action_list.get(@action_name) if action_list.get(@action_name)
138
+ return action_list.get_by_alias(@action_name) if action_list.get_by_alias(@action_name)
117
139
 
118
140
  raise UnknownActionError, "Unknown action: #{@action_name}"
119
141
  end
120
142
 
121
- def actions
122
- @actions ||= begin
123
- if config["actions"]
124
- config["actions"]&.transform_values do |config|
125
- Action.new(config, @args)
126
- end
127
- else
128
- # only print this error if ops.yml had something in it
129
- Output.warn("'ops.yml' has no 'actions' defined.") if config.any?
130
- {}
131
- end
143
+ def action_list
144
+ @action_list ||= begin
145
+ Output.warn("'ops.yml' has no 'actions' defined.") if config.any? && config["actions"].nil?
146
+
147
+ ActionList.new(config["actions"], @args)
132
148
  end
133
149
  end
134
150
 
@@ -142,14 +158,6 @@ class Ops
142
158
  end
143
159
  end
144
160
 
145
- def aliases
146
- @aliases ||= begin
147
- actions.each_with_object({}) do |(_name, action), alias_hash|
148
- alias_hash[action.alias] = action if action.alias
149
- end
150
- end
151
- end
152
-
153
161
  def env_vars
154
162
  @config.dig("options", "environment") || {}
155
163
  end
@@ -157,10 +165,6 @@ class Ops
157
165
  def environment
158
166
  @environment ||= Environment.new(env_vars)
159
167
  end
160
-
161
- def app_config
162
- @app_config ||= AppConfig.new
163
- end
164
168
  end
165
169
 
166
170
  Ops.new(ARGV).run if $PROGRAM_NAME == __FILE__
@@ -40,7 +40,7 @@ class Output
40
40
  @err.puts(msg.yellow)
41
41
  end
42
42
 
43
- alias_method :notice, :warn
43
+ alias notice warn
44
44
 
45
45
  def error(msg)
46
46
  @err.puts(msg.red)
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'ops_team'
5
- s.version = '0.12.3'
5
+ s.version = '0.14.0'
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.12.3
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - nickthecook@gmail.com
@@ -146,6 +146,8 @@ files:
146
146
  - etc/ruby.template.yml
147
147
  - etc/terraform.template.yml
148
148
  - lib/action.rb
149
+ - lib/action_list.rb
150
+ - lib/action_suggester.rb
149
151
  - lib/app_config.rb
150
152
  - lib/builtin.rb
151
153
  - lib/builtins/background.rb
@@ -168,6 +170,7 @@ files:
168
170
  - lib/dependencies/gem.rb
169
171
  - lib/dependencies/helpers/apt_cache_policy.rb
170
172
  - lib/dependencies/sshkey.rb
173
+ - lib/dependencies/versioned_dependency.rb
171
174
  - lib/dependency.rb
172
175
  - lib/environment.rb
173
176
  - lib/executor.rb