spoom 1.1.12 → 1.1.13

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: ed6d04e01efc1c6c8c00df77ad340f189a277aebf3afbd64edbd89f6145541f2
4
- data.tar.gz: 1935557277bcfdb54b4ab0d389ab5a72fb5b2d00a6631f6c787dae9d83dac7c4
3
+ metadata.gz: 5cad6017cf76302bc359d170fce6c2e33c4ff5923a564b26e2f270b42c102e3d
4
+ data.tar.gz: 734654483394f8520346d0ddab7872e1c7f42de4eed7523e503264f8045bf2c9
5
5
  SHA512:
6
- metadata.gz: 781d3bb6443c518fc1d4334e5c4ac17a09372ba9115f024bcdceb5cf15af4d4524d1e4cb465963ce5d23aaa07ebd5ab2114ebe81b4eea3fffe27942295e21b9f
7
- data.tar.gz: 3427fdfe5cd483609fbbe6618de2f8a536f8bf0727a6865e44c2c4c9b74f9303c0fdcfdefd44bdd547d16e6766f0f09fa49c1e8cd991d0efcffaa37f3c9c7609
6
+ metadata.gz: a67da9fa2811e15d5bfc5f554a2b1cb23bed4a0744617d1168b3d3d4c08f4f6828b207142996fb8cebc57ca8732d901e3e390c43939eaa504a2ed1cc1fe611b4
7
+ data.tar.gz: 1b98af8f37acd554f908fdde1257f9c53eaab0a37b21847e619caee5cdda44e9f06e248545ec247cb43c6ac434d5e00bce4b6731eb434c62bd3a60a72c67313f
@@ -71,7 +71,7 @@ module Spoom
71
71
  say("\n")
72
72
 
73
73
  if files_to_bump.empty?
74
- say("No file to bump from `#{from}` to `#{to}`")
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
- if files.empty?
136
- say("No file to bump from `#{from}` to `#{to}`")
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 << " `#{files.size}` file#{"s" if files.size > 1}"
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
@@ -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
- intro_sha = Spoom::Git.sorbet_intro_commit(path: path)
75
- intro_sha = T.must(intro_sha) # we know it's in there since in_sorbet_project!
76
- from = Spoom::Git.commit_time(intro_sha, path: path)
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 |sha, i|
88
- date = Spoom::Git.commit_time(sha, path: path)
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)
@@ -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.sigils.select { |_k, v| v })
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(id, title, { true: snapshot.methods_with_sig, false: snapshot.methods_without_sig })
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(d, (d.data.key == "true" ? " with" : " without") + " a signature", "methods", sum_#{id})
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.sigils,
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.methods_with_sig + snapshot.methods_without_sig,
486
- values: { true: snapshot.methods_with_sig, false: snapshot.methods_without_sig },
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} (including #{snapshot.rbi_files} RBIs)")
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,
@@ -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
- sha = Spoom::Git.last_commit(path: path)
38
- snapshot.commit_sha = sha
39
- snapshot.commit_timestamp = Spoom::Git.commit_timestamp(sha, path: path).to_i if sha
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
- Snapshot::STRICTNESSES.each do |strictness|
54
- next unless metrics.key?("types.input.files.sigil.#{strictness}")
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
- snapshot.sigils[strictness] = T.must(metrics["types.input.files.sigil.#{strictness}"])
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: intro_date,
98
+ sorbet_intro_commit: intro_commit&.sha,
99
+ sorbet_intro_date: intro_commit&.time,
80
100
  )
81
101
  end
82
102
 
@@ -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 epoch timestamp for a `sha`
71
- sig { params(sha: String, path: String).returns(T.nilable(Integer)) }
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 = rev_parse("HEAD", path: path)
80
+ result = log("HEAD --format='%h %at' -1", path: path)
92
81
  return nil unless result.status
93
82
 
94
- result.out.strip
95
- end
83
+ out = result.out.strip
84
+ return nil if out.empty?
96
85
 
97
- # Translate a git epoch timestamp into a Time
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 hash of the commit introducing the `sorbet/config` file
110
- sig { params(path: String).returns(T.nilable(String)) }
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 = Spoom::Git.log("--diff-filter=A --format='%h' -1 -- sorbet/config", path: path)
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 hash of the commit removing the `sorbet/config` file
122
- sig { params(path: String).returns(T.nilable(String)) }
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 = Spoom::Git.log("--diff-filter=D --format='%h' -1 -- sorbet/config", path: path)
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
@@ -142,7 +142,7 @@ module Spoom
142
142
  line: T.nilable(Integer),
143
143
  message: T.nilable(String),
144
144
  code: T.nilable(Integer),
145
- more: T::Array[String]
145
+ more: T::Array[String],
146
146
  ).void
147
147
  end
148
148
  def initialize(file, line, message, code, more = [])
@@ -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)
@@ -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"]
@@ -88,7 +88,7 @@ module Spoom
88
88
  params(
89
89
  directory: T.any(String, Pathname),
90
90
  strictness: String,
91
- extension: String
91
+ extension: String,
92
92
  ).returns(T::Array[String])
93
93
  end
94
94
  def files_with_sigil_strictness(directory, strictness, extension: ".rb")
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)
@@ -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[String]) }
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[String]) }
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
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Spoom
5
- VERSION = "1.1.12"
5
+ VERSION = "1.1.13"
6
6
  end
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.12
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-08-18 00:00:00.000000000 Z
11
+ date: 2022-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler