cli-kit 5.0.0 → 5.1.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: e576da52278c6b0596840691bffbb12546b54bf2238145455a45333d6101f773
4
- data.tar.gz: 24243f1a2d66ad3b12fb2728b73b608038950d958ffc31dc0ab7951c3714533a
3
+ metadata.gz: 2d726194921593173c9e5ddc6825b4bb450b3b5b349be39801b0178668c3e94a
4
+ data.tar.gz: 3ab180c9b128bc0c6bdee63b68275273a12a938df484eb94e743f11ff81d28a2
5
5
  SHA512:
6
- metadata.gz: 8e7f4f5c4cc6620a2d98eca89e85ad57e6a9a0bd94ec704503ac0c9ba84f631984beb7c71c60e8b24ddbd2c4cf88b30cc298d3b05009f565450348a5b82c8d7f
7
- data.tar.gz: ac1c63ad107ca13fda07413a17054a17bb69ec6ae793f2a0abb97a5c2616c15fe7aaeaf7c3328b7ce035136dd72007df51fe7f5aab15e0c90199ede7ddd8d1e0
6
+ metadata.gz: 7677c4a9ccf218206b5b31f261507f66e12e7d8148be5857025979e282c8e524546015df0c6a612c818de297d6c93157fc15394592d0914eada8b5acd17469aa
7
+ data.tar.gz: 1a7882f6f3bb2a81dfa50c655c02fef3286badba79e4f5f6e384fc87a5d0953beba48b92eb83981c8124db91980c14d11c41a16d012b99eb3ef8151cc895fd86
@@ -8,3 +8,6 @@ updates:
8
8
  time: "07:00"
9
9
  timezone: America/Toronto
10
10
  open-pull-requests-limit: 99
11
+ groups:
12
+ dev-dependencies:
13
+ dependency-type: "development"
@@ -11,7 +11,6 @@ jobs:
11
11
  - name: Set up Ruby
12
12
  uses: ruby/setup-ruby@v1
13
13
  with:
14
- ruby-version: '2.7'
15
14
  bundler-cache: true
16
15
  - name: Check style
17
16
  run: bundle exec rake style
@@ -23,7 +22,6 @@ jobs:
23
22
  - name: Set up Ruby
24
23
  uses: ruby/setup-ruby@v1
25
24
  with:
26
- ruby-version: '2.7'
27
25
  bundler-cache: true
28
26
  - name: Typecheck
29
27
  run: bundle exec srb tc
@@ -32,25 +30,9 @@ jobs:
32
30
  strategy:
33
31
  matrix:
34
32
  os: [macos-latest, ubuntu-latest]
35
- ruby-version: ['2.7', '3.0']
33
+ ruby-version: ['3.1', '3.2', '3.3', '3.4']
36
34
 
37
35
  runs-on: ${{ matrix.os }}
38
- steps:
39
- - uses: actions/checkout@v2
40
- - name: Set up Ruby
41
- uses: ruby/setup-ruby@v1
42
- with:
43
- ruby-version: ${{ matrix.ruby-version }}
44
- bundler-cache: true
45
- - name: Run tests
46
- run: bundle exec rake test
47
-
48
- test-windows:
49
- strategy:
50
- matrix:
51
- ruby-version: ['2.7', '3.0']
52
-
53
- runs-on: windows-latest
54
36
  env:
55
37
  BUNDLE_WITHOUT: typecheck
56
38
  steps:
data/.rubocop.yml CHANGED
@@ -11,7 +11,7 @@ AllCops:
11
11
  Exclude:
12
12
  - gen/template/**/*
13
13
  - vendor/**/*
14
- TargetRubyVersion: 2.7
14
+ - lib/cli/kit/levenshtein.rb # Vendored
15
15
  NewCops: disable
16
16
 
17
17
  Style/ClassAndModuleChildren:
@@ -51,3 +51,19 @@ Style/GlobalStdStream:
51
51
  # Sometimes (often) explicit is good
52
52
  Style/EmptyElse:
53
53
  Enabled: false
54
+
55
+ # We make frequent use Open3 methods to run other programs. When passing long command lines, it's useful and informative
56
+ # to place the argument to an option on the same line as its option, eg:
57
+ # Open3.capture3(
58
+ # 'curl',
59
+ # '-H', 'X-Header: value',
60
+ # '-o', 'file.txt',
61
+ # '-L',
62
+ # 'https://example.com/',
63
+ # )
64
+ Layout/MultilineMethodArgumentLineBreaks:
65
+ Enabled: false
66
+ Layout/MultilineArrayLineBreaks:
67
+ Enabled: false
68
+ Layout/MultilineHashKeyLineBreaks:
69
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.3
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :development, :test do
7
- gem 'cli-ui', git: 'https://github.com/Shopify/cli-ui', ref: '0eefd57248f42ec163639884e77a071d82bfbda8'
7
+ gem 'cli-ui'
8
8
  gem 'rubocop'
9
9
  gem 'rubocop-rake'
10
10
  gem 'rubocop-shopify'
@@ -20,7 +20,7 @@ group :typecheck do
20
20
  end
21
21
 
22
22
  group :test do
23
- gem 'mocha', '~> 2.0.1', require: false
23
+ gem 'mocha', '~> 2.4.0', require: false
24
24
  gem 'minitest', '>= 5.0.0', require: false
25
25
  gem 'minitest-reporters', require: false
26
26
  end
data/Gemfile.lock CHANGED
@@ -1,118 +1,118 @@
1
- GIT
2
- remote: https://github.com/Shopify/cli-ui
3
- revision: 0eefd57248f42ec163639884e77a071d82bfbda8
4
- ref: 0eefd57248f42ec163639884e77a071d82bfbda8
5
- specs:
6
- cli-ui (1.5.1)
7
-
8
1
  PATH
9
2
  remote: .
10
3
  specs:
11
- cli-kit (4.0.0)
12
- cli-ui (>= 1.1.4)
4
+ cli-kit (5.1.0)
5
+ cli-ui (~> 2.4)
13
6
 
14
7
  GEM
15
8
  remote: https://rubygems.org/
16
9
  specs:
17
10
  ansi (1.5.0)
18
- ast (2.4.2)
19
- builder (3.2.4)
20
- byebug (11.1.3)
21
- diff-lcs (1.5.0)
22
- docile (1.4.0)
23
- json (2.6.2)
24
- method_source (1.0.0)
25
- minitest (5.16.3)
26
- minitest-reporters (1.5.0)
11
+ ast (2.4.3)
12
+ benchmark (0.4.1)
13
+ builder (3.3.0)
14
+ byebug (12.0.0)
15
+ cli-ui (2.4.0)
16
+ docile (1.4.1)
17
+ erubi (1.13.1)
18
+ json (2.13.2)
19
+ language_server-protocol (3.17.0.5)
20
+ lint_roller (1.1.0)
21
+ logger (1.7.0)
22
+ method_source (1.1.0)
23
+ minitest (5.25.5)
24
+ minitest-reporters (1.7.1)
27
25
  ansi
28
26
  builder
29
27
  minitest (>= 5.0)
30
28
  ruby-progressbar
31
- mocha (2.0.2)
29
+ mocha (2.4.5)
32
30
  ruby2_keywords (>= 0.0.5)
33
31
  netrc (0.11.0)
34
- parallel (1.22.1)
35
- parser (3.1.2.1)
32
+ parallel (1.27.0)
33
+ parser (3.3.9.0)
36
34
  ast (~> 2.4.1)
35
+ racc
36
+ prism (1.4.0)
37
+ racc (1.8.1)
37
38
  rainbow (3.1.1)
38
- rake (13.0.6)
39
- rbi (0.0.16)
40
- ast
41
- parser (>= 2.6.4.0)
42
- sorbet-runtime (>= 0.5.9204)
43
- unparser
44
- regexp_parser (2.6.0)
45
- rexml (3.2.5)
46
- rubocop (1.39.0)
39
+ rake (13.3.0)
40
+ rbi (0.3.6)
41
+ prism (~> 1.0)
42
+ rbs (>= 3.4.4)
43
+ rbs (3.9.4)
44
+ logger
45
+ regexp_parser (2.10.0)
46
+ rexml (3.4.1)
47
+ rubocop (1.79.0)
47
48
  json (~> 2.3)
49
+ language_server-protocol (~> 3.17.0.2)
50
+ lint_roller (~> 1.1.0)
48
51
  parallel (~> 1.10)
49
- parser (>= 3.1.2.1)
52
+ parser (>= 3.3.0.2)
50
53
  rainbow (>= 2.2.2, < 4.0)
51
- regexp_parser (>= 1.8, < 3.0)
52
- rexml (>= 3.2.5, < 4.0)
53
- rubocop-ast (>= 1.23.0, < 2.0)
54
+ regexp_parser (>= 2.9.3, < 3.0)
55
+ rubocop-ast (>= 1.46.0, < 2.0)
54
56
  ruby-progressbar (~> 1.7)
55
- unicode-display_width (>= 1.4.0, < 3.0)
56
- rubocop-ast (1.23.0)
57
- parser (>= 3.1.1.0)
58
- rubocop-rake (0.6.0)
59
- rubocop (~> 1.0)
60
- rubocop-shopify (2.10.1)
61
- rubocop (~> 1.35)
62
- rubocop-sorbet (0.6.11)
63
- rubocop (>= 0.90.0)
64
- ruby-progressbar (1.11.0)
57
+ tsort (>= 0.2.0)
58
+ unicode-display_width (>= 2.4.0, < 4.0)
59
+ rubocop-ast (1.46.0)
60
+ parser (>= 3.3.7.2)
61
+ prism (~> 1.4)
62
+ rubocop-rake (0.7.1)
63
+ lint_roller (~> 1.1)
64
+ rubocop (>= 1.72.1)
65
+ rubocop-shopify (2.17.1)
66
+ rubocop (~> 1.62)
67
+ rubocop-sorbet (0.10.5)
68
+ lint_roller
69
+ rubocop (>= 1.75.2)
70
+ ruby-progressbar (1.13.0)
65
71
  ruby2_keywords (0.0.5)
66
- simplecov (0.21.2)
72
+ simplecov (0.22.0)
67
73
  docile (~> 1.1)
68
74
  simplecov-html (~> 0.11)
69
75
  simplecov_json_formatter (~> 0.1)
70
- simplecov-html (0.12.3)
76
+ simplecov-html (0.13.2)
71
77
  simplecov_json_formatter (0.1.4)
72
- sorbet (0.5.10554)
73
- sorbet-static (= 0.5.10554)
74
- sorbet-runtime (0.5.10554)
75
- sorbet-static (0.5.10554-universal-darwin-14)
76
- sorbet-static (0.5.10554-universal-darwin-15)
77
- sorbet-static (0.5.10554-universal-darwin-16)
78
- sorbet-static (0.5.10554-universal-darwin-17)
79
- sorbet-static (0.5.10554-universal-darwin-18)
80
- sorbet-static (0.5.10554-universal-darwin-19)
81
- sorbet-static (0.5.10554-universal-darwin-20)
82
- sorbet-static (0.5.10554-universal-darwin-21)
83
- sorbet-static (0.5.10554-universal-darwin-22)
84
- sorbet-static (0.5.10554-x86_64-linux)
85
- sorbet-static-and-runtime (0.5.10554)
86
- sorbet (= 0.5.10554)
87
- sorbet-runtime (= 0.5.10554)
88
- spoom (1.1.12)
89
- sorbet (>= 0.5.9204)
90
- sorbet-runtime (>= 0.5.9204)
78
+ sorbet (0.5.12358)
79
+ sorbet-static (= 0.5.12358)
80
+ sorbet-runtime (0.5.12358)
81
+ sorbet-static (0.5.12358-aarch64-linux)
82
+ sorbet-static (0.5.12358-universal-darwin)
83
+ sorbet-static (0.5.12358-x86_64-linux)
84
+ sorbet-static-and-runtime (0.5.12358)
85
+ sorbet (= 0.5.12358)
86
+ sorbet-runtime (= 0.5.12358)
87
+ spoom (1.6.3)
88
+ erubi (>= 1.10.0)
89
+ prism (>= 0.28.0)
90
+ rbi (>= 0.3.3)
91
+ rexml (>= 3.2.6)
92
+ sorbet-static-and-runtime (>= 0.5.10187)
91
93
  thor (>= 0.19.2)
92
- tapioca (0.10.3)
93
- bundler (>= 1.17.3)
94
+ tapioca (0.16.11)
95
+ benchmark
96
+ bundler (>= 2.2.25)
94
97
  netrc (>= 0.11.0)
95
98
  parallel (>= 1.21.0)
96
- rbi (~> 0.0.0, >= 0.0.16)
97
- sorbet-static-and-runtime (>= 0.5.9892)
98
- spoom (~> 1.1.0, >= 1.1.11)
99
+ rbi (~> 0.2)
100
+ sorbet-static-and-runtime (>= 0.5.11087)
101
+ spoom (>= 1.2.0)
99
102
  thor (>= 1.2.0)
100
103
  yard-sorbet
101
- thor (1.2.1)
102
- unicode-display_width (2.3.0)
103
- unparser (0.6.5)
104
- diff-lcs (~> 1.3)
105
- parser (>= 3.1.0)
106
- webrick (1.7.0)
107
- yard (0.9.28)
108
- webrick (~> 1.7.0)
109
- yard-sorbet (0.7.0)
110
- sorbet-runtime (>= 0.5)
111
- yard (>= 0.9)
104
+ thor (1.4.0)
105
+ tsort (0.2.0)
106
+ unicode-display_width (3.1.4)
107
+ unicode-emoji (~> 4.0, >= 4.0.4)
108
+ unicode-emoji (4.0.4)
109
+ yard (0.9.37)
110
+ yard-sorbet (0.9.0)
111
+ sorbet-runtime
112
+ yard
112
113
 
113
114
  PLATFORMS
114
- arm64-darwin-21
115
- ruby
115
+ aarch64-linux
116
116
  universal-darwin
117
117
  x86_64-linux
118
118
 
@@ -120,11 +120,11 @@ DEPENDENCIES
120
120
  bundler (~> 2.1)
121
121
  byebug
122
122
  cli-kit!
123
- cli-ui!
123
+ cli-ui
124
124
  method_source
125
125
  minitest (>= 5.0.0)
126
126
  minitest-reporters
127
- mocha (~> 2.0.1)
127
+ mocha (~> 2.4.0)
128
128
  rake (~> 13.0)
129
129
  rubocop
130
130
  rubocop-rake
@@ -135,4 +135,4 @@ DEPENDENCIES
135
135
  tapioca
136
136
 
137
137
  BUNDLED WITH
138
- 2.2.24
138
+ 2.6.7
data/bin/tapioca CHANGED
@@ -9,8 +9,7 @@
9
9
  #
10
10
 
11
11
  require 'pathname'
12
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
- Pathname.new(__FILE__).realpath)
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
14
13
 
15
14
  bundle_binstub = File.expand_path('../bundle', __FILE__)
16
15
 
data/cli-kit.gemspec CHANGED
@@ -7,8 +7,11 @@ require 'cli/kit/version'
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'cli-kit'
9
9
  spec.version = CLI::Kit::VERSION
10
- spec.authors = ['Burke Libbey', 'Aaron Olson', 'Lisa Ugray']
11
- spec.email = ['burke.libbey@shopify.com', 'aaron.olson@shopify.com', 'lisa.ugray@shopify.com']
10
+ spec.authors = ['Burke Libbey', 'Aaron Olson', 'Lisa Ugray', 'Don Kelly']
11
+ spec.email = [
12
+ 'burke.libbey@shopify.com', 'aaron.olson@shopify.com', 'lisa.ugray@shopify.com',
13
+ 'don.kelly@shopify.com',
14
+ ]
12
15
 
13
16
  spec.summary = 'Terminal UI framework extensions'
14
17
  spec.description = 'Terminal UI framework extensions'
@@ -22,7 +25,9 @@ Gem::Specification.new do |spec|
22
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
26
  spec.require_paths = ['lib']
24
27
 
25
- spec.add_runtime_dependency('cli-ui', '~> 2.0')
28
+ spec.add_runtime_dependency('cli-ui', '~> 2.4')
29
+
30
+ spec.required_ruby_version = '>= 3.0'
26
31
 
27
32
  spec.add_development_dependency('bundler', '~> 2.1')
28
33
  spec.add_development_dependency('minitest', '~> 5.0')
data/dev.yml CHANGED
@@ -1,10 +1,15 @@
1
+ nix: true
2
+
1
3
  up:
2
- - homebrew:
4
+ - packages:
3
5
  - fswatch
4
- - ruby: 3.0.4
6
+ - ruby
5
7
  - bundler
6
8
 
7
9
  commands:
10
+ add-back-ruby:
11
+ run: bundle lock --add-platform ruby && git commit -a -m 'Add back ruby platform' && git push
12
+ aliases: [abr]
8
13
  console: irb -I./lib -rcli/kit
9
14
  check:
10
15
  run: 'srb && rake style test'
@@ -9,12 +9,15 @@ CLI::UI::StdoutRouter.enable
9
9
  include(CLI::Kit)
10
10
 
11
11
  registry = CommandRegistry.new(default: 'hello')
12
- registry.add(Class.new(BaseCommand) do
13
- sig { params(_args: T::Array[String], _name: String).void }
14
- def call(_args, _name)
15
- puts 'hello, world!'
16
- end
17
- end, 'hello')
12
+ registry.add(
13
+ Class.new(BaseCommand) do
14
+ sig { params(_args: T::Array[String], _name: String).void }
15
+ def call(_args, _name)
16
+ puts 'hello, world!'
17
+ end
18
+ end,
19
+ 'hello',
20
+ )
18
21
 
19
22
  executor = Executor.new(log_file: '/tmp/example.log')
20
23
  error_handler = ErrorHandler.new(log_file: '/tmp/example.log', exception_reporter: nil)
@@ -149,10 +149,10 @@ module Gen
149
149
  sig { params(s: String).returns(String) }
150
150
  def apply_template_variables(s)
151
151
  s
152
- .gsub(/__app__/, @project_name)
153
- .gsub(/__App__/, @title_case_project_name)
154
- .gsub(/__cli-kit-version__/, cli_kit_version)
155
- .gsub(/__cli-ui-version__/, cli_ui_version)
152
+ .gsub('__app__', @project_name)
153
+ .gsub('__App__', @title_case_project_name)
154
+ .gsub('__cli-kit-version__', cli_kit_version)
155
+ .gsub('__cli-ui-version__', cli_ui_version)
156
156
  end
157
157
 
158
158
  sig { returns(String) }
data/gen/lib/gen/help.rb CHANGED
@@ -40,7 +40,7 @@ module Gen
40
40
  max_len = cmds.map(&:first).map(&:length).max
41
41
 
42
42
  cmds.each do |name, desc|
43
- to.write(CLI::UI.fmt(" {{command:#{name.ljust(max_len)}}} #{desc}\n"))
43
+ to.write(CLI::UI.fmt(" {{command:#{name.ljust(T.must(max_len))}}} #{desc}\n"))
44
44
  end
45
45
  end
46
46
 
@@ -1,3 +1,3 @@
1
1
  up:
2
- - ruby: 2.5.0
2
+ - ruby: 3.2.2
3
3
  - bundler
@@ -1,4 +1,4 @@
1
1
  up:
2
- - ruby: 2.5.0
2
+ - ruby: 3.2.2
3
3
 
4
4
  build: bin/update-deps
@@ -151,7 +151,7 @@ module CLI
151
151
  next unless opt.required?
152
152
 
153
153
  node = @parse.detect do |node|
154
- node.is_a?(Parser::Node::Option) && node.name == opt.name
154
+ node.is_a?(Parser::Node::Option) && node.name.to_sym == opt.name
155
155
  end
156
156
  if !node || T.cast(node, Parser::Node::Option).value.nil?
157
157
  raise(MissingRequiredOption, opt.as_written_by_user)
@@ -199,26 +199,15 @@ module CLI
199
199
 
200
200
  sig { params(opt: Definition::Option).returns(T.any(NilClass, String, T::Array[String])) }
201
201
  def lookup_option(opt)
202
- if opt.short
203
- opts = T.cast(
204
- parse.select { |node| node.is_a?(Parser::Node::ShortOption) },
205
- T::Array[Parser::Node::ShortOption],
206
- )
207
- matches = opts.select { |node| node.name == opt.short }
208
- if (last = matches.last)
209
- return(opt.multi? ? matches.map(&:value) : last.value)
210
- end
211
- end
212
- if opt.long
213
- opts = T.cast(
214
- parse.select { |node| node.is_a?(Parser::Node::LongOption) },
215
- T::Array[Parser::Node::LongOption],
216
- )
217
- matches = opts.select { |node| node.name == opt.long }
218
- if (last = matches.last)
219
- return(opt.multi? ? matches.map(&:value) : last.value)
220
- end
202
+ opts = T.cast(
203
+ parse.select { |node| node.is_a?(Parser::Node::ShortOption) || node.is_a?(Parser::Node::LongOption) },
204
+ T::Array[T.any(Parser::Node::ShortOption, Parser::Node::LongOption)],
205
+ )
206
+ matches = opts.select { |node| (opt.short && node.name == opt.short) || (opt.long && node.name == opt.long) }
207
+ if (last = matches.last)
208
+ return (opt.multi? ? matches.map(&:value) : last.value)
221
209
  end
210
+
222
211
  opt.default
223
212
  end
224
213
 
@@ -135,7 +135,7 @@ module CLI
135
135
  sig { returns(T.nilable(String)) }
136
136
  def build_options
137
137
  opts = opts_class
138
- return(nil) unless opts
138
+ return unless opts
139
139
 
140
140
  methods = []
141
141
  loop do
@@ -149,7 +149,7 @@ module CLI
149
149
  o = opts.new
150
150
  o.define!(@defn)
151
151
 
152
- return nil if @defn.options.empty? && @defn.flags.empty?
152
+ return if @defn.options.empty? && @defn.flags.empty?
153
153
 
154
154
  merged = T.let(@defn.options, T::Array[T.any(Args::Definition::Option, Args::Definition::Flag)])
155
155
  merged += @defn.flags
@@ -238,7 +238,7 @@ module CLI
238
238
 
239
239
  sig { returns(T.nilable(String)) }
240
240
  def build_examples
241
- return nil unless @examples
241
+ return unless @examples
242
242
 
243
243
  cmd_prefix = " {{command:#{CommandHelp._tool_name} #{_command_name}}}"
244
244
  "{{bold:Examples:}}\n" + @examples.map do |command, explanation|
@@ -107,15 +107,15 @@ module CLI
107
107
  sig { params(name: String).returns([T.nilable(T.class_of(CLI::Kit::BaseCommand)), String]) }
108
108
  def resolve_command(name)
109
109
  name = resolve_alias(name)
110
- resolve_global_command(name) || \
111
- resolve_contextual_command(name) || \
110
+ resolve_global_command(name) ||
111
+ resolve_contextual_command(name) ||
112
112
  [nil, name]
113
113
  end
114
114
 
115
115
  sig { params(name: String).returns(T.nilable([T.class_of(CLI::Kit::BaseCommand), String])) }
116
116
  def resolve_global_command(name)
117
117
  klass = resolve_class(commands.fetch(name, nil))
118
- return nil unless klass
118
+ return unless klass
119
119
 
120
120
  [klass, name]
121
121
  rescue NameError
@@ -125,7 +125,7 @@ module CLI
125
125
  sig { params(name: String).returns(T.nilable([T.class_of(CLI::Kit::BaseCommand), String])) }
126
126
  def resolve_contextual_command(name)
127
127
  found = @contextual_resolver.command_names.include?(name)
128
- return nil unless found
128
+ return unless found
129
129
 
130
130
  [@contextual_resolver.command_class(name), name]
131
131
  end
@@ -1,4 +1,4 @@
1
- # typed: strong
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  class Exception
@@ -133,9 +133,9 @@ module CLI
133
133
  sig { params(error: T.nilable(Exception)).returns(T.nilable(Exception)) }
134
134
  def exception_for_submission(error)
135
135
  # happens on normal non-error termination
136
- return(nil) if error.nil?
136
+ return if error.nil?
137
137
 
138
- return(nil) unless error.bug?
138
+ return unless error.bug?
139
139
 
140
140
  case error
141
141
  when SignalException
@@ -56,8 +56,9 @@ module CLI
56
56
  end
57
57
 
58
58
  sig do
59
- type_parameters(:T).params(signal: String, handler: Method,
60
- block: T.proc.returns(T.type_parameter(:T))).returns(T.type_parameter(:T))
59
+ type_parameters(:T)
60
+ .params(signal: String, handler: Method, block: T.proc.returns(T.type_parameter(:T)))
61
+ .returns(T.type_parameter(:T))
61
62
  end
62
63
  def twrap(signal, handler, &block)
63
64
  return yield unless Signal.list.key?(signal)
data/lib/cli/kit/opts.rb CHANGED
@@ -180,17 +180,24 @@ module CLI
180
180
 
181
181
  private
182
182
 
183
+ sig { params(label: T.nilable(String)).returns(T.nilable(Symbol)) }
184
+ def symbolize(label)
185
+ return if label.nil?
186
+
187
+ label.split('#').last&.to_sym
188
+ end
189
+
183
190
  sig { returns(Symbol) }
184
191
  def infer_name
185
192
  to_skip = 1
186
- Kernel.caller_locations&.each do |loc|
193
+ Kernel.caller_locations.each do |loc|
187
194
  next if loc.path =~ /sorbet-runtime/
188
195
 
189
196
  if to_skip > 0
190
197
  to_skip -= 1
191
198
  next
192
199
  end
193
- return(T.must(loc.label&.to_sym))
200
+ return T.must(symbolize(loc.label))
194
201
  end
195
202
  raise(ArgumentError, 'could not infer name')
196
203
  end
@@ -218,7 +225,7 @@ module CLI
218
225
  ).returns(T.untyped)
219
226
  end
220
227
  def each_option(&block)
221
- return(enum_for(:each_option)) unless block_given?
228
+ return enum_for(:each_option) unless block_given?
222
229
 
223
230
  obj = assert_result!
224
231
  obj.defn.options.each do |opt|
@@ -236,7 +243,7 @@ module CLI
236
243
  ).returns(T.untyped)
237
244
  end
238
245
  def each_flag(&block)
239
- return(enum_for(:each_flag)) unless block_given?
246
+ return enum_for(:each_flag) unless block_given?
240
247
 
241
248
  obj = assert_result!
242
249
  obj.defn.flags.each do |flag|
@@ -0,0 +1,60 @@
1
+ # typed: true
2
+
3
+ module CLI
4
+ module Kit
5
+ module ParseArgs
6
+ # because sorbet type-checking takes the pedantic route that module doesn't include Kernel, therefore
7
+ # this is necessary (even tho it's ~probably fine~)
8
+ include Kernel
9
+ extend T::Sig
10
+
11
+ # T.untyped is used in two places. The interpretation of dynamic values from the provided `opts`
12
+ # and the resulting args[:opts] is pretty broad. There seems to be minimal value in expressing a
13
+ # tighter subset of T.untyped.
14
+
15
+ sig do
16
+ params(
17
+ args: T.any(Array, String),
18
+ opts_defn: T::Hash[Symbol, T::Array[T.untyped]],
19
+ ).returns(T::Hash[Symbol, T.untyped])
20
+ end
21
+ def parse_args(args, opts_defn)
22
+ start_opts, parser_config = opts_defn.reduce([{}, []]) do |(ini, pcfg), (n, cfg)|
23
+ (vals, desc, short, klass) = cfg
24
+ (init_val, def_val) = Array(vals)
25
+
26
+ [
27
+ init_val.nil? ? ini : ini.merge(n => init_val),
28
+ pcfg + [[n, short, desc, def_val, klass]],
29
+ ]
30
+ end
31
+
32
+ require('optparse')
33
+
34
+ acc_opts = {}
35
+ prsr = OptionParser.new do |opt_p|
36
+ parser_config.each do |(n, short, desc, def_val, klass)|
37
+ (_, mark) = short.split(' ')
38
+ long = "--#{n.to_s.tr("_", "-")}" + (mark.nil? ? '' : " #{mark}")
39
+ opt_args = klass.nil? ? [short, long, desc] : [short, long, klass, desc]
40
+
41
+ T.unsafe(opt_p).on(*opt_args) do |v|
42
+ acc_opts[n] = if acc_opts.key?(n)
43
+ Array(acc_opts[n]) + Array(v || def_val)
44
+ else
45
+ v || def_val
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ arg_v = (args.is_a?(Array) ? args : args.strip.split(/\s+/)).map(&:strip)
52
+ sub = prsr.parse(arg_v)
53
+
54
+ { opts: start_opts.merge(acc_opts) }.tap do |a|
55
+ a[:sub] = sub if sub
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -94,10 +94,8 @@ module T
94
94
  def log_info_handler=(value); end
95
95
  def scalar_types; end
96
96
  def scalar_types=(values); end
97
- # rubocop:disable Naming/InclusiveLanguage
98
97
  def sealed_violation_whitelist; end
99
98
  def sealed_violation_whitelist=(sealed_violation_whitelist); end
100
- # rubocop:enable Naming/InclusiveLanguage
101
99
  def sig_builder_error_handler=(value); end
102
100
  def sig_validation_error_handler(error, opts); end
103
101
  def sig_validation_error_handler=(value); end
@@ -21,6 +21,8 @@ module CLI
21
21
  def teardown
22
22
  super
23
23
  assert_all_commands_run
24
+ rescue Errno::EACCES
25
+ # this sometimes happens on windows builds - let's ignore it
24
26
  end
25
27
 
26
28
  module FakeConfig
@@ -223,7 +225,7 @@ module CLI
223
225
  EOF
224
226
  end
225
227
 
226
- return nil if final_error.empty?
228
+ return if final_error.empty?
227
229
 
228
230
  "\n" + final_error.join("\n") # Initial new line for formatting reasons
229
231
  end
@@ -235,7 +237,7 @@ module CLI
235
237
 
236
238
  if expected_cmd.nil?
237
239
  @delegate_open3[a.join(' ')] = { unexpected: true }
238
- return nil
240
+ return
239
241
  end
240
242
 
241
243
  expected_cmd[:run] = true
@@ -237,11 +237,15 @@ module CLI
237
237
 
238
238
  previous_trailing = Hash.new('')
239
239
  loop do
240
+ break if Process.wait(pid, Process::WNOHANG)
241
+
240
242
  ios = [err_r, out_r].reject(&:closed?)
241
- break if ios.empty?
243
+ next if ios.empty?
244
+
245
+ readers, = IO.select(ios, [], [], 1)
246
+ next if readers.nil? # If IO.select times out we iterate again so we can check if the process has exited
242
247
 
243
- readers, = IO.select(ios)
244
- (readers || []).each do |io|
248
+ readers.each do |io|
245
249
  data, trailing = split_partial_characters(io.readpartial(4096))
246
250
  handlers[io].call(previous_trailing[io] + data)
247
251
  previous_trailing[io] = trailing
@@ -250,7 +254,6 @@ module CLI
250
254
  end
251
255
  end
252
256
 
253
- Process.wait(pid)
254
257
  $CHILD_STATUS
255
258
  end
256
259
 
@@ -297,7 +300,7 @@ module CLI
297
300
  def os
298
301
  return :mac if /darwin/.match(RUBY_PLATFORM)
299
302
  return :linux if /linux/.match(RUBY_PLATFORM)
300
- return :windows if /mingw32/.match(RUBY_PLATFORM)
303
+ return :windows if /mingw/.match(RUBY_PLATFORM)
301
304
 
302
305
  raise "Could not determine OS from platform #{RUBY_PLATFORM}"
303
306
  end
@@ -322,7 +325,7 @@ module CLI
322
325
  .returns([String, T::Array[String]])
323
326
  end
324
327
  def apply_sudo(cmd, args, sudo)
325
- return [cmd, args] unless sudo
328
+ return [cmd, args] if !sudo || Process.uid.zero?
326
329
 
327
330
  sudo_reason(sudo) if sudo.is_a?(String)
328
331
  ['sudo', args.unshift('-E', '-S', '-p', SUDO_PROMPT, '--', cmd)]
data/lib/cli/kit/util.rb CHANGED
@@ -18,8 +18,8 @@ module CLI
18
18
  # Converts a number to a human readable format on the SI scale
19
19
  #
20
20
  sig do
21
- params(number: Numeric, unit: String, factor: Integer, precision: Integer,
22
- space: T::Boolean).returns(String)
21
+ params(number: Numeric, unit: String, factor: Integer, precision: Integer, space: T::Boolean)
22
+ .returns(String)
23
23
  end
24
24
  def to_si_scale(number, unit = '', factor: 1000, precision: 2, space: false)
25
25
  raise ArgumentError, 'factor should only be 1000 or 1024' unless [1000, 1024].include?(factor)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CLI
4
4
  module Kit
5
- VERSION = '5.0.0'
5
+ VERSION = '5.1.0'
6
6
  end
7
7
  end
data/lib/cli/kit.rb CHANGED
@@ -23,6 +23,7 @@ module CLI
23
23
  autoload :Levenshtein, 'cli/kit/levenshtein'
24
24
  autoload :Logger, 'cli/kit/logger'
25
25
  autoload :Opts, 'cli/kit/opts'
26
+ autoload :ParseArgs, 'cli/kit/parse_args'
26
27
  autoload :Resolver, 'cli/kit/resolver'
27
28
  autoload :Support, 'cli/kit/support'
28
29
  autoload :System, 'cli/kit/system'
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cli-kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Burke Libbey
8
8
  - Aaron Olson
9
9
  - Lisa Ugray
10
- autorequire:
10
+ - Don Kelly
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2022-11-18 00:00:00.000000000 Z
13
+ date: 1980-01-02 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: cli-ui
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: '2.0'
21
+ version: '2.4'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: '2.0'
28
+ version: '2.4'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: bundler
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -73,6 +73,7 @@ email:
73
73
  - burke.libbey@shopify.com
74
74
  - aaron.olson@shopify.com
75
75
  - lisa.ugray@shopify.com
76
+ - don.kelly@shopify.com
76
77
  executables:
77
78
  - cli-kit
78
79
  extensions: []
@@ -85,6 +86,7 @@ files:
85
86
  - ".gitignore"
86
87
  - ".rubocop.sorbet.yml"
87
88
  - ".rubocop.yml"
89
+ - ".ruby-version"
88
90
  - Gemfile
89
91
  - Gemfile.lock
90
92
  - LICENSE.txt
@@ -144,6 +146,7 @@ files:
144
146
  - lib/cli/kit/levenshtein.rb
145
147
  - lib/cli/kit/logger.rb
146
148
  - lib/cli/kit/opts.rb
149
+ - lib/cli/kit/parse_args.rb
147
150
  - lib/cli/kit/resolver.rb
148
151
  - lib/cli/kit/sorbet_runtime_stub.rb
149
152
  - lib/cli/kit/support.rb
@@ -155,7 +158,6 @@ homepage: https://github.com/shopify/cli-kit
155
158
  licenses:
156
159
  - MIT
157
160
  metadata: {}
158
- post_install_message:
159
161
  rdoc_options: []
160
162
  require_paths:
161
163
  - lib
@@ -163,15 +165,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
163
165
  requirements:
164
166
  - - ">="
165
167
  - !ruby/object:Gem::Version
166
- version: '0'
168
+ version: '3.0'
167
169
  required_rubygems_version: !ruby/object:Gem::Requirement
168
170
  requirements:
169
171
  - - ">="
170
172
  - !ruby/object:Gem::Version
171
173
  version: '0'
172
174
  requirements: []
173
- rubygems_version: 3.2.33
174
- signing_key:
175
+ rubygems_version: 3.6.7
175
176
  specification_version: 4
176
177
  summary: Terminal UI framework extensions
177
178
  test_files: []