spoom 1.1.12 → 1.1.13
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/lib/spoom/cli/bump.rb +7 -6
- data/lib/spoom/cli/coverage.rb +10 -11
- data/lib/spoom/cli/helper.rb +2 -2
- data/lib/spoom/cli/lsp.rb +2 -2
- data/lib/spoom/cli/run.rb +2 -2
- data/lib/spoom/coverage/d3/pie.rb +11 -4
- data/lib/spoom/coverage/d3/timeline.rb +11 -8
- data/lib/spoom/coverage/snapshot.rb +25 -1
- data/lib/spoom/coverage.rb +32 -12
- data/lib/spoom/file_tree.rb +3 -3
- data/lib/spoom/git.rb +38 -42
- data/lib/spoom/sorbet/errors.rb +1 -1
- data/lib/spoom/sorbet/lsp/errors.rb +2 -2
- data/lib/spoom/sorbet/lsp/structures.rb +6 -6
- data/lib/spoom/sorbet/lsp.rb +7 -7
- data/lib/spoom/sorbet/sigils.rb +1 -1
- data/lib/spoom/sorbet.rb +6 -6
- data/lib/spoom/timeline.rb +5 -5
- data/lib/spoom/version.rb +1 -1
- data/lib/spoom.rb +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5cad6017cf76302bc359d170fce6c2e33c4ff5923a564b26e2f270b42c102e3d
|
4
|
+
data.tar.gz: 734654483394f8520346d0ddab7872e1c7f42de4eed7523e503264f8045bf2c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a67da9fa2811e15d5bfc5f554a2b1cb23bed4a0744617d1168b3d3d4c08f4f6828b207142996fb8cebc57ca8732d901e3e390c43939eaa504a2ed1cc1fe611b4
|
7
|
+
data.tar.gz: 1b98af8f37acd554f908fdde1257f9c53eaab0a37b21847e619caee5cdda44e9f06e248545ec247cb43c6ac434d5e00bce4b6731eb434c62bd3a60a72c67313f
|
data/lib/spoom/cli/bump.rb
CHANGED
@@ -71,7 +71,7 @@ module Spoom
|
|
71
71
|
say("\n")
|
72
72
|
|
73
73
|
if files_to_bump.empty?
|
74
|
-
say("No
|
74
|
+
say("No files to bump from `#{from}` to `#{to}`")
|
75
75
|
exit(0)
|
76
76
|
end
|
77
77
|
|
@@ -88,7 +88,7 @@ module Spoom
|
|
88
88
|
"--error-url-base=#{error_url_base}",
|
89
89
|
path: exec_path,
|
90
90
|
capture_err: true,
|
91
|
-
sorbet_bin: options[:sorbet]
|
91
|
+
sorbet_bin: options[:sorbet],
|
92
92
|
)
|
93
93
|
|
94
94
|
check_sorbet_segfault(result.exit_code) do
|
@@ -132,13 +132,14 @@ module Spoom
|
|
132
132
|
|
133
133
|
no_commands do
|
134
134
|
def print_changes(files, command:, from: "false", to: "true", dry: false, path: File.expand_path("."))
|
135
|
-
|
136
|
-
|
135
|
+
files_count = files.size
|
136
|
+
if files_count.zero?
|
137
|
+
say("No files to bump from `#{from}` to `#{to}`")
|
137
138
|
return
|
138
139
|
end
|
139
140
|
message = StringIO.new
|
140
141
|
message << (dry ? "Can bump" : "Bumped")
|
141
|
-
message << " `#{
|
142
|
+
message << " `#{files_count}` file#{"s" if files_count > 1}"
|
142
143
|
message << " from `#{from}` to `#{to}`:"
|
143
144
|
say(message.string)
|
144
145
|
files.each do |file|
|
@@ -146,7 +147,7 @@ module Spoom
|
|
146
147
|
say(" + #{file_path}")
|
147
148
|
end
|
148
149
|
if dry && command
|
149
|
-
say("\nRun `#{command}` to bump them")
|
150
|
+
say("\nRun `#{command}` to bump #{files_count > 1 ? "them" : "it"}")
|
150
151
|
elsif dry
|
151
152
|
say("\nRun `spoom bump --from #{from} --to #{to}` locally then `commit the changes` and `push them`")
|
152
153
|
end
|
data/lib/spoom/cli/coverage.rb
CHANGED
@@ -46,7 +46,7 @@ module Spoom
|
|
46
46
|
sorbet = options[:sorbet]
|
47
47
|
|
48
48
|
ref_before = Spoom::Git.current_branch
|
49
|
-
ref_before = Spoom::Git.last_commit(path: path) unless ref_before
|
49
|
+
ref_before = Spoom::Git.last_commit(path: path)&.sha unless ref_before
|
50
50
|
unless ref_before
|
51
51
|
say_error("Not in a git repository")
|
52
52
|
say_error("\nSpoom needs to checkout into your previous commits to build the timeline.", status: nil)
|
@@ -71,9 +71,9 @@ module Spoom
|
|
71
71
|
to = parse_time(options[:to], "--to")
|
72
72
|
|
73
73
|
unless from
|
74
|
-
|
75
|
-
|
76
|
-
from =
|
74
|
+
intro_commit = Spoom::Git.sorbet_intro_commit(path: path)
|
75
|
+
intro_commit = T.must(intro_commit) # we know it's in there since in_sorbet_project!
|
76
|
+
from = intro_commit.time
|
77
77
|
end
|
78
78
|
|
79
79
|
timeline = Spoom::Timeline.new(from, to, path: path)
|
@@ -84,16 +84,15 @@ module Spoom
|
|
84
84
|
exit(1)
|
85
85
|
end
|
86
86
|
|
87
|
-
ticks.each_with_index do |
|
88
|
-
|
89
|
-
say("Analyzing commit `#{sha}` - #{date&.strftime("%F")} (#{i + 1} / #{ticks.size})")
|
87
|
+
ticks.each_with_index do |commit, i|
|
88
|
+
say("Analyzing commit `#{commit.sha}` - #{commit.time.strftime("%F")} (#{i + 1} / #{ticks.size})")
|
90
89
|
|
91
|
-
Spoom::Git.checkout(sha, path: path)
|
90
|
+
Spoom::Git.checkout(commit.sha, path: path)
|
92
91
|
|
93
92
|
snapshot = T.let(nil, T.nilable(Spoom::Coverage::Snapshot))
|
94
93
|
if options[:bundle_install]
|
95
94
|
Bundler.with_unbundled_env do
|
96
|
-
next unless bundle_install(path, sha)
|
95
|
+
next unless bundle_install(path, commit.sha)
|
97
96
|
|
98
97
|
snapshot = Spoom::Coverage.snapshot(path: path, sorbet_bin: sorbet)
|
99
98
|
end
|
@@ -107,7 +106,7 @@ module Spoom
|
|
107
106
|
|
108
107
|
next unless save_dir
|
109
108
|
|
110
|
-
file = "#{save_dir}/#{sha}.json"
|
109
|
+
file = "#{save_dir}/#{commit.sha}.json"
|
111
110
|
File.write(file, snapshot.to_json)
|
112
111
|
say(" Snapshot data saved under `#{file}`\n\n")
|
113
112
|
end
|
@@ -148,7 +147,7 @@ module Spoom
|
|
148
147
|
false: options[:color_false],
|
149
148
|
true: options[:color_true],
|
150
149
|
strict: options[:color_strict],
|
151
|
-
strong: options[:color_strong]
|
150
|
+
strong: options[:color_strong],
|
152
151
|
)
|
153
152
|
|
154
153
|
report = Spoom::Coverage.report(snapshots, palette: palette, path: exec_path)
|
data/lib/spoom/cli/helper.rb
CHANGED
@@ -33,7 +33,7 @@ module Spoom
|
|
33
33
|
params(
|
34
34
|
message: String,
|
35
35
|
status: T.nilable(String),
|
36
|
-
nl: T::Boolean
|
36
|
+
nl: T::Boolean,
|
37
37
|
).void
|
38
38
|
end
|
39
39
|
def say_error(message, status: "Error", nl: true)
|
@@ -61,7 +61,7 @@ module Spoom
|
|
61
61
|
say_error(
|
62
62
|
"not in a Sorbet project (`#{sorbet_config_file}` not found)\n\n" \
|
63
63
|
"When running spoom from another path than the project's root, " \
|
64
|
-
"use `--path PATH` to specify the path to the root."
|
64
|
+
"use `--path PATH` to specify the path to the root.",
|
65
65
|
)
|
66
66
|
Kernel.exit(1)
|
67
67
|
end
|
data/lib/spoom/cli/lsp.rb
CHANGED
@@ -118,7 +118,7 @@ module Spoom
|
|
118
118
|
"--lsp",
|
119
119
|
"--enable-all-experimental-lsp-features",
|
120
120
|
"--disable-watchman",
|
121
|
-
path: path
|
121
|
+
path: path,
|
122
122
|
)
|
123
123
|
client.open(File.expand_path(path))
|
124
124
|
client
|
@@ -128,7 +128,7 @@ module Spoom
|
|
128
128
|
Spoom::LSP::SymbolPrinter.new(
|
129
129
|
indent_level: 2,
|
130
130
|
colors: options[:color],
|
131
|
-
prefix: "file://#{File.expand_path(exec_path)}"
|
131
|
+
prefix: "file://#{File.expand_path(exec_path)}",
|
132
132
|
)
|
133
133
|
end
|
134
134
|
|
data/lib/spoom/cli/run.rb
CHANGED
@@ -40,7 +40,7 @@ module Spoom
|
|
40
40
|
*options[:sorbet_options].split(" "),
|
41
41
|
path: path,
|
42
42
|
capture_err: false,
|
43
|
-
sorbet_bin: sorbet
|
43
|
+
sorbet_bin: sorbet,
|
44
44
|
)
|
45
45
|
|
46
46
|
check_sorbet_segfault(result.code)
|
@@ -54,7 +54,7 @@ module Spoom
|
|
54
54
|
"--error-url-base=#{error_url_base}",
|
55
55
|
path: path,
|
56
56
|
capture_err: true,
|
57
|
-
sorbet_bin: sorbet
|
57
|
+
sorbet_bin: sorbet,
|
58
58
|
)
|
59
59
|
|
60
60
|
check_sorbet_segfault(result.exit_code)
|
@@ -125,14 +125,14 @@ module Spoom
|
|
125
125
|
|
126
126
|
sig { params(id: String, title: String, snapshot: Snapshot).void }
|
127
127
|
def initialize(id, title, snapshot)
|
128
|
-
super(id, title, snapshot.
|
128
|
+
super(id, title, snapshot.sigils_excluding_rbis.select { |_k, v| v })
|
129
129
|
end
|
130
130
|
|
131
131
|
sig { override.returns(String) }
|
132
132
|
def tooltip
|
133
133
|
<<~JS
|
134
134
|
function tooltip_#{id}(d) {
|
135
|
-
tooltipPie(d, "typed: " + d.data.key, "files", sum_#{id});
|
135
|
+
tooltipPie(d, "typed: " + d.data.key, "files excluding RBIs", sum_#{id});
|
136
136
|
}
|
137
137
|
JS
|
138
138
|
end
|
@@ -161,14 +161,21 @@ module Spoom
|
|
161
161
|
|
162
162
|
sig { params(id: String, title: String, snapshot: Snapshot).void }
|
163
163
|
def initialize(id, title, snapshot)
|
164
|
-
super(
|
164
|
+
super(
|
165
|
+
id,
|
166
|
+
title,
|
167
|
+
{ true: snapshot.methods_with_sig_excluding_rbis, false: snapshot.methods_without_sig_excluding_rbis }
|
168
|
+
)
|
165
169
|
end
|
166
170
|
|
167
171
|
sig { override.returns(String) }
|
168
172
|
def tooltip
|
169
173
|
<<~JS
|
170
174
|
function tooltip_#{id}(d) {
|
171
|
-
tooltipPie(
|
175
|
+
tooltipPie(
|
176
|
+
d,
|
177
|
+
(d.data.key == "true" ? " with" : " without") + " a signature", "methods excluding RBIs", sum_#{id}
|
178
|
+
)
|
172
179
|
}
|
173
180
|
JS
|
174
181
|
end
|
@@ -268,7 +268,7 @@ module Spoom
|
|
268
268
|
d3.min(data_#{id}, (d) => parseVersion(d.runtime))]) - 0.01",
|
269
269
|
max: "d3.max([d3.max(data_#{id}, (d) => parseVersion(d.static)),
|
270
270
|
d3.max(data_#{id}, (d) => parseVersion(d.runtime))]) + 0.01",
|
271
|
-
ticks: "ticks(8)"
|
271
|
+
ticks: "ticks(8)",
|
272
272
|
)}
|
273
273
|
#{line(y: "parseVersion(d.runtime)", color: "#e83e8c", curve: "curveStepAfter")}
|
274
274
|
#{line(y: "parseVersion(d.static)", color: "#007bff", curve: "curveStepAfter")}
|
@@ -314,7 +314,7 @@ module Spoom
|
|
314
314
|
#{y_scale(
|
315
315
|
min: "0",
|
316
316
|
max: "d3.max(data_#{id}, (d) => d.runtime)",
|
317
|
-
ticks: "ticks(10)"
|
317
|
+
ticks: "ticks(10)",
|
318
318
|
)}
|
319
319
|
#{area(y: "d.runtime")}
|
320
320
|
#{line(y: "d.runtime")}
|
@@ -428,8 +428,8 @@ module Spoom
|
|
428
428
|
{
|
429
429
|
timestamp: snapshot.commit_timestamp,
|
430
430
|
commit: snapshot.commit_sha,
|
431
|
-
total: snapshot.files,
|
432
|
-
values: snapshot.
|
431
|
+
total: snapshot.files - snapshot.rbi_files,
|
432
|
+
values: snapshot.sigils_excluding_rbis,
|
433
433
|
}
|
434
434
|
end
|
435
435
|
super(id, data, keys)
|
@@ -439,7 +439,7 @@ module Spoom
|
|
439
439
|
def tooltip
|
440
440
|
<<~JS
|
441
441
|
function tooltip_#{id}(d) {
|
442
|
-
tooltipTimeline(d, "files");
|
442
|
+
tooltipTimeline(d, "files excluding RBIs");
|
443
443
|
}
|
444
444
|
JS
|
445
445
|
end
|
@@ -482,8 +482,11 @@ module Spoom
|
|
482
482
|
{
|
483
483
|
timestamp: snapshot.commit_timestamp,
|
484
484
|
commit: snapshot.commit_sha,
|
485
|
-
total: snapshot.
|
486
|
-
values: {
|
485
|
+
total: snapshot.methods_with_sig_excluding_rbis + snapshot.methods_without_sig_excluding_rbis,
|
486
|
+
values: {
|
487
|
+
true: snapshot.methods_with_sig_excluding_rbis,
|
488
|
+
false: snapshot.methods_without_sig_excluding_rbis,
|
489
|
+
},
|
487
490
|
}
|
488
491
|
end
|
489
492
|
super(id, data, keys)
|
@@ -493,7 +496,7 @@ module Spoom
|
|
493
496
|
def tooltip
|
494
497
|
<<~JS
|
495
498
|
function tooltip_#{id}(d) {
|
496
|
-
tooltipTimeline(d, "methods");
|
499
|
+
tooltipTimeline(d, "methods excluding RBIs");
|
497
500
|
}
|
498
501
|
JS
|
499
502
|
end
|
@@ -22,6 +22,9 @@ module Spoom
|
|
22
22
|
prop :calls_untyped, Integer, default: 0
|
23
23
|
prop :calls_typed, Integer, default: 0
|
24
24
|
prop :sigils, T::Hash[String, Integer], default: Hash.new(0)
|
25
|
+
prop :methods_with_sig_excluding_rbis, Integer, default: 0
|
26
|
+
prop :methods_without_sig_excluding_rbis, Integer, default: 0
|
27
|
+
prop :sigils_excluding_rbis, T::Hash[String, Integer], default: Hash.new(0)
|
25
28
|
|
26
29
|
# The strictness name as found in the Sorbet metrics file
|
27
30
|
STRICTNESSES = T.let(["ignore", "false", "true", "strict", "strong", "stdlib"].freeze, T::Array[String])
|
@@ -63,6 +66,8 @@ module Spoom
|
|
63
66
|
snapshot.methods_without_sig = obj.fetch("methods_without_sig", 0)
|
64
67
|
snapshot.calls_typed = obj.fetch("calls_typed", 0)
|
65
68
|
snapshot.calls_untyped = obj.fetch("calls_untyped", 0)
|
69
|
+
snapshot.methods_with_sig_excluding_rbis = obj.fetch("methods_with_sig_excluding_rbis", 0)
|
70
|
+
snapshot.methods_without_sig_excluding_rbis = obj.fetch("methods_without_sig_excluding_rbis", 0)
|
66
71
|
|
67
72
|
sigils = obj.fetch("sigils", {})
|
68
73
|
if sigils
|
@@ -73,6 +78,15 @@ module Spoom
|
|
73
78
|
end
|
74
79
|
end
|
75
80
|
|
81
|
+
sigils_excluding_rbis = obj.fetch("sigils_excluding_rbis", {})
|
82
|
+
if sigils_excluding_rbis
|
83
|
+
Snapshot::STRICTNESSES.each do |strictness|
|
84
|
+
next unless sigils_excluding_rbis.key?(strictness)
|
85
|
+
|
86
|
+
snapshot.sigils_excluding_rbis[strictness] = sigils_excluding_rbis[strictness]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
76
90
|
snapshot
|
77
91
|
end
|
78
92
|
end
|
@@ -84,6 +98,7 @@ module Spoom
|
|
84
98
|
sig { params(snapshot: Snapshot).void }
|
85
99
|
def print_snapshot(snapshot)
|
86
100
|
methods = snapshot.methods_with_sig + snapshot.methods_without_sig
|
101
|
+
methods_excluding_rbis = snapshot.methods_with_sig_excluding_rbis + snapshot.methods_without_sig_excluding_rbis
|
87
102
|
calls = snapshot.calls_typed + snapshot.calls_untyped
|
88
103
|
|
89
104
|
if snapshot.version_static || snapshot.version_runtime
|
@@ -93,10 +108,12 @@ module Spoom
|
|
93
108
|
end
|
94
109
|
printl("Content:")
|
95
110
|
indent
|
96
|
-
printl("files: #{snapshot.files}
|
111
|
+
printl("files: #{snapshot.files}")
|
112
|
+
printl("files excluding rbis: #{snapshot.files - snapshot.rbi_files}")
|
97
113
|
printl("modules: #{snapshot.modules}")
|
98
114
|
printl("classes: #{snapshot.classes - snapshot.singleton_classes}")
|
99
115
|
printl("methods: #{methods}")
|
116
|
+
printl("methods excluding rbis: #{methods_excluding_rbis}")
|
100
117
|
dedent
|
101
118
|
printn
|
102
119
|
printl("Sigils:")
|
@@ -109,6 +126,13 @@ module Spoom
|
|
109
126
|
}
|
110
127
|
print_map(methods_map, methods)
|
111
128
|
printn
|
129
|
+
printl("Methods excluding RBIs")
|
130
|
+
methods_excluding_rbis_map = {
|
131
|
+
"with signature" => snapshot.methods_with_sig_excluding_rbis,
|
132
|
+
"without signature" => snapshot.methods_without_sig_excluding_rbis,
|
133
|
+
}
|
134
|
+
print_map(methods_excluding_rbis_map, methods_excluding_rbis)
|
135
|
+
printn
|
112
136
|
printl("Calls:")
|
113
137
|
calls_map = {
|
114
138
|
"typed" => snapshot.calls_typed,
|
data/lib/spoom/coverage.rb
CHANGED
@@ -19,24 +19,35 @@ module Spoom
|
|
19
19
|
|
20
20
|
new_config = config.copy
|
21
21
|
new_config.allowed_extensions.reject! { |ext| !rbi && ext == ".rbi" }
|
22
|
-
|
23
|
-
metrics = Spoom::Sorbet.srb_metrics(
|
22
|
+
flags = [
|
24
23
|
"--no-config",
|
25
24
|
"--no-error-sections",
|
26
25
|
"--no-error-count",
|
27
26
|
"--isolate-error-code=0",
|
28
27
|
new_config.options_string,
|
28
|
+
]
|
29
|
+
|
30
|
+
metrics = Spoom::Sorbet.srb_metrics(
|
31
|
+
*flags,
|
32
|
+
path: path,
|
33
|
+
capture_err: true,
|
34
|
+
sorbet_bin: sorbet_bin,
|
35
|
+
)
|
36
|
+
# Collect extra information using a different configuration
|
37
|
+
flags << "--ignore sorbet/rbi/"
|
38
|
+
metrics_without_rbis = Spoom::Sorbet.srb_metrics(
|
39
|
+
*flags,
|
29
40
|
path: path,
|
30
41
|
capture_err: true,
|
31
|
-
sorbet_bin: sorbet_bin
|
42
|
+
sorbet_bin: sorbet_bin,
|
32
43
|
)
|
33
44
|
|
34
45
|
snapshot = Snapshot.new
|
35
46
|
return snapshot unless metrics
|
36
47
|
|
37
|
-
|
38
|
-
snapshot.commit_sha = sha
|
39
|
-
snapshot.commit_timestamp =
|
48
|
+
last_commit = Spoom::Git.last_commit(path: path)
|
49
|
+
snapshot.commit_sha = last_commit&.sha
|
50
|
+
snapshot.commit_timestamp = last_commit&.timestamp
|
40
51
|
|
41
52
|
snapshot.files = metrics.fetch("types.input.files", 0)
|
42
53
|
snapshot.modules = metrics.fetch("types.input.modules.total", 0)
|
@@ -50,10 +61,20 @@ module Spoom
|
|
50
61
|
snapshot.duration += metrics.fetch("run.utilization.system_time.us", 0)
|
51
62
|
snapshot.duration += metrics.fetch("run.utilization.user_time.us", 0)
|
52
63
|
|
53
|
-
|
54
|
-
|
64
|
+
if metrics_without_rbis
|
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
|
68
|
+
end
|
55
69
|
|
56
|
-
|
70
|
+
Snapshot::STRICTNESSES.each do |strictness|
|
71
|
+
if metrics.key?("types.input.files.sigil.#{strictness}")
|
72
|
+
snapshot.sigils[strictness] = T.must(metrics["types.input.files.sigil.#{strictness}"])
|
73
|
+
end
|
74
|
+
if metrics_without_rbis&.key?("types.input.files.sigil.#{strictness}")
|
75
|
+
snapshot.sigils_excluding_rbis[strictness] =
|
76
|
+
T.must(metrics_without_rbis["types.input.files.sigil.#{strictness}"])
|
77
|
+
end
|
57
78
|
end
|
58
79
|
|
59
80
|
snapshot.version_static = Spoom::Sorbet.version_from_gemfile_lock(gem: "sorbet-static", path: path)
|
@@ -68,15 +89,14 @@ module Spoom
|
|
68
89
|
sig { params(snapshots: T::Array[Snapshot], palette: D3::ColorPalette, path: String).returns(Report) }
|
69
90
|
def report(snapshots, palette:, path: ".")
|
70
91
|
intro_commit = Git.sorbet_intro_commit(path: path)
|
71
|
-
intro_date = intro_commit ? Git.commit_time(intro_commit, path: path) : nil
|
72
92
|
|
73
93
|
Report.new(
|
74
94
|
project_name: File.basename(File.expand_path(path)),
|
75
95
|
palette: palette,
|
76
96
|
snapshots: snapshots,
|
77
97
|
sigils_tree: sigils_tree(path: path),
|
78
|
-
sorbet_intro_commit: intro_commit,
|
79
|
-
sorbet_intro_date:
|
98
|
+
sorbet_intro_commit: intro_commit&.sha,
|
99
|
+
sorbet_intro_date: intro_commit&.time,
|
80
100
|
)
|
81
101
|
end
|
82
102
|
|
data/lib/spoom/file_tree.rb
CHANGED
@@ -65,7 +65,7 @@ module Spoom
|
|
65
65
|
out: T.any(IO, StringIO),
|
66
66
|
show_strictness: T::Boolean,
|
67
67
|
colors: T::Boolean,
|
68
|
-
indent_level: Integer
|
68
|
+
indent_level: Integer,
|
69
69
|
).void
|
70
70
|
end
|
71
71
|
def print(out: $stdout, show_strictness: true, colors: true, indent_level: 0)
|
@@ -74,7 +74,7 @@ module Spoom
|
|
74
74
|
out: out,
|
75
75
|
show_strictness: show_strictness,
|
76
76
|
colors: colors,
|
77
|
-
indent_level: indent_level
|
77
|
+
indent_level: indent_level,
|
78
78
|
)
|
79
79
|
printer.print_tree
|
80
80
|
end
|
@@ -126,7 +126,7 @@ module Spoom
|
|
126
126
|
out: T.any(IO, StringIO),
|
127
127
|
show_strictness: T::Boolean,
|
128
128
|
colors: T::Boolean,
|
129
|
-
indent_level: Integer
|
129
|
+
indent_level: Integer,
|
130
130
|
).void
|
131
131
|
end
|
132
132
|
def initialize(tree:, out: $stdout, show_strictness: true, colors: true, indent_level: 0)
|
data/lib/spoom/git.rb
CHANGED
@@ -6,6 +6,18 @@ require "time"
|
|
6
6
|
module Spoom
|
7
7
|
# Execute git commands
|
8
8
|
module Git
|
9
|
+
class Commit < T::Struct
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
const :sha, String
|
13
|
+
const :time, Time
|
14
|
+
|
15
|
+
sig { returns(Integer) }
|
16
|
+
def timestamp
|
17
|
+
time.to_i
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
9
21
|
class << self
|
10
22
|
extend T::Sig
|
11
23
|
|
@@ -16,7 +28,7 @@ module Spoom
|
|
16
28
|
out: "",
|
17
29
|
err: "Error: `#{path}` is not a directory.",
|
18
30
|
status: false,
|
19
|
-
exit_code: 1
|
31
|
+
exit_code: 1,
|
20
32
|
) unless File.directory?(path)
|
21
33
|
|
22
34
|
T.unsafe(Open3).popen3(command, *arg, chdir: path) do |_, stdout, stderr, thread|
|
@@ -25,7 +37,7 @@ module Spoom
|
|
25
37
|
out: stdout.read,
|
26
38
|
err: stderr.read,
|
27
39
|
status: T.must(status.success?),
|
28
|
-
exit_code: T.must(status.exitstatus)
|
40
|
+
exit_code: T.must(status.exitstatus),
|
29
41
|
)
|
30
42
|
end
|
31
43
|
end
|
@@ -47,11 +59,6 @@ module Spoom
|
|
47
59
|
exec("git log #{arg.join(" ")}", path: path)
|
48
60
|
end
|
49
61
|
|
50
|
-
sig { params(arg: String, path: String).returns(ExecResult) }
|
51
|
-
def rev_parse(*arg, path: ".")
|
52
|
-
exec("git rev-parse --short #{arg.join(" ")}", path: path)
|
53
|
-
end
|
54
|
-
|
55
62
|
sig { params(arg: String, path: String).returns(ExecResult) }
|
56
63
|
def show(*arg, path: ".")
|
57
64
|
exec("git show #{arg.join(" ")}", path: path)
|
@@ -67,37 +74,16 @@ module Spoom
|
|
67
74
|
|
68
75
|
# Utils
|
69
76
|
|
70
|
-
# Get the commit
|
71
|
-
sig { params(
|
72
|
-
def commit_timestamp(sha, path: ".")
|
73
|
-
result = show("--no-notes --no-patch --pretty=%at #{sha}", path: path)
|
74
|
-
return nil unless result.status
|
75
|
-
|
76
|
-
result.out.strip.to_i
|
77
|
-
end
|
78
|
-
|
79
|
-
# Get the commit Time for a `sha`
|
80
|
-
sig { params(sha: String, path: String).returns(T.nilable(Time)) }
|
81
|
-
def commit_time(sha, path: ".")
|
82
|
-
timestamp = commit_timestamp(sha, path: path)
|
83
|
-
return nil unless timestamp
|
84
|
-
|
85
|
-
epoch_to_time(timestamp.to_s)
|
86
|
-
end
|
87
|
-
|
88
|
-
# Get the last commit sha
|
89
|
-
sig { params(path: String).returns(T.nilable(String)) }
|
77
|
+
# Get the last commit in the currently checked out branch
|
78
|
+
sig { params(path: String).returns(T.nilable(Commit)) }
|
90
79
|
def last_commit(path: ".")
|
91
|
-
result =
|
80
|
+
result = log("HEAD --format='%h %at' -1", path: path)
|
92
81
|
return nil unless result.status
|
93
82
|
|
94
|
-
result.out.strip
|
95
|
-
|
83
|
+
out = result.out.strip
|
84
|
+
return nil if out.empty?
|
96
85
|
|
97
|
-
|
98
|
-
sig { params(timestamp: String).returns(Time) }
|
99
|
-
def epoch_to_time(timestamp)
|
100
|
-
Time.strptime(timestamp, "%s")
|
86
|
+
parse_commit(out)
|
101
87
|
end
|
102
88
|
|
103
89
|
# Is there uncommited changes in `path`?
|
@@ -106,28 +92,38 @@ module Spoom
|
|
106
92
|
diff("HEAD", path: path).out.empty?
|
107
93
|
end
|
108
94
|
|
109
|
-
# Get the
|
110
|
-
sig { params(path: String).returns(T.nilable(
|
95
|
+
# Get the commit introducing the `sorbet/config` file
|
96
|
+
sig { params(path: String).returns(T.nilable(Commit)) }
|
111
97
|
def sorbet_intro_commit(path: ".")
|
112
|
-
result =
|
98
|
+
result = log("--diff-filter=A --format='%h %at' -1 -- sorbet/config", path: path)
|
113
99
|
return nil unless result.status
|
114
100
|
|
115
101
|
out = result.out.strip
|
116
102
|
return nil if out.empty?
|
117
103
|
|
118
|
-
out
|
104
|
+
parse_commit(out)
|
119
105
|
end
|
120
106
|
|
121
|
-
# Get the
|
122
|
-
sig { params(path: String).returns(T.nilable(
|
107
|
+
# Get the commit removing the `sorbet/config` file
|
108
|
+
sig { params(path: String).returns(T.nilable(Commit)) }
|
123
109
|
def sorbet_removal_commit(path: ".")
|
124
|
-
result =
|
110
|
+
result = log("--diff-filter=D --format='%h %at' -1 -- sorbet/config", path: path)
|
125
111
|
return nil unless result.status
|
126
112
|
|
127
113
|
out = result.out.strip
|
128
114
|
return nil if out.empty?
|
129
115
|
|
130
|
-
out
|
116
|
+
parse_commit(out)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Parse a line formated as `%h %at` into a `Commit`
|
120
|
+
sig { params(string: String).returns(T.nilable(Commit)) }
|
121
|
+
def parse_commit(string)
|
122
|
+
sha, epoch = string.split(" ", 2)
|
123
|
+
return nil unless sha && epoch
|
124
|
+
|
125
|
+
time = Time.strptime(epoch, "%s")
|
126
|
+
Commit.new(sha: sha, time: time)
|
131
127
|
end
|
132
128
|
end
|
133
129
|
end
|
data/lib/spoom/sorbet/errors.rb
CHANGED
@@ -23,7 +23,7 @@ module Spoom
|
|
23
23
|
def from_json(json)
|
24
24
|
Diagnostics.new(
|
25
25
|
json["uri"],
|
26
|
-
json["diagnostics"].map { |d| Diagnostic.from_json(d) }
|
26
|
+
json["diagnostics"].map { |d| Diagnostic.from_json(d) },
|
27
27
|
)
|
28
28
|
end
|
29
29
|
end
|
@@ -54,7 +54,7 @@ module Spoom
|
|
54
54
|
ResponseError.new(
|
55
55
|
json["code"],
|
56
56
|
json["message"],
|
57
|
-
json["data"]
|
57
|
+
json["data"],
|
58
58
|
)
|
59
59
|
end
|
60
60
|
end
|
@@ -30,7 +30,7 @@ module Spoom
|
|
30
30
|
def from_json(json)
|
31
31
|
Hover.new(
|
32
32
|
contents: json["contents"]["value"],
|
33
|
-
range: json["range"] ? Range.from_json(json["range"]) : nil
|
33
|
+
range: json["range"] ? Range.from_json(json["range"]) : nil,
|
34
34
|
)
|
35
35
|
end
|
36
36
|
end
|
@@ -61,7 +61,7 @@ module Spoom
|
|
61
61
|
def from_json(json)
|
62
62
|
Position.new(
|
63
63
|
line: json["line"].to_i,
|
64
|
-
char: json["character"].to_i
|
64
|
+
char: json["character"].to_i,
|
65
65
|
)
|
66
66
|
end
|
67
67
|
end
|
@@ -91,7 +91,7 @@ module Spoom
|
|
91
91
|
def from_json(json)
|
92
92
|
Range.new(
|
93
93
|
start: Position.from_json(json["start"]),
|
94
|
-
end: Position.from_json(json["end"])
|
94
|
+
end: Position.from_json(json["end"]),
|
95
95
|
)
|
96
96
|
end
|
97
97
|
end
|
@@ -123,7 +123,7 @@ module Spoom
|
|
123
123
|
def from_json(json)
|
124
124
|
Location.new(
|
125
125
|
uri: json["uri"],
|
126
|
-
range: Range.from_json(json["range"])
|
126
|
+
range: Range.from_json(json["range"]),
|
127
127
|
)
|
128
128
|
end
|
129
129
|
end
|
@@ -193,7 +193,7 @@ module Spoom
|
|
193
193
|
range: Range.from_json(json["range"]),
|
194
194
|
code: json["code"].to_i,
|
195
195
|
message: json["message"],
|
196
|
-
informations: json["relatedInformation"]
|
196
|
+
informations: json["relatedInformation"],
|
197
197
|
)
|
198
198
|
end
|
199
199
|
end
|
@@ -317,7 +317,7 @@ module Spoom
|
|
317
317
|
out: T.any(IO, StringIO),
|
318
318
|
colors: T::Boolean,
|
319
319
|
indent_level: Integer,
|
320
|
-
prefix: T.nilable(String)
|
320
|
+
prefix: T.nilable(String),
|
321
321
|
).void
|
322
322
|
end
|
323
323
|
def initialize(out: $stdout, colors: true, indent_level: 0, prefix: nil)
|
data/lib/spoom/sorbet/lsp.rb
CHANGED
@@ -98,7 +98,7 @@ module Spoom
|
|
98
98
|
"line" => line,
|
99
99
|
"character" => column,
|
100
100
|
},
|
101
|
-
}
|
101
|
+
},
|
102
102
|
))
|
103
103
|
|
104
104
|
return nil unless json && json["result"]
|
@@ -119,7 +119,7 @@ module Spoom
|
|
119
119
|
"line" => line,
|
120
120
|
"character" => column,
|
121
121
|
},
|
122
|
-
}
|
122
|
+
},
|
123
123
|
))
|
124
124
|
|
125
125
|
return [] unless json && json["result"] && json["result"]["signatures"]
|
@@ -140,7 +140,7 @@ module Spoom
|
|
140
140
|
"line" => line,
|
141
141
|
"character" => column,
|
142
142
|
},
|
143
|
-
}
|
143
|
+
},
|
144
144
|
))
|
145
145
|
|
146
146
|
return [] unless json && json["result"]
|
@@ -161,7 +161,7 @@ module Spoom
|
|
161
161
|
"line" => line,
|
162
162
|
"character" => column,
|
163
163
|
},
|
164
|
-
}
|
164
|
+
},
|
165
165
|
))
|
166
166
|
|
167
167
|
return [] unless json && json["result"]
|
@@ -185,7 +185,7 @@ module Spoom
|
|
185
185
|
"context" => {
|
186
186
|
"includeDeclaration" => include_decl,
|
187
187
|
},
|
188
|
-
}
|
188
|
+
},
|
189
189
|
))
|
190
190
|
|
191
191
|
return [] unless json && json["result"]
|
@@ -200,7 +200,7 @@ module Spoom
|
|
200
200
|
"workspace/symbol",
|
201
201
|
{
|
202
202
|
"query" => query,
|
203
|
-
}
|
203
|
+
},
|
204
204
|
))
|
205
205
|
|
206
206
|
return [] unless json && json["result"]
|
@@ -217,7 +217,7 @@ module Spoom
|
|
217
217
|
"textDocument" => {
|
218
218
|
"uri" => uri,
|
219
219
|
},
|
220
|
-
}
|
220
|
+
},
|
221
221
|
))
|
222
222
|
|
223
223
|
return [] unless json && json["result"]
|
data/lib/spoom/sorbet/sigils.rb
CHANGED
data/lib/spoom/sorbet.rb
CHANGED
@@ -25,7 +25,7 @@ module Spoom
|
|
25
25
|
arg: String,
|
26
26
|
path: String,
|
27
27
|
capture_err: T::Boolean,
|
28
|
-
sorbet_bin: T.nilable(String)
|
28
|
+
sorbet_bin: T.nilable(String),
|
29
29
|
).returns(ExecResult)
|
30
30
|
end
|
31
31
|
def srb(*arg, path: ".", capture_err: false, sorbet_bin: nil)
|
@@ -42,7 +42,7 @@ module Spoom
|
|
42
42
|
arg: String,
|
43
43
|
path: String,
|
44
44
|
capture_err: T::Boolean,
|
45
|
-
sorbet_bin: T.nilable(String)
|
45
|
+
sorbet_bin: T.nilable(String),
|
46
46
|
).returns(ExecResult)
|
47
47
|
end
|
48
48
|
def srb_tc(*arg, path: ".", capture_err: false, sorbet_bin: nil)
|
@@ -65,7 +65,7 @@ module Spoom
|
|
65
65
|
arg: String,
|
66
66
|
path: String,
|
67
67
|
capture_err: T::Boolean,
|
68
|
-
sorbet_bin: T.nilable(String)
|
68
|
+
sorbet_bin: T.nilable(String),
|
69
69
|
).returns(T.nilable(String))
|
70
70
|
end
|
71
71
|
def srb_version(*arg, path: ".", capture_err: false, sorbet_bin: nil)
|
@@ -75,7 +75,7 @@ module Spoom
|
|
75
75
|
*arg,
|
76
76
|
path: path,
|
77
77
|
capture_err: capture_err,
|
78
|
-
sorbet_bin: sorbet_bin
|
78
|
+
sorbet_bin: sorbet_bin,
|
79
79
|
), ExecResult)
|
80
80
|
return nil unless result.status
|
81
81
|
|
@@ -87,7 +87,7 @@ module Spoom
|
|
87
87
|
arg: String,
|
88
88
|
path: String,
|
89
89
|
capture_err: T::Boolean,
|
90
|
-
sorbet_bin: T.nilable(String)
|
90
|
+
sorbet_bin: T.nilable(String),
|
91
91
|
).returns(T.nilable(T::Hash[String, Integer]))
|
92
92
|
end
|
93
93
|
def srb_metrics(*arg, path: ".", capture_err: false, sorbet_bin: nil)
|
@@ -99,7 +99,7 @@ module Spoom
|
|
99
99
|
*arg,
|
100
100
|
path: path,
|
101
101
|
capture_err: capture_err,
|
102
|
-
sorbet_bin: sorbet_bin
|
102
|
+
sorbet_bin: sorbet_bin,
|
103
103
|
)
|
104
104
|
if File.exist?(metrics_path)
|
105
105
|
metrics = Spoom::Sorbet::MetricsParser.parse_file(metrics_path)
|
data/lib/spoom/timeline.rb
CHANGED
@@ -15,7 +15,7 @@ module Spoom
|
|
15
15
|
end
|
16
16
|
|
17
17
|
# Return one commit for each month between `from` and `to`
|
18
|
-
sig { returns(T::Array[
|
18
|
+
sig { returns(T::Array[Git::Commit]) }
|
19
19
|
def ticks
|
20
20
|
commits_for_dates(months)
|
21
21
|
end
|
@@ -34,21 +34,21 @@ module Spoom
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# Return one commit for each date in `dates`
|
37
|
-
sig { params(dates: T::Array[Time]).returns(T::Array[
|
37
|
+
sig { params(dates: T::Array[Time]).returns(T::Array[Git::Commit]) }
|
38
38
|
def commits_for_dates(dates)
|
39
39
|
dates.map do |t|
|
40
40
|
result = Spoom::Git.log(
|
41
41
|
"--since='#{t}'",
|
42
42
|
"--until='#{t.to_date.next_month}'",
|
43
|
-
"--format='format:%h'",
|
43
|
+
"--format='format:%h %at'",
|
44
44
|
"--author-date-order",
|
45
45
|
"-1",
|
46
46
|
path: @path,
|
47
47
|
)
|
48
48
|
next if result.out.empty?
|
49
49
|
|
50
|
-
result.out
|
51
|
-
end.compact.uniq
|
50
|
+
Git.parse_commit(result.out.strip)
|
51
|
+
end.compact.uniq(&:sha)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
data/lib/spoom/version.rb
CHANGED
data/lib/spoom.rb
CHANGED
@@ -39,7 +39,7 @@ module Spoom
|
|
39
39
|
cmd: String,
|
40
40
|
arg: String,
|
41
41
|
path: String,
|
42
|
-
capture_err: T::Boolean
|
42
|
+
capture_err: T::Boolean,
|
43
43
|
).returns(ExecResult)
|
44
44
|
end
|
45
45
|
def exec(cmd, *arg, path: ".", capture_err: false)
|
@@ -49,7 +49,7 @@ module Spoom
|
|
49
49
|
out: stdout,
|
50
50
|
err: stderr,
|
51
51
|
status: status.success?,
|
52
|
-
exit_code: status.exitstatus
|
52
|
+
exit_code: status.exitstatus,
|
53
53
|
)
|
54
54
|
else
|
55
55
|
stdout, status = T.unsafe(Open3).capture2([cmd, *arg].join(" "), chdir: path)
|
@@ -57,7 +57,7 @@ module Spoom
|
|
57
57
|
out: stdout,
|
58
58
|
err: "",
|
59
59
|
status: status.success?,
|
60
|
-
exit_code: status.exitstatus
|
60
|
+
exit_code: status.exitstatus,
|
61
61
|
)
|
62
62
|
end
|
63
63
|
end
|
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.13
|
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-11-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|