spoom 1.1.15 → 1.1.16

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: 2a61ae83fa56b7a78027c8954c5680d4784c5a3f8b2d717ed3ba49b36409ede2
4
- data.tar.gz: b339a398e57f92f71b797dd8d427e18749d1afd6246be42fe549baf96563706e
3
+ metadata.gz: 9c41426fe9cc0e4f20115b5ce81ff2256d00f255acf59f29beb7e6ffeef16b0c
4
+ data.tar.gz: ea751643663fc13175ad1ec23c39872a7b963b2f6f619a497e4bc6fc51052e8f
5
5
  SHA512:
6
- metadata.gz: 981c7b625e31b732ce731c600fd1291afb9635818918d77424750ba152633f06e8f4515037c5044badcc951ded1dd9fd768ae135ff2305359005a2cb7ad47a38
7
- data.tar.gz: 123baadb32b3341271b323eab29a1ddb4561c74b9afbe6cfa71af61ff1547783a24a1d439406f482b3c40920b960e4b04fc19ca7c0423c18407af00bc35fa692
6
+ metadata.gz: 4503195f8c603f0148f9393a2fdfdb5667ef6b6a9d43917484952409cfa69ce5edc86fda0275144451790d5e2928fe33b7fd19597ab0f9500678185e65f65b33
7
+ data.tar.gz: 4eb49038a48389c0ac8160c1f9b7e37f80275c8d39fda35a8d08b1e75bae0e763382f24419a1fc51a3e2c7972d4e4d8e2ef22996961bb9a003ee7ad4bbb1abbb
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  group :development do
9
- gem "pry-byebug"
9
+ gem "debug"
10
10
  gem "ruby-lsp"
11
11
  gem "rubocop-shopify", require: false
12
12
  gem "rubocop-sorbet", require: false
@@ -13,20 +13,36 @@ module Spoom
13
13
  default_task :bump
14
14
 
15
15
  desc "bump DIRECTORY", "Change Sorbet sigils from one strictness to another when no errors"
16
- option :from, type: :string, default: Spoom::Sorbet::Sigils::STRICTNESS_FALSE,
16
+ option :from,
17
+ type: :string,
18
+ default: Spoom::Sorbet::Sigils::STRICTNESS_FALSE,
17
19
  desc: "Change only files from this strictness"
18
- option :to, type: :string, default: Spoom::Sorbet::Sigils::STRICTNESS_TRUE,
20
+ option :to,
21
+ type: :string,
22
+ default: Spoom::Sorbet::Sigils::STRICTNESS_TRUE,
19
23
  desc: "Change files to this strictness"
20
- option :force, type: :boolean, default: false, aliases: :f,
24
+ option :force,
25
+ type: :boolean,
26
+ default: false,
27
+ aliases: :f,
21
28
  desc: "Change strictness without type checking"
22
29
  option :sorbet, type: :string, desc: "Path to custom Sorbet bin"
23
- option :dry, type: :boolean, default: false, aliases: :d,
30
+ option :dry,
31
+ type: :boolean,
32
+ default: false,
33
+ aliases: :d,
24
34
  desc: "Only display what would happen, do not actually change sigils"
25
- option :only, type: :string, default: nil, aliases: :o,
35
+ option :only,
36
+ type: :string,
37
+ default: nil,
38
+ aliases: :o,
26
39
  desc: "Only change specified list (one file by line)"
27
- option :suggest_bump_command, type: :string,
40
+ option :suggest_bump_command,
41
+ type: :string,
28
42
  desc: "Command to suggest if files can be bumped"
29
- option :count_errors, type: :boolean, default: false,
43
+ option :count_errors,
44
+ type: :boolean,
45
+ default: false,
30
46
  desc: "Count the number of errors if all files were bumped"
31
47
  option :sorbet_options, type: :string, default: "", desc: "Pass options to Sorbet"
32
48
  sig { params(directory: String).void }
@@ -85,20 +101,33 @@ module Spoom
85
101
  end
86
102
 
87
103
  error_url_base = Spoom::Sorbet::Errors::DEFAULT_ERROR_URL_BASE
88
- result = Sorbet.srb_tc(
89
- *options[:sorbet_options].split(" "),
90
- "--error-url-base=#{error_url_base}",
91
- path: exec_path,
92
- capture_err: true,
93
- sorbet_bin: options[:sorbet],
94
- )
95
-
96
- check_sorbet_segfault(result.exit_code) do
104
+ result = begin
105
+ Sorbet.srb_tc(
106
+ *options[:sorbet_options].split(" "),
107
+ "--error-url-base=#{error_url_base}",
108
+ path: exec_path,
109
+ capture_err: true,
110
+ sorbet_bin: options[:sorbet],
111
+ )
112
+ rescue Spoom::Sorbet::Error::Segfault => error
97
113
  say_error(<<~ERR, status: nil)
114
+ !!! Sorbet exited with code #{Spoom::Sorbet::SEGFAULT_CODE} - SEGFAULT !!!
115
+
116
+ This is most likely related to a bug in Sorbet.
98
117
  It means one of the file bumped to `typed: #{to}` made Sorbet crash.
99
118
  Run `spoom bump -f` locally followed by `bundle exec srb tc` to investigate the problem.
100
119
  ERR
101
120
  undo_changes(files_to_bump, from)
121
+ exit(error.result.exit_code)
122
+ rescue Spoom::Sorbet::Error::Killed => error
123
+ say_error(<<~ERR, status: nil)
124
+ !!! Sorbet exited with code #{Spoom::Sorbet::KILLED_CODE} - KILLED !!!
125
+
126
+ It means Sorbet was killed while executing. Changes to files have not been applied.
127
+ Re-run `spoom bump` to try again.
128
+ ERR
129
+ undo_changes(files_to_bump, from)
130
+ exit(error.result.exit_code)
102
131
  end
103
132
 
104
133
  if result.status
@@ -115,17 +115,30 @@ module Spoom
115
115
 
116
116
  desc "report", "Produce a typing coverage report"
117
117
  option :data, type: :string, default: DATA_DIR, desc: "Snapshots JSON data"
118
- option :file, type: :string, default: "spoom_report.html", aliases: :f,
118
+ option :file,
119
+ type: :string,
120
+ default: "spoom_report.html",
121
+ aliases: :f,
119
122
  desc: "Save report to file"
120
- option :color_ignore, type: :string, default: Spoom::Coverage::D3::COLOR_IGNORE,
123
+ option :color_ignore,
124
+ type: :string,
125
+ default: Spoom::Coverage::D3::COLOR_IGNORE,
121
126
  desc: "Color used for typed: ignore"
122
- option :color_false, type: :string, default: Spoom::Coverage::D3::COLOR_FALSE,
127
+ option :color_false,
128
+ type: :string,
129
+ default: Spoom::Coverage::D3::COLOR_FALSE,
123
130
  desc: "Color used for typed: false"
124
- option :color_true, type: :string, default: Spoom::Coverage::D3::COLOR_TRUE,
131
+ option :color_true,
132
+ type: :string,
133
+ default: Spoom::Coverage::D3::COLOR_TRUE,
125
134
  desc: "Color used for typed: true"
126
- option :color_strict, type: :string, default: Spoom::Coverage::D3::COLOR_STRICT,
135
+ option :color_strict,
136
+ type: :string,
137
+ default: Spoom::Coverage::D3::COLOR_STRICT,
127
138
  desc: "Color used for typed: strict"
128
- option :color_strong, type: :string, default: Spoom::Coverage::D3::COLOR_STRONG,
139
+ option :color_strong,
140
+ type: :string,
141
+ default: Spoom::Coverage::D3::COLOR_STRONG,
129
142
  desc: "Color used for typed: strong"
130
143
  def report
131
144
  in_sorbet_project!
@@ -83,20 +83,6 @@ module Spoom
83
83
  Sorbet::Config.parse_file(sorbet_config_file)
84
84
  end
85
85
 
86
- sig { params(exit_code: Integer, block: T.nilable(T.proc.void)).void }
87
- def check_sorbet_segfault(exit_code, &block)
88
- return unless exit_code == Spoom::Sorbet::SEGFAULT_CODE
89
-
90
- say_error(<<~ERR, status: nil)
91
- #{red("!!! Sorbet exited with code #{exit_code} - SEGFAULT !!!")}
92
-
93
- This is most likely related to a bug in Sorbet.
94
- ERR
95
-
96
- block&.call
97
- exit(exit_code)
98
- end
99
-
100
86
  # Colors
101
87
 
102
88
  # Color used to highlight expressions in backticks
data/lib/spoom/cli/run.rb CHANGED
@@ -43,7 +43,6 @@ module Spoom
43
43
  sorbet_bin: sorbet,
44
44
  )
45
45
 
46
- check_sorbet_segfault(result.code)
47
46
  say_error(result.err, status: nil, nl: false)
48
47
  exit(result.status)
49
48
  end
@@ -57,8 +56,6 @@ module Spoom
57
56
  sorbet_bin: sorbet,
58
57
  )
59
58
 
60
- check_sorbet_segfault(result.exit_code)
61
-
62
59
  if result.status
63
60
  say_error(result.err, status: nil, nl: false)
64
61
  exit(0)
@@ -109,6 +106,20 @@ module Spoom
109
106
  end
110
107
 
111
108
  exit(1)
109
+ rescue Spoom::Sorbet::Error::Segfault => error
110
+ say_error(<<~ERR, status: nil)
111
+ #{red("!!! Sorbet exited with code #{error.result.exit_code} - SEGFAULT !!!")}
112
+
113
+ This is most likely related to a bug in Sorbet.
114
+ ERR
115
+
116
+ exit(error.result.exit_code)
117
+ rescue Spoom::Sorbet::Error::Killed => error
118
+ say_error(<<~ERR, status: nil)
119
+ #{red("!!! Sorbet exited with code #{error.result.exit_code} - KILLED !!!")}
120
+ ERR
121
+
122
+ exit(error.result.exit_code)
112
123
  end
113
124
 
114
125
  no_commands do
data/lib/spoom/context.rb CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  require "fileutils"
5
5
  require "open3"
6
+ require "tmpdir"
6
7
 
7
8
  module Spoom
8
9
  # An abstraction to a Ruby project context
@@ -132,7 +133,7 @@ module Spoom
132
133
  ExecResult.new(out: out, err: err, status: T.must(status.success?), exit_code: T.must(status.exitstatus))
133
134
  else
134
135
  out, status = Open3.capture2(command, opts)
135
- ExecResult.new(out: out, err: "", status: T.must(status.success?), exit_code: T.must(status.exitstatus))
136
+ ExecResult.new(out: out, err: nil, status: T.must(status.success?), exit_code: T.must(status.exitstatus))
136
137
  end
137
138
  end
138
139
  end
@@ -179,9 +180,16 @@ module Spoom
179
180
  end
180
181
 
181
182
  # Run `git init` in this context directory
182
- sig { params(branch: String).void }
183
- def git_init!(branch: "main")
184
- git("init -q -b #{branch}")
183
+ #
184
+ # Warning: passing a branch will run `git init -b <branch>` which is only available in git 2.28+.
185
+ # In older versions, use `git_init!` followed by `git("checkout -b <branch>")`.
186
+ sig { params(branch: T.nilable(String)).returns(ExecResult) }
187
+ def git_init!(branch: nil)
188
+ if branch
189
+ git("init -b #{branch}")
190
+ else
191
+ git("init")
192
+ end
185
193
  end
186
194
 
187
195
  # Run `git checkout` in this context directory
@@ -147,7 +147,7 @@ module Spoom
147
147
  def print_map(hash, total)
148
148
  indent
149
149
  hash.each do |key, value|
150
- next unless value > 0
150
+ next if value <= 0
151
151
 
152
152
  printl("#{key}: #{value}#{percent(value, total)}")
153
153
  end
@@ -63,8 +63,10 @@ module Spoom
63
63
 
64
64
  if metrics_without_rbis
65
65
  snapshot.methods_with_sig_excluding_rbis = metrics_without_rbis.fetch("types.sig.count", 0)
66
- snapshot.methods_without_sig_excluding_rbis = metrics_without_rbis.fetch("types.input.methods.total",
67
- 0) - snapshot.methods_with_sig_excluding_rbis
66
+ snapshot.methods_without_sig_excluding_rbis = metrics_without_rbis.fetch(
67
+ "types.input.methods.total",
68
+ 0,
69
+ ) - snapshot.methods_with_sig_excluding_rbis
68
70
  end
69
71
 
70
72
  Snapshot::STRICTNESSES.each do |strictness|
data/lib/spoom/git.rb CHANGED
@@ -21,52 +21,31 @@ module Spoom
21
21
  class << self
22
22
  extend T::Sig
23
23
 
24
- # Execute a `command`
25
- sig { params(command: String, arg: String, path: String).returns(ExecResult) }
26
- def exec(command, *arg, path: ".")
27
- return ExecResult.new(
28
- out: "",
29
- err: "Error: `#{path}` is not a directory.",
30
- status: false,
31
- exit_code: 1,
32
- ) unless File.directory?(path)
33
-
34
- T.unsafe(Open3).popen3(command, *arg, chdir: path) do |_, stdout, stderr, thread|
35
- status = T.cast(thread.value, Process::Status)
36
- ExecResult.new(
37
- out: stdout.read,
38
- err: stderr.read,
39
- status: T.must(status.success?),
40
- exit_code: T.must(status.exitstatus),
41
- )
42
- end
43
- end
44
-
45
24
  # Git commands
46
25
 
47
26
  sig { params(arg: String, path: String).returns(ExecResult) }
48
27
  def checkout(*arg, path: ".")
49
- exec("git checkout -q #{arg.join(" ")}", path: path)
28
+ Spoom.exec("git checkout -q #{arg.join(" ")}", path: path)
50
29
  end
51
30
 
52
31
  sig { params(arg: String, path: String).returns(ExecResult) }
53
32
  def diff(*arg, path: ".")
54
- exec("git diff #{arg.join(" ")}", path: path)
33
+ Spoom.exec("git diff #{arg.join(" ")}", path: path)
55
34
  end
56
35
 
57
36
  sig { params(arg: String, path: String).returns(ExecResult) }
58
37
  def log(*arg, path: ".")
59
- exec("git log #{arg.join(" ")}", path: path)
38
+ Spoom.exec("git log #{arg.join(" ")}", path: path)
60
39
  end
61
40
 
62
41
  sig { params(arg: String, path: String).returns(ExecResult) }
63
42
  def show(*arg, path: ".")
64
- exec("git show #{arg.join(" ")}", path: path)
43
+ Spoom.exec("git show #{arg.join(" ")}", path: path)
65
44
  end
66
45
 
67
46
  sig { params(path: String).returns(T.nilable(String)) }
68
47
  def current_branch(path: ".")
69
- result = exec("git branch --show-current", path: path)
48
+ result = Spoom.exec("git branch --show-current", path: path)
70
49
  return nil unless result.status
71
50
 
72
51
  result.out.strip
@@ -18,13 +18,16 @@ module Spoom
18
18
  class Parser
19
19
  extend T::Sig
20
20
 
21
- HEADER = T.let([
22
- "👋 Hey there! Heads up that this is not a release build of sorbet.",
23
- "Release builds are faster and more well-supported by the Sorbet team.",
24
- "Check out the README to learn how to build Sorbet in release mode.",
25
- "To forcibly silence this error, either pass --silence-dev-message,",
26
- "or set SORBET_SILENCE_DEV_MESSAGE=1 in your shell environment.",
27
- ], T::Array[String])
21
+ HEADER = T.let(
22
+ [
23
+ "👋 Hey there! Heads up that this is not a release build of sorbet.",
24
+ "Release builds are faster and more well-supported by the Sorbet team.",
25
+ "Check out the README to learn how to build Sorbet in release mode.",
26
+ "To forcibly silence this error, either pass --silence-dev-message,",
27
+ "or set SORBET_SILENCE_DEV_MESSAGE=1 in your shell environment.",
28
+ ],
29
+ T::Array[String],
30
+ )
28
31
 
29
32
  class << self
30
33
  extend T::Sig
@@ -273,34 +273,37 @@ module Spoom
273
273
  SYMBOL_KINDS[kind] || "<unknown:#{kind}>"
274
274
  end
275
275
 
276
- SYMBOL_KINDS = T.let({
277
- 1 => "file",
278
- 2 => "module",
279
- 3 => "namespace",
280
- 4 => "package",
281
- 5 => "class",
282
- 6 => "def",
283
- 7 => "property",
284
- 8 => "field",
285
- 9 => "constructor",
286
- 10 => "enum",
287
- 11 => "interface",
288
- 12 => "function",
289
- 13 => "variable",
290
- 14 => "const",
291
- 15 => "string",
292
- 16 => "number",
293
- 17 => "boolean",
294
- 18 => "array",
295
- 19 => "object",
296
- 20 => "key",
297
- 21 => "null",
298
- 22 => "enum_member",
299
- 23 => "struct",
300
- 24 => "event",
301
- 25 => "operator",
302
- 26 => "type_parameter",
303
- }, T::Hash[Integer, String])
276
+ SYMBOL_KINDS = T.let(
277
+ {
278
+ 1 => "file",
279
+ 2 => "module",
280
+ 3 => "namespace",
281
+ 4 => "package",
282
+ 5 => "class",
283
+ 6 => "def",
284
+ 7 => "property",
285
+ 8 => "field",
286
+ 9 => "constructor",
287
+ 10 => "enum",
288
+ 11 => "interface",
289
+ 12 => "function",
290
+ 13 => "variable",
291
+ 14 => "const",
292
+ 15 => "string",
293
+ 16 => "number",
294
+ 17 => "boolean",
295
+ 18 => "array",
296
+ 19 => "object",
297
+ 20 => "key",
298
+ 21 => "null",
299
+ 22 => "enum_member",
300
+ 23 => "struct",
301
+ 24 => "event",
302
+ 25 => "operator",
303
+ 26 => "type_parameter",
304
+ },
305
+ T::Hash[Integer, String],
306
+ )
304
307
  end
305
308
 
306
309
  class SymbolPrinter < Printer
@@ -16,14 +16,17 @@ module Spoom
16
16
  STRICTNESS_STRONG = "strong"
17
17
  STRICTNESS_INTERNAL = "__STDLIB_INTERNAL"
18
18
 
19
- VALID_STRICTNESS = T.let([
20
- STRICTNESS_IGNORE,
21
- STRICTNESS_FALSE,
22
- STRICTNESS_TRUE,
23
- STRICTNESS_STRICT,
24
- STRICTNESS_STRONG,
25
- STRICTNESS_INTERNAL,
26
- ].freeze, T::Array[String])
19
+ VALID_STRICTNESS = T.let(
20
+ [
21
+ STRICTNESS_IGNORE,
22
+ STRICTNESS_FALSE,
23
+ STRICTNESS_TRUE,
24
+ STRICTNESS_STRICT,
25
+ STRICTNESS_STRONG,
26
+ STRICTNESS_INTERNAL,
27
+ ].freeze,
28
+ T::Array[String],
29
+ )
27
30
 
28
31
  SIGIL_REGEXP = T.let(/^#[\ t]*typed[\ t]*:[ \t]*(\w*)[ \t]*/.freeze, Regexp)
29
32
 
data/lib/spoom/sorbet.rb CHANGED
@@ -11,10 +11,33 @@ require "open3"
11
11
 
12
12
  module Spoom
13
13
  module Sorbet
14
+ class Error < StandardError
15
+ extend T::Sig
16
+
17
+ class Killed < Error; end
18
+ class Segfault < Error; end
19
+
20
+ sig { returns(ExecResult) }
21
+ attr_reader :result
22
+
23
+ sig do
24
+ params(
25
+ message: String,
26
+ result: ExecResult,
27
+ ).void
28
+ end
29
+ def initialize(message, result)
30
+ super(message)
31
+
32
+ @result = result
33
+ end
34
+ end
35
+
14
36
  CONFIG_PATH = "sorbet/config"
15
37
  GEM_PATH = T.let(Gem::Specification.find_by_name("sorbet-static").full_gem_path, String)
16
38
  BIN_PATH = T.let((Pathname.new(GEM_PATH) / "libexec" / "sorbet").to_s, String)
17
39
 
40
+ KILLED_CODE = 137
18
41
  SEGFAULT_CODE = 139
19
42
 
20
43
  class << self
@@ -34,7 +57,16 @@ module Spoom
34
57
  else
35
58
  arg.prepend("bundle", "exec", "srb")
36
59
  end
37
- Spoom.exec(*T.unsafe(arg), path: path, capture_err: capture_err)
60
+ result = Spoom.exec(*T.unsafe(arg), path: path, capture_err: capture_err)
61
+
62
+ case result.exit_code
63
+ when KILLED_CODE
64
+ raise Error::Killed.new("Sorbet was killed.", result)
65
+ when SEGFAULT_CODE
66
+ raise Error::Segfault.new("Sorbet segfaulted.", result)
67
+ end
68
+
69
+ result
38
70
  end
39
71
 
40
72
  sig do
@@ -69,14 +101,17 @@ module Spoom
69
101
  ).returns(T.nilable(String))
70
102
  end
71
103
  def srb_version(*arg, path: ".", capture_err: false, sorbet_bin: nil)
72
- result = T.let(T.unsafe(self).srb_tc(
73
- "--no-config",
74
- "--version",
75
- *arg,
76
- path: path,
77
- capture_err: capture_err,
78
- sorbet_bin: sorbet_bin,
79
- ), ExecResult)
104
+ result = T.let(
105
+ T.unsafe(self).srb_tc(
106
+ "--no-config",
107
+ "--version",
108
+ *arg,
109
+ path: path,
110
+ capture_err: capture_err,
111
+ sorbet_bin: sorbet_bin,
112
+ ),
113
+ ExecResult,
114
+ )
80
115
  return nil unless result.status
81
116
 
82
117
  result.out.split(" ")[2]
data/lib/spoom/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Spoom
5
- VERSION = "1.1.15"
5
+ VERSION = "1.1.16"
6
6
  end
data/lib/spoom.rb CHANGED
@@ -15,7 +15,7 @@ module Spoom
15
15
  extend T::Sig
16
16
 
17
17
  const :out, String
18
- const :err, String
18
+ const :err, T.nilable(String)
19
19
  const :status, T::Boolean
20
20
  const :exit_code, Integer
21
21
 
@@ -25,7 +25,7 @@ module Spoom
25
25
  ########## STDOUT ##########
26
26
  #{out.empty? ? "<empty>" : out}
27
27
  ########## STDERR ##########
28
- #{err.empty? ? "<empty>" : err}
28
+ #{err&.empty? ? "<empty>" : err}
29
29
  ########## STATUS: #{status} ##########
30
30
  STR
31
31
  end
@@ -42,7 +42,7 @@ module Spoom
42
42
  capture_err: T::Boolean,
43
43
  ).returns(ExecResult)
44
44
  end
45
- def exec(cmd, *arg, path: ".", capture_err: false)
45
+ def exec(cmd, *arg, path: ".", capture_err: true)
46
46
  if capture_err
47
47
  stdout, stderr, status = T.unsafe(Open3).capture3([cmd, *arg].join(" "), chdir: path)
48
48
  ExecResult.new(
@@ -55,7 +55,7 @@ module Spoom
55
55
  stdout, status = T.unsafe(Open3).capture2([cmd, *arg].join(" "), chdir: path)
56
56
  ExecResult.new(
57
57
  out: stdout,
58
- err: "",
58
+ err: nil,
59
59
  status: status.success?,
60
60
  exit_code: status.exitstatus,
61
61
  )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spoom
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.15
4
+ version: 1.1.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre Terrasa
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-14 00:00:00.000000000 Z
11
+ date: 2023-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler