spoom 1.1.16 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/spoom/cli/bump.rb +6 -15
- data/lib/spoom/cli/config.rb +4 -3
- data/lib/spoom/cli/coverage.rb +14 -15
- data/lib/spoom/cli/helper.rb +11 -21
- data/lib/spoom/cli/lsp.rb +4 -2
- data/lib/spoom/cli/run.rb +3 -7
- data/lib/spoom/cli.rb +6 -13
- data/lib/spoom/context/bundle.rb +58 -0
- data/lib/spoom/context/exec.rb +50 -0
- data/lib/spoom/context/file_system.rb +93 -0
- data/lib/spoom/context/git.rb +121 -0
- data/lib/spoom/context/sorbet.rb +154 -0
- data/lib/spoom/context.rb +16 -200
- data/lib/spoom/coverage/d3/circle_map.rb +22 -36
- data/lib/spoom/coverage/report.rb +45 -32
- data/lib/spoom/coverage.rb +27 -42
- data/lib/spoom/file_collector.rb +79 -0
- data/lib/spoom/file_tree.rb +168 -83
- data/lib/spoom/sorbet/config.rb +3 -1
- data/lib/spoom/sorbet/sigils.rb +0 -15
- data/lib/spoom/sorbet.rb +0 -119
- data/lib/spoom/timeline.rb +5 -8
- data/lib/spoom/version.rb +1 -1
- data/lib/spoom.rb +1 -52
- metadata +9 -4
- data/lib/spoom/git.rb +0 -109
@@ -0,0 +1,154 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Spoom
|
5
|
+
class Context
|
6
|
+
# Sorbet features for a context
|
7
|
+
module Sorbet
|
8
|
+
extend T::Sig
|
9
|
+
extend T::Helpers
|
10
|
+
|
11
|
+
requires_ancestor { Context }
|
12
|
+
|
13
|
+
# Run `bundle exec srb` in this context directory
|
14
|
+
sig { params(arg: String, sorbet_bin: T.nilable(String), capture_err: T::Boolean).returns(ExecResult) }
|
15
|
+
def srb(*arg, sorbet_bin: nil, capture_err: true)
|
16
|
+
res = if sorbet_bin
|
17
|
+
exec("#{sorbet_bin} #{arg.join(" ")}", capture_err: capture_err)
|
18
|
+
else
|
19
|
+
bundle_exec("srb #{arg.join(" ")}", capture_err: capture_err)
|
20
|
+
end
|
21
|
+
|
22
|
+
case res.exit_code
|
23
|
+
when Spoom::Sorbet::KILLED_CODE
|
24
|
+
raise Spoom::Sorbet::Error::Killed.new("Sorbet was killed.", res)
|
25
|
+
when Spoom::Sorbet::SEGFAULT_CODE
|
26
|
+
raise Spoom::Sorbet::Error::Segfault.new("Sorbet segfaulted.", res)
|
27
|
+
end
|
28
|
+
|
29
|
+
res
|
30
|
+
end
|
31
|
+
|
32
|
+
sig { params(arg: String, sorbet_bin: T.nilable(String), capture_err: T::Boolean).returns(ExecResult) }
|
33
|
+
def srb_tc(*arg, sorbet_bin: nil, capture_err: true)
|
34
|
+
arg.prepend("tc") unless sorbet_bin
|
35
|
+
T.unsafe(self).srb(*arg, sorbet_bin: sorbet_bin, capture_err: capture_err)
|
36
|
+
end
|
37
|
+
|
38
|
+
sig do
|
39
|
+
params(
|
40
|
+
arg: String,
|
41
|
+
sorbet_bin: T.nilable(String),
|
42
|
+
capture_err: T::Boolean,
|
43
|
+
).returns(T.nilable(T::Hash[String, Integer]))
|
44
|
+
end
|
45
|
+
def srb_metrics(*arg, sorbet_bin: nil, capture_err: true)
|
46
|
+
metrics_file = "metrics.tmp"
|
47
|
+
|
48
|
+
T.unsafe(self).srb_tc(
|
49
|
+
"--metrics-file",
|
50
|
+
metrics_file,
|
51
|
+
*arg,
|
52
|
+
sorbet_bin: sorbet_bin,
|
53
|
+
capture_err: capture_err,
|
54
|
+
)
|
55
|
+
return nil unless file?(metrics_file)
|
56
|
+
|
57
|
+
metrics_path = absolute_path_to(metrics_file)
|
58
|
+
metrics = Spoom::Sorbet::MetricsParser.parse_file(metrics_path)
|
59
|
+
remove!(metrics_file)
|
60
|
+
metrics
|
61
|
+
end
|
62
|
+
|
63
|
+
# List all files typechecked by Sorbet from its `config`
|
64
|
+
sig { params(with_config: T.nilable(Spoom::Sorbet::Config), include_rbis: T::Boolean).returns(T::Array[String]) }
|
65
|
+
def srb_files(with_config: nil, include_rbis: true)
|
66
|
+
config = with_config || sorbet_config
|
67
|
+
|
68
|
+
allowed_extensions = config.allowed_extensions
|
69
|
+
allowed_extensions = Spoom::Sorbet::Config::DEFAULT_ALLOWED_EXTENSIONS if allowed_extensions.empty?
|
70
|
+
allowed_extensions -= [".rbi"] unless include_rbis
|
71
|
+
|
72
|
+
excluded_patterns = config.ignore.map { |string| File.join("**", string, "**") }
|
73
|
+
|
74
|
+
collector = FileCollector.new(allow_extensions: allowed_extensions, exclude_patterns: excluded_patterns)
|
75
|
+
collector.visit_paths(config.paths.map { |path| absolute_path_to(path) })
|
76
|
+
collector.files.map { |file| file.delete_prefix("#{absolute_path}/") }.sort
|
77
|
+
end
|
78
|
+
|
79
|
+
# List all files typechecked by Sorbet from its `config` that matches `strictness`
|
80
|
+
sig do
|
81
|
+
params(
|
82
|
+
strictness: String,
|
83
|
+
with_config: T.nilable(Spoom::Sorbet::Config),
|
84
|
+
include_rbis: T::Boolean,
|
85
|
+
).returns(T::Array[String])
|
86
|
+
end
|
87
|
+
def srb_files_with_strictness(strictness, with_config: nil, include_rbis: true)
|
88
|
+
srb_files(with_config: with_config, include_rbis: include_rbis)
|
89
|
+
.select { |file| read_file_strictness(file) == strictness }
|
90
|
+
end
|
91
|
+
|
92
|
+
sig { params(arg: String, sorbet_bin: T.nilable(String), capture_err: T::Boolean).returns(T.nilable(String)) }
|
93
|
+
def srb_version(*arg, sorbet_bin: nil, capture_err: true)
|
94
|
+
res = T.unsafe(self).srb_tc("--no-config", "--version", *arg, sorbet_bin: sorbet_bin, capture_err: capture_err)
|
95
|
+
return nil unless res.status
|
96
|
+
|
97
|
+
res.out.split(" ")[2]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Does this context has a `sorbet/config` file?
|
101
|
+
sig { returns(T::Boolean) }
|
102
|
+
def has_sorbet_config?
|
103
|
+
file?(Spoom::Sorbet::CONFIG_PATH)
|
104
|
+
end
|
105
|
+
|
106
|
+
sig { returns(Spoom::Sorbet::Config) }
|
107
|
+
def sorbet_config
|
108
|
+
Spoom::Sorbet::Config.parse_string(read_sorbet_config)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Read the contents of `sorbet/config` in this context directory
|
112
|
+
sig { returns(String) }
|
113
|
+
def read_sorbet_config
|
114
|
+
read(Spoom::Sorbet::CONFIG_PATH)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Set the `contents` of `sorbet/config` in this context directory
|
118
|
+
sig { params(contents: String, append: T::Boolean).void }
|
119
|
+
def write_sorbet_config!(contents, append: false)
|
120
|
+
write!(Spoom::Sorbet::CONFIG_PATH, contents, append: append)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Read the strictness sigil from the file at `relative_path` (returns `nil` if no sigil)
|
124
|
+
sig { params(relative_path: String).returns(T.nilable(String)) }
|
125
|
+
def read_file_strictness(relative_path)
|
126
|
+
Spoom::Sorbet::Sigils.file_strictness(absolute_path_to(relative_path))
|
127
|
+
end
|
128
|
+
|
129
|
+
# Get the commit introducing the `sorbet/config` file
|
130
|
+
sig { returns(T.nilable(Spoom::Git::Commit)) }
|
131
|
+
def sorbet_intro_commit
|
132
|
+
res = git_log("--diff-filter=A --format='%h %at' -1 -- sorbet/config")
|
133
|
+
return nil unless res.status
|
134
|
+
|
135
|
+
out = res.out.strip
|
136
|
+
return nil if out.empty?
|
137
|
+
|
138
|
+
Spoom::Git::Commit.parse_line(out)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Get the commit removing the `sorbet/config` file
|
142
|
+
sig { returns(T.nilable(Spoom::Git::Commit)) }
|
143
|
+
def sorbet_removal_commit
|
144
|
+
res = git_log("--diff-filter=D --format='%h %at' -1 -- sorbet/config")
|
145
|
+
return nil unless res.status
|
146
|
+
|
147
|
+
out = res.out.strip
|
148
|
+
return nil if out.empty?
|
149
|
+
|
150
|
+
Spoom::Git::Commit.parse_line(out)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
data/lib/spoom/context.rb
CHANGED
@@ -3,8 +3,15 @@
|
|
3
3
|
|
4
4
|
require "fileutils"
|
5
5
|
require "open3"
|
6
|
+
require "time"
|
6
7
|
require "tmpdir"
|
7
8
|
|
9
|
+
require_relative "context/bundle"
|
10
|
+
require_relative "context/exec"
|
11
|
+
require_relative "context/file_system"
|
12
|
+
require_relative "context/git"
|
13
|
+
require_relative "context/sorbet"
|
14
|
+
|
8
15
|
module Spoom
|
9
16
|
# An abstraction to a Ruby project context
|
10
17
|
#
|
@@ -13,9 +20,11 @@ module Spoom
|
|
13
20
|
class Context
|
14
21
|
extend T::Sig
|
15
22
|
|
16
|
-
|
17
|
-
|
18
|
-
|
23
|
+
include Bundle
|
24
|
+
include Exec
|
25
|
+
include FileSystem
|
26
|
+
include Git
|
27
|
+
include Sorbet
|
19
28
|
|
20
29
|
class << self
|
21
30
|
extend T::Sig
|
@@ -30,6 +39,10 @@ module Spoom
|
|
30
39
|
end
|
31
40
|
end
|
32
41
|
|
42
|
+
# The absolute path to the directory this context is about
|
43
|
+
sig { returns(String) }
|
44
|
+
attr_reader :absolute_path
|
45
|
+
|
33
46
|
# Create a new context about `absolute_path`
|
34
47
|
#
|
35
48
|
# The directory will not be created if it doesn't exist.
|
@@ -38,202 +51,5 @@ module Spoom
|
|
38
51
|
def initialize(absolute_path)
|
39
52
|
@absolute_path = T.let(::File.expand_path(absolute_path), String)
|
40
53
|
end
|
41
|
-
|
42
|
-
# Returns the absolute path to `relative_path` in the context's directory
|
43
|
-
sig { params(relative_path: String).returns(String) }
|
44
|
-
def absolute_path_to(relative_path)
|
45
|
-
File.join(@absolute_path, relative_path)
|
46
|
-
end
|
47
|
-
|
48
|
-
# File System
|
49
|
-
|
50
|
-
# Does the context directory at `absolute_path` exist and is a directory?
|
51
|
-
sig { returns(T::Boolean) }
|
52
|
-
def exist?
|
53
|
-
File.directory?(@absolute_path)
|
54
|
-
end
|
55
|
-
|
56
|
-
# Create the context directory at `absolute_path`
|
57
|
-
sig { void }
|
58
|
-
def mkdir!
|
59
|
-
FileUtils.rm_rf(@absolute_path)
|
60
|
-
FileUtils.mkdir_p(@absolute_path)
|
61
|
-
end
|
62
|
-
|
63
|
-
# List all files in this context matching `pattern`
|
64
|
-
sig { params(pattern: String).returns(T::Array[String]) }
|
65
|
-
def glob(pattern = "**/*")
|
66
|
-
Dir.glob(absolute_path_to(pattern)).map do |path|
|
67
|
-
Pathname.new(path).relative_path_from(@absolute_path).to_s
|
68
|
-
end.sort
|
69
|
-
end
|
70
|
-
|
71
|
-
# List all files at the top level of this context directory
|
72
|
-
sig { returns(T::Array[String]) }
|
73
|
-
def list
|
74
|
-
glob("*")
|
75
|
-
end
|
76
|
-
|
77
|
-
# Does `relative_path` point to an existing file in this context directory?
|
78
|
-
sig { params(relative_path: String).returns(T::Boolean) }
|
79
|
-
def file?(relative_path)
|
80
|
-
File.file?(absolute_path_to(relative_path))
|
81
|
-
end
|
82
|
-
|
83
|
-
# Return the contents of the file at `relative_path` in this context directory
|
84
|
-
#
|
85
|
-
# Will raise if the file doesn't exist.
|
86
|
-
sig { params(relative_path: String).returns(String) }
|
87
|
-
def read(relative_path)
|
88
|
-
File.read(absolute_path_to(relative_path))
|
89
|
-
end
|
90
|
-
|
91
|
-
# Write `contents` in the file at `relative_path` in this context directory
|
92
|
-
#
|
93
|
-
# Append to the file if `append` is true.
|
94
|
-
sig { params(relative_path: String, contents: String, append: T::Boolean).void }
|
95
|
-
def write!(relative_path, contents = "", append: false)
|
96
|
-
absolute_path = absolute_path_to(relative_path)
|
97
|
-
FileUtils.mkdir_p(File.dirname(absolute_path))
|
98
|
-
File.write(absolute_path, contents, mode: append ? "a" : "w")
|
99
|
-
end
|
100
|
-
|
101
|
-
# Remove the path at `relative_path` (recursive + force) in this context directory
|
102
|
-
sig { params(relative_path: String).void }
|
103
|
-
def remove!(relative_path)
|
104
|
-
FileUtils.rm_rf(absolute_path_to(relative_path))
|
105
|
-
end
|
106
|
-
|
107
|
-
# Move the file or directory from `from_relative_path` to `to_relative_path`
|
108
|
-
sig { params(from_relative_path: String, to_relative_path: String).void }
|
109
|
-
def move!(from_relative_path, to_relative_path)
|
110
|
-
destination_path = absolute_path_to(to_relative_path)
|
111
|
-
FileUtils.mkdir_p(File.dirname(destination_path))
|
112
|
-
FileUtils.mv(absolute_path_to(from_relative_path), destination_path)
|
113
|
-
end
|
114
|
-
|
115
|
-
# Delete this context and its content
|
116
|
-
#
|
117
|
-
# Warning: it will `rm -rf` the context directory on the file system.
|
118
|
-
sig { void }
|
119
|
-
def destroy!
|
120
|
-
FileUtils.rm_rf(@absolute_path)
|
121
|
-
end
|
122
|
-
|
123
|
-
# Execution
|
124
|
-
|
125
|
-
# Run a command in this context directory
|
126
|
-
sig { params(command: String, capture_err: T::Boolean).returns(ExecResult) }
|
127
|
-
def exec(command, capture_err: true)
|
128
|
-
Bundler.with_unbundled_env do
|
129
|
-
opts = T.let({ chdir: @absolute_path }, T::Hash[Symbol, T.untyped])
|
130
|
-
|
131
|
-
if capture_err
|
132
|
-
out, err, status = Open3.capture3(command, opts)
|
133
|
-
ExecResult.new(out: out, err: err, status: T.must(status.success?), exit_code: T.must(status.exitstatus))
|
134
|
-
else
|
135
|
-
out, status = Open3.capture2(command, opts)
|
136
|
-
ExecResult.new(out: out, err: nil, status: T.must(status.success?), exit_code: T.must(status.exitstatus))
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
# Bundle
|
142
|
-
|
143
|
-
# Read the `contents` of the Gemfile in this context directory
|
144
|
-
sig { returns(T.nilable(String)) }
|
145
|
-
def read_gemfile
|
146
|
-
read("Gemfile")
|
147
|
-
end
|
148
|
-
|
149
|
-
# Set the `contents` of the Gemfile in this context directory
|
150
|
-
sig { params(contents: String, append: T::Boolean).void }
|
151
|
-
def write_gemfile!(contents, append: false)
|
152
|
-
write!("Gemfile", contents, append: append)
|
153
|
-
end
|
154
|
-
|
155
|
-
# Run a command with `bundle` in this context directory
|
156
|
-
sig { params(command: String, version: T.nilable(String)).returns(ExecResult) }
|
157
|
-
def bundle(command, version: nil)
|
158
|
-
command = "_#{version}_ #{command}" if version
|
159
|
-
exec("bundle #{command}")
|
160
|
-
end
|
161
|
-
|
162
|
-
# Run `bundle install` in this context directory
|
163
|
-
sig { params(version: T.nilable(String)).returns(ExecResult) }
|
164
|
-
def bundle_install!(version: nil)
|
165
|
-
bundle("install", version: version)
|
166
|
-
end
|
167
|
-
|
168
|
-
# Run a command `bundle exec` in this context directory
|
169
|
-
sig { params(command: String, version: T.nilable(String)).returns(ExecResult) }
|
170
|
-
def bundle_exec(command, version: nil)
|
171
|
-
bundle("exec #{command}", version: version)
|
172
|
-
end
|
173
|
-
|
174
|
-
# Git
|
175
|
-
|
176
|
-
# Run a command prefixed by `git` in this context directory
|
177
|
-
sig { params(command: String).returns(ExecResult) }
|
178
|
-
def git(command)
|
179
|
-
exec("git #{command}")
|
180
|
-
end
|
181
|
-
|
182
|
-
# Run `git init` in this context directory
|
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
|
193
|
-
end
|
194
|
-
|
195
|
-
# Run `git checkout` in this context directory
|
196
|
-
sig { params(ref: String).returns(ExecResult) }
|
197
|
-
def git_checkout!(ref: "main")
|
198
|
-
git("checkout #{ref}")
|
199
|
-
end
|
200
|
-
|
201
|
-
# Get the current git branch in this context directory
|
202
|
-
sig { returns(T.nilable(String)) }
|
203
|
-
def git_current_branch
|
204
|
-
Spoom::Git.current_branch(path: @absolute_path)
|
205
|
-
end
|
206
|
-
|
207
|
-
# Get the last commit in the currently checked out branch
|
208
|
-
sig { params(short_sha: T::Boolean).returns(T.nilable(Git::Commit)) }
|
209
|
-
def git_last_commit(short_sha: true)
|
210
|
-
Spoom::Git.last_commit(path: @absolute_path, short_sha: short_sha)
|
211
|
-
end
|
212
|
-
|
213
|
-
# Sorbet
|
214
|
-
|
215
|
-
# Run `bundle exec srb` in this context directory
|
216
|
-
sig { params(command: String).returns(ExecResult) }
|
217
|
-
def srb(command)
|
218
|
-
bundle_exec("srb #{command}")
|
219
|
-
end
|
220
|
-
|
221
|
-
# Read the contents of `sorbet/config` in this context directory
|
222
|
-
sig { returns(String) }
|
223
|
-
def read_sorbet_config
|
224
|
-
read(Spoom::Sorbet::CONFIG_PATH)
|
225
|
-
end
|
226
|
-
|
227
|
-
# Set the `contents` of `sorbet/config` in this context directory
|
228
|
-
sig { params(contents: String, append: T::Boolean).void }
|
229
|
-
def write_sorbet_config!(contents, append: false)
|
230
|
-
write!(Spoom::Sorbet::CONFIG_PATH, contents, append: append)
|
231
|
-
end
|
232
|
-
|
233
|
-
# Read the strictness sigil from the file at `relative_path` (returns `nil` if no sigil)
|
234
|
-
sig { params(relative_path: String).returns(T.nilable(String)) }
|
235
|
-
def read_file_strictness(relative_path)
|
236
|
-
Spoom::Sorbet::Sigils.file_strictness(absolute_path_to(relative_path))
|
237
|
-
end
|
238
54
|
end
|
239
55
|
end
|
@@ -148,48 +148,34 @@ module Spoom
|
|
148
148
|
class Sigils < CircleMap
|
149
149
|
extend T::Sig
|
150
150
|
|
151
|
-
sig
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
151
|
+
sig do
|
152
|
+
params(
|
153
|
+
id: String,
|
154
|
+
file_tree: FileTree,
|
155
|
+
nodes_strictnesses: T::Hash[FileTree::Node, T.nilable(String)],
|
156
|
+
nodes_scores: T::Hash[FileTree::Node, Float],
|
157
|
+
).void
|
158
|
+
end
|
159
|
+
def initialize(id, file_tree, nodes_strictnesses, nodes_scores)
|
160
|
+
@nodes_strictnesses = nodes_strictnesses
|
161
|
+
@nodes_scores = nodes_scores
|
162
|
+
super(id, file_tree.roots.map { |r| tree_node_to_json(r) })
|
157
163
|
end
|
158
164
|
|
159
165
|
sig { params(node: FileTree::Node).returns(T::Hash[Symbol, T.untyped]) }
|
160
166
|
def tree_node_to_json(node)
|
161
167
|
if node.children.empty?
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
sig { params(node: FileTree::Node).returns(T.nilable(String)) }
|
173
|
-
def tree_node_strictness(node)
|
174
|
-
prefix = @sigils_tree.strip_prefix
|
175
|
-
path = node.path
|
176
|
-
path = "#{prefix}/#{path}" if prefix
|
177
|
-
@strictnesses[node] ||= Spoom::Sorbet::Sigils.file_strictness(path)
|
178
|
-
end
|
179
|
-
|
180
|
-
sig { params(node: FileTree::Node).returns(Float) }
|
181
|
-
def tree_node_score(node)
|
182
|
-
unless @scores.key?(node)
|
183
|
-
if node.name =~ /\.rbi?$/
|
184
|
-
case tree_node_strictness(node)
|
185
|
-
when "true", "strict", "strong"
|
186
|
-
@scores[node] = 1.0
|
187
|
-
end
|
188
|
-
elsif !node.children.empty?
|
189
|
-
@scores[node] = node.children.values.sum { |n| tree_node_score(n) } / node.children.size.to_f
|
190
|
-
end
|
168
|
+
{
|
169
|
+
name: node.name,
|
170
|
+
strictness: @nodes_strictnesses.fetch(node, "false"),
|
171
|
+
}
|
172
|
+
else
|
173
|
+
{
|
174
|
+
name: node.name,
|
175
|
+
children: node.children.values.map { |n| tree_node_to_json(n) },
|
176
|
+
score: @nodes_scores.fetch(node, 0.0),
|
177
|
+
}
|
191
178
|
end
|
192
|
-
@scores[node] || 0.0
|
193
179
|
end
|
194
180
|
end
|
195
181
|
end
|
@@ -153,9 +153,24 @@ module Spoom
|
|
153
153
|
class Map < Card
|
154
154
|
extend T::Sig
|
155
155
|
|
156
|
-
sig
|
157
|
-
|
158
|
-
|
156
|
+
sig do
|
157
|
+
params(
|
158
|
+
file_tree: FileTree,
|
159
|
+
nodes_strictnesses: T::Hash[FileTree::Node, T.nilable(String)],
|
160
|
+
nodes_strictness_scores: T::Hash[FileTree::Node, Float],
|
161
|
+
title: String,
|
162
|
+
).void
|
163
|
+
end
|
164
|
+
def initialize(file_tree:, nodes_strictnesses:, nodes_strictness_scores:, title: "Strictness Map")
|
165
|
+
super(
|
166
|
+
title: title,
|
167
|
+
body: D3::CircleMap::Sigils.new(
|
168
|
+
"map_sigils",
|
169
|
+
file_tree,
|
170
|
+
nodes_strictnesses,
|
171
|
+
nodes_strictness_scores,
|
172
|
+
).html
|
173
|
+
)
|
159
174
|
end
|
160
175
|
end
|
161
176
|
|
@@ -246,27 +261,14 @@ module Spoom
|
|
246
261
|
class Report < Page
|
247
262
|
extend T::Sig
|
248
263
|
|
249
|
-
sig { returns(String) }
|
250
|
-
attr_reader :project_name
|
251
|
-
|
252
|
-
sig { returns(T.nilable(String)) }
|
253
|
-
attr_reader :sorbet_intro_commit
|
254
|
-
|
255
|
-
sig { returns(T.nilable(Time)) }
|
256
|
-
attr_reader :sorbet_intro_date
|
257
|
-
|
258
|
-
sig { returns(T::Array[Snapshot]) }
|
259
|
-
attr_reader :snapshots
|
260
|
-
|
261
|
-
sig { returns(FileTree) }
|
262
|
-
attr_reader :sigils_tree
|
263
|
-
|
264
264
|
sig do
|
265
265
|
params(
|
266
266
|
project_name: String,
|
267
267
|
palette: D3::ColorPalette,
|
268
268
|
snapshots: T::Array[Snapshot],
|
269
|
-
|
269
|
+
file_tree: FileTree,
|
270
|
+
nodes_strictnesses: T::Hash[FileTree::Node, T.nilable(String)],
|
271
|
+
nodes_strictness_scores: T::Hash[FileTree::Node, Float],
|
270
272
|
sorbet_intro_commit: T.nilable(String),
|
271
273
|
sorbet_intro_date: T.nilable(Time),
|
272
274
|
).void
|
@@ -275,24 +277,28 @@ module Spoom
|
|
275
277
|
project_name:,
|
276
278
|
palette:,
|
277
279
|
snapshots:,
|
278
|
-
|
280
|
+
file_tree:,
|
281
|
+
nodes_strictnesses:,
|
282
|
+
nodes_strictness_scores:,
|
279
283
|
sorbet_intro_commit: nil,
|
280
284
|
sorbet_intro_date: nil
|
281
285
|
)
|
282
286
|
super(title: project_name, palette: palette)
|
283
287
|
@project_name = project_name
|
284
288
|
@snapshots = snapshots
|
285
|
-
@
|
289
|
+
@file_tree = file_tree
|
290
|
+
@nodes_strictnesses = nodes_strictnesses
|
291
|
+
@nodes_strictness_scores = nodes_strictness_scores
|
286
292
|
@sorbet_intro_commit = sorbet_intro_commit
|
287
293
|
@sorbet_intro_date = sorbet_intro_date
|
288
294
|
end
|
289
295
|
|
290
296
|
sig { override.returns(String) }
|
291
297
|
def header_html
|
292
|
-
last = T.must(snapshots.last)
|
298
|
+
last = T.must(@snapshots.last)
|
293
299
|
<<~ERB
|
294
300
|
<h1 class="display-3">
|
295
|
-
#{project_name}
|
301
|
+
#{@project_name}
|
296
302
|
<span class="badge badge-pill badge-dark" style="font-size: 20%;">#{last.commit_sha}</span>
|
297
303
|
</h1>
|
298
304
|
ERB
|
@@ -300,17 +306,24 @@ module Spoom
|
|
300
306
|
|
301
307
|
sig { override.returns(T::Array[Cards::Card]) }
|
302
308
|
def cards
|
303
|
-
last = T.must(snapshots.last)
|
309
|
+
last = T.must(@snapshots.last)
|
304
310
|
cards = []
|
305
311
|
cards << Cards::Snapshot.new(snapshot: last)
|
306
|
-
cards << Cards::Map.new(
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
cards << Cards::Timeline::
|
312
|
-
cards << Cards::Timeline::
|
313
|
-
cards << Cards::
|
312
|
+
cards << Cards::Map.new(
|
313
|
+
file_tree: @file_tree,
|
314
|
+
nodes_strictnesses: @nodes_strictnesses,
|
315
|
+
nodes_strictness_scores: @nodes_strictness_scores,
|
316
|
+
)
|
317
|
+
cards << Cards::Timeline::Sigils.new(snapshots: @snapshots)
|
318
|
+
cards << Cards::Timeline::Calls.new(snapshots: @snapshots)
|
319
|
+
cards << Cards::Timeline::Sigs.new(snapshots: @snapshots)
|
320
|
+
cards << Cards::Timeline::RBIs.new(snapshots: @snapshots)
|
321
|
+
cards << Cards::Timeline::Versions.new(snapshots: @snapshots)
|
322
|
+
cards << Cards::Timeline::Runtimes.new(snapshots: @snapshots)
|
323
|
+
cards << Cards::SorbetIntro.new(
|
324
|
+
sorbet_intro_commit: @sorbet_intro_commit,
|
325
|
+
sorbet_intro_date: @sorbet_intro_date,
|
326
|
+
)
|
314
327
|
cards
|
315
328
|
end
|
316
329
|
end
|