ops_team 0.12.3 → 0.14.0

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: 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