spoom 1.1.11 → 1.1.12
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 +4 -4
- data/Gemfile +1 -0
- data/README.md +6 -0
- data/Rakefile +1 -0
- data/lib/spoom/cli/bump.rb +11 -7
- data/lib/spoom/cli/coverage.rb +11 -7
- data/lib/spoom/cli/helper.rb +5 -4
- data/lib/spoom/cli/lsp.rb +2 -1
- data/lib/spoom/cli/run.rb +16 -6
- data/lib/spoom/cli.rb +6 -4
- data/lib/spoom/context.rb +219 -0
- data/lib/spoom/coverage/d3/base.rb +12 -8
- data/lib/spoom/coverage/d3/circle_map.rb +40 -37
- data/lib/spoom/coverage/d3/pie.rb +30 -26
- data/lib/spoom/coverage/d3/timeline.rb +86 -82
- data/lib/spoom/coverage/d3.rb +72 -70
- data/lib/spoom/coverage/report.rb +6 -6
- data/lib/spoom/coverage/snapshot.rb +40 -33
- data/lib/spoom/coverage.rb +84 -81
- data/lib/spoom/file_tree.rb +2 -0
- data/lib/spoom/git.rb +107 -97
- data/lib/spoom/printer.rb +4 -0
- data/lib/spoom/sorbet/errors.rb +29 -11
- data/lib/spoom/sorbet/lsp/base.rb +1 -1
- data/lib/spoom/sorbet/lsp/errors.rb +23 -17
- data/lib/spoom/sorbet/lsp/structures.rb +85 -54
- data/lib/spoom/sorbet/lsp.rb +71 -63
- data/lib/spoom/sorbet/metrics.rb +18 -16
- data/lib/spoom/sorbet/sigils.rb +59 -54
- data/lib/spoom/sorbet.rb +11 -8
- data/lib/spoom/timeline.rb +1 -0
- data/lib/spoom/version.rb +1 -1
- data/lib/spoom.rb +43 -25
- metadata +20 -20
- data/lib/spoom/test_helpers/project.rb +0 -138
data/lib/spoom/sorbet.rb
CHANGED
@@ -28,7 +28,7 @@ module Spoom
|
|
28
28
|
sorbet_bin: T.nilable(String)
|
29
29
|
).returns(ExecResult)
|
30
30
|
end
|
31
|
-
def srb(*arg, path:
|
31
|
+
def srb(*arg, path: ".", capture_err: false, sorbet_bin: nil)
|
32
32
|
if sorbet_bin
|
33
33
|
arg.prepend(sorbet_bin)
|
34
34
|
else
|
@@ -45,17 +45,17 @@ module Spoom
|
|
45
45
|
sorbet_bin: T.nilable(String)
|
46
46
|
).returns(ExecResult)
|
47
47
|
end
|
48
|
-
def srb_tc(*arg, path:
|
48
|
+
def srb_tc(*arg, path: ".", capture_err: false, sorbet_bin: nil)
|
49
49
|
arg.prepend("tc") unless sorbet_bin
|
50
50
|
srb(*T.unsafe(arg), path: path, capture_err: capture_err, sorbet_bin: sorbet_bin)
|
51
51
|
end
|
52
52
|
|
53
53
|
# List all files typechecked by Sorbet from its `config`
|
54
54
|
sig { params(config: Config, path: String).returns(T::Array[String]) }
|
55
|
-
def srb_files(config, path:
|
55
|
+
def srb_files(config, path: ".")
|
56
56
|
regs = config.ignore.map { |string| Regexp.new(Regexp.escape(string)) }
|
57
|
-
exts = config.allowed_extensions.empty? ? [
|
58
|
-
Dir.glob((Pathname.new(path) / "**/*{#{exts.join(
|
57
|
+
exts = config.allowed_extensions.empty? ? [".rb", ".rbi"] : config.allowed_extensions
|
58
|
+
Dir.glob((Pathname.new(path) / "**/*{#{exts.join(",")}}").to_s).reject do |f|
|
59
59
|
regs.any? { |re| re.match?(f) }
|
60
60
|
end.sort
|
61
61
|
end
|
@@ -68,7 +68,7 @@ module Spoom
|
|
68
68
|
sorbet_bin: T.nilable(String)
|
69
69
|
).returns(T.nilable(String))
|
70
70
|
end
|
71
|
-
def srb_version(*arg, path:
|
71
|
+
def srb_version(*arg, path: ".", capture_err: false, sorbet_bin: nil)
|
72
72
|
result = T.let(T.unsafe(self).srb_tc(
|
73
73
|
"--no-config",
|
74
74
|
"--version",
|
@@ -78,6 +78,7 @@ module Spoom
|
|
78
78
|
sorbet_bin: sorbet_bin
|
79
79
|
), ExecResult)
|
80
80
|
return nil unless result.status
|
81
|
+
|
81
82
|
result.out.split(" ")[2]
|
82
83
|
end
|
83
84
|
|
@@ -89,7 +90,7 @@ module Spoom
|
|
89
90
|
sorbet_bin: T.nilable(String)
|
90
91
|
).returns(T.nilable(T::Hash[String, Integer]))
|
91
92
|
end
|
92
|
-
def srb_metrics(*arg, path:
|
93
|
+
def srb_metrics(*arg, path: ".", capture_err: false, sorbet_bin: nil)
|
93
94
|
metrics_file = "metrics.tmp"
|
94
95
|
metrics_path = "#{path}/#{metrics_file}"
|
95
96
|
T.unsafe(self).srb_tc(
|
@@ -112,11 +113,13 @@ module Spoom
|
|
112
113
|
#
|
113
114
|
# Returns `nil` if `gem` cannot be found in the Gemfile.
|
114
115
|
sig { params(gem: String, path: String).returns(T.nilable(String)) }
|
115
|
-
def version_from_gemfile_lock(gem:
|
116
|
+
def version_from_gemfile_lock(gem: "sorbet", path: ".")
|
116
117
|
gemfile_path = "#{path}/Gemfile.lock"
|
117
118
|
return nil unless File.exist?(gemfile_path)
|
119
|
+
|
118
120
|
content = File.read(gemfile_path).match(/^ #{gem} \(.*(\d+\.\d+\.\d+).*\)/)
|
119
121
|
return nil unless content
|
122
|
+
|
120
123
|
content[1]
|
121
124
|
end
|
122
125
|
end
|
data/lib/spoom/timeline.rb
CHANGED
data/lib/spoom/version.rb
CHANGED
data/lib/spoom.rb
CHANGED
@@ -12,41 +12,59 @@ module Spoom
|
|
12
12
|
class Error < StandardError; end
|
13
13
|
|
14
14
|
class ExecResult < T::Struct
|
15
|
+
extend T::Sig
|
16
|
+
|
15
17
|
const :out, String
|
16
18
|
const :err, String
|
17
19
|
const :status, T::Boolean
|
18
20
|
const :exit_code, Integer
|
19
|
-
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
sig { returns(String) }
|
23
|
+
def to_s
|
24
|
+
<<~STR
|
25
|
+
########## STDOUT ##########
|
26
|
+
#{out.empty? ? "<empty>" : out}
|
27
|
+
########## STDERR ##########
|
28
|
+
#{err.empty? ? "<empty>" : err}
|
29
|
+
########## STATUS: #{status} ##########
|
30
|
+
STR
|
31
|
+
end
|
28
32
|
end
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
status:
|
44
|
-
|
45
|
-
|
33
|
+
|
34
|
+
class << self
|
35
|
+
extend T::Sig
|
36
|
+
|
37
|
+
sig do
|
38
|
+
params(
|
39
|
+
cmd: String,
|
40
|
+
arg: String,
|
41
|
+
path: String,
|
42
|
+
capture_err: T::Boolean
|
43
|
+
).returns(ExecResult)
|
44
|
+
end
|
45
|
+
def exec(cmd, *arg, path: ".", capture_err: false)
|
46
|
+
if capture_err
|
47
|
+
stdout, stderr, status = T.unsafe(Open3).capture3([cmd, *arg].join(" "), chdir: path)
|
48
|
+
ExecResult.new(
|
49
|
+
out: stdout,
|
50
|
+
err: stderr,
|
51
|
+
status: status.success?,
|
52
|
+
exit_code: status.exitstatus
|
53
|
+
)
|
54
|
+
else
|
55
|
+
stdout, status = T.unsafe(Open3).capture2([cmd, *arg].join(" "), chdir: path)
|
56
|
+
ExecResult.new(
|
57
|
+
out: stdout,
|
58
|
+
err: "",
|
59
|
+
status: status.success?,
|
60
|
+
exit_code: status.exitstatus
|
61
|
+
)
|
62
|
+
end
|
46
63
|
end
|
47
64
|
end
|
48
65
|
end
|
49
66
|
|
67
|
+
require "spoom/context"
|
50
68
|
require "spoom/colors"
|
51
69
|
require "spoom/sorbet"
|
52
70
|
require "spoom/cli"
|
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.
|
4
|
+
version: 1.1.12
|
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-
|
11
|
+
date: 2022-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -25,49 +25,49 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 2.2.10
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: minitest
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: '5.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: '5.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name: minitest
|
42
|
+
name: minitest-reporters
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 13.0.1
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 13.0.1
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name: sorbet
|
70
|
+
name: sorbet
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 0.5.9204
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name: sorbet
|
84
|
+
name: sorbet-runtime
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -129,6 +129,7 @@ files:
|
|
129
129
|
- lib/spoom/cli/lsp.rb
|
130
130
|
- lib/spoom/cli/run.rb
|
131
131
|
- lib/spoom/colors.rb
|
132
|
+
- lib/spoom/context.rb
|
132
133
|
- lib/spoom/coverage.rb
|
133
134
|
- lib/spoom/coverage/d3.rb
|
134
135
|
- lib/spoom/coverage/d3/base.rb
|
@@ -149,7 +150,6 @@ files:
|
|
149
150
|
- lib/spoom/sorbet/lsp/structures.rb
|
150
151
|
- lib/spoom/sorbet/metrics.rb
|
151
152
|
- lib/spoom/sorbet/sigils.rb
|
152
|
-
- lib/spoom/test_helpers/project.rb
|
153
153
|
- lib/spoom/timeline.rb
|
154
154
|
- lib/spoom/version.rb
|
155
155
|
- templates/card.erb
|
@@ -168,14 +168,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
168
168
|
requirements:
|
169
169
|
- - ">="
|
170
170
|
- !ruby/object:Gem::Version
|
171
|
-
version: 2.
|
171
|
+
version: 2.7.0
|
172
172
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
173
173
|
requirements:
|
174
174
|
- - ">="
|
175
175
|
- !ruby/object:Gem::Version
|
176
176
|
version: '0'
|
177
177
|
requirements: []
|
178
|
-
rubygems_version: 3.
|
178
|
+
rubygems_version: 3.3.3
|
179
179
|
signing_key:
|
180
180
|
specification_version: 4
|
181
181
|
summary: Useful tools for Sorbet enthusiasts.
|
@@ -1,138 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "fileutils"
|
5
|
-
require "open3"
|
6
|
-
require "pathname"
|
7
|
-
|
8
|
-
require_relative "../git"
|
9
|
-
|
10
|
-
module Spoom
|
11
|
-
module TestHelpers
|
12
|
-
# A simple project abstraction for testing purposes
|
13
|
-
class Project
|
14
|
-
extend T::Sig
|
15
|
-
|
16
|
-
# The absolute path to this test project
|
17
|
-
sig { returns(String) }
|
18
|
-
attr_reader :path
|
19
|
-
|
20
|
-
# Create a new test project at `path`
|
21
|
-
sig { params(path: String).void }
|
22
|
-
def initialize(path)
|
23
|
-
@path = path
|
24
|
-
FileUtils.rm_rf(@path)
|
25
|
-
FileUtils.mkdir_p(@path)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Content
|
29
|
-
|
30
|
-
# Set the content of the Gemfile in this project
|
31
|
-
sig { params(content: String).void }
|
32
|
-
def gemfile(content)
|
33
|
-
write("Gemfile", content)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Set the content of `sorbet/config` in this project
|
37
|
-
sig { params(content: String).void }
|
38
|
-
def sorbet_config(content)
|
39
|
-
write("sorbet/config", content)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Write `content` in the file at `rel_path`
|
43
|
-
sig { params(rel_path: String, content: String).void }
|
44
|
-
def write(rel_path, content = "")
|
45
|
-
path = absolute_path(rel_path)
|
46
|
-
FileUtils.mkdir_p(File.dirname(path))
|
47
|
-
File.write(path, content)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Remove `rel_path`
|
51
|
-
sig { params(rel_path: String).void }
|
52
|
-
def remove(rel_path)
|
53
|
-
FileUtils.rm_rf(absolute_path(rel_path))
|
54
|
-
end
|
55
|
-
|
56
|
-
# List all files in this project
|
57
|
-
sig { returns(T::Array[String]) }
|
58
|
-
def files
|
59
|
-
Dir.glob("#{@path}/**/*").sort
|
60
|
-
end
|
61
|
-
|
62
|
-
# Return the content of the file at `rel_path`
|
63
|
-
sig { params(rel_path: String).returns(String) }
|
64
|
-
def read(rel_path)
|
65
|
-
File.read(absolute_path(rel_path))
|
66
|
-
end
|
67
|
-
|
68
|
-
# Actions
|
69
|
-
|
70
|
-
# Run `git init` in this project
|
71
|
-
sig { params(branch: String).void }
|
72
|
-
def git_init(branch: "main")
|
73
|
-
Spoom::Git.exec("git init -q -b #{branch}", path: path)
|
74
|
-
Spoom::Git.exec("git config user.name 'spoom-tests'", path: path)
|
75
|
-
Spoom::Git.exec("git config user.email 'spoom@shopify.com'", path: path)
|
76
|
-
end
|
77
|
-
|
78
|
-
# Commit all new changes in this project
|
79
|
-
sig { params(message: String, date: Time).void }
|
80
|
-
def commit(message = "message", date: Time.now.utc)
|
81
|
-
Spoom::Git.exec("git add --all", path: path)
|
82
|
-
Spoom::Git.exec("GIT_COMMITTER_DATE=\"#{date}\" git commit -m '#{message}' --date '#{date}'", path: path)
|
83
|
-
end
|
84
|
-
|
85
|
-
# Run `bundle install` in this project
|
86
|
-
sig { returns(ExecResult) }
|
87
|
-
def bundle_install
|
88
|
-
opts = {}
|
89
|
-
opts[:chdir] = path
|
90
|
-
out, err, status = Open3.capture3("bundle", "install", opts)
|
91
|
-
ExecResult.new(
|
92
|
-
out: out,
|
93
|
-
err: err,
|
94
|
-
status: T.must(status.success?),
|
95
|
-
exit_code: T.must(status.exitstatus)
|
96
|
-
)
|
97
|
-
end
|
98
|
-
|
99
|
-
# Run a command with `bundle exec` in this project
|
100
|
-
sig { params(cmd: String, args: String).returns(ExecResult) }
|
101
|
-
def bundle_exec(cmd, *args)
|
102
|
-
opts = {}
|
103
|
-
opts[:chdir] = path
|
104
|
-
out, err, status = Open3.capture3(["bundle", "exec", cmd, *args].join(' '), opts)
|
105
|
-
ExecResult.new(
|
106
|
-
out: out,
|
107
|
-
err: err,
|
108
|
-
status: T.must(status.success?),
|
109
|
-
exit_code: T.must(status.exitstatus)
|
110
|
-
)
|
111
|
-
end
|
112
|
-
|
113
|
-
# Delete this project and its content
|
114
|
-
sig { void }
|
115
|
-
def destroy
|
116
|
-
FileUtils.rm_rf(path)
|
117
|
-
end
|
118
|
-
|
119
|
-
sig { params(name: String).void }
|
120
|
-
def create_and_checkout_branch(name)
|
121
|
-
Spoom::Git.exec("git checkout -b #{name}", path: path)
|
122
|
-
end
|
123
|
-
|
124
|
-
sig { returns(T.nilable(String)) }
|
125
|
-
def current_branch
|
126
|
-
Spoom::Git.current_branch(path: path)
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
# Create an absolute path from `self.path` and `rel_path`
|
132
|
-
sig { params(rel_path: String).returns(String) }
|
133
|
-
def absolute_path(rel_path)
|
134
|
-
(Pathname.new(path) / rel_path).to_s
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|