spoom 1.1.15 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -273,34 +273,37 @@ module Spoom
273
273
  SYMBOL_KINDS[kind] || "<unknown:#{kind}>"
274
274
  end
275
275
 
276
- SYMBOL_KINDS = T.let({
277
- 1 => "file",
278
- 2 => "module",
279
- 3 => "namespace",
280
- 4 => "package",
281
- 5 => "class",
282
- 6 => "def",
283
- 7 => "property",
284
- 8 => "field",
285
- 9 => "constructor",
286
- 10 => "enum",
287
- 11 => "interface",
288
- 12 => "function",
289
- 13 => "variable",
290
- 14 => "const",
291
- 15 => "string",
292
- 16 => "number",
293
- 17 => "boolean",
294
- 18 => "array",
295
- 19 => "object",
296
- 20 => "key",
297
- 21 => "null",
298
- 22 => "enum_member",
299
- 23 => "struct",
300
- 24 => "event",
301
- 25 => "operator",
302
- 26 => "type_parameter",
303
- }, T::Hash[Integer, String])
276
+ SYMBOL_KINDS = T.let(
277
+ {
278
+ 1 => "file",
279
+ 2 => "module",
280
+ 3 => "namespace",
281
+ 4 => "package",
282
+ 5 => "class",
283
+ 6 => "def",
284
+ 7 => "property",
285
+ 8 => "field",
286
+ 9 => "constructor",
287
+ 10 => "enum",
288
+ 11 => "interface",
289
+ 12 => "function",
290
+ 13 => "variable",
291
+ 14 => "const",
292
+ 15 => "string",
293
+ 16 => "number",
294
+ 17 => "boolean",
295
+ 18 => "array",
296
+ 19 => "object",
297
+ 20 => "key",
298
+ 21 => "null",
299
+ 22 => "enum_member",
300
+ 23 => "struct",
301
+ 24 => "event",
302
+ 25 => "operator",
303
+ 26 => "type_parameter",
304
+ },
305
+ T::Hash[Integer, String],
306
+ )
304
307
  end
305
308
 
306
309
  class SymbolPrinter < Printer
@@ -16,14 +16,17 @@ module Spoom
16
16
  STRICTNESS_STRONG = "strong"
17
17
  STRICTNESS_INTERNAL = "__STDLIB_INTERNAL"
18
18
 
19
- VALID_STRICTNESS = T.let([
20
- STRICTNESS_IGNORE,
21
- STRICTNESS_FALSE,
22
- STRICTNESS_TRUE,
23
- STRICTNESS_STRICT,
24
- STRICTNESS_STRONG,
25
- STRICTNESS_INTERNAL,
26
- ].freeze, T::Array[String])
19
+ VALID_STRICTNESS = T.let(
20
+ [
21
+ STRICTNESS_IGNORE,
22
+ STRICTNESS_FALSE,
23
+ STRICTNESS_TRUE,
24
+ STRICTNESS_STRICT,
25
+ STRICTNESS_STRONG,
26
+ STRICTNESS_INTERNAL,
27
+ ].freeze,
28
+ T::Array[String],
29
+ )
27
30
 
28
31
  SIGIL_REGEXP = T.let(/^#[\ t]*typed[\ t]*:[ \t]*(\w*)[ \t]*/.freeze, Regexp)
29
32
 
data/lib/spoom/sorbet.rb CHANGED
@@ -11,117 +11,33 @@ require "open3"
11
11
 
12
12
  module Spoom
13
13
  module Sorbet
14
- CONFIG_PATH = "sorbet/config"
15
- GEM_PATH = T.let(Gem::Specification.find_by_name("sorbet-static").full_gem_path, String)
16
- BIN_PATH = T.let((Pathname.new(GEM_PATH) / "libexec" / "sorbet").to_s, String)
17
-
18
- SEGFAULT_CODE = 139
19
-
20
- class << self
14
+ class Error < StandardError
21
15
  extend T::Sig
22
16
 
23
- sig do
24
- params(
25
- arg: String,
26
- path: String,
27
- capture_err: T::Boolean,
28
- sorbet_bin: T.nilable(String),
29
- ).returns(ExecResult)
30
- end
31
- def srb(*arg, path: ".", capture_err: false, sorbet_bin: nil)
32
- if sorbet_bin
33
- arg.prepend(sorbet_bin)
34
- else
35
- arg.prepend("bundle", "exec", "srb")
36
- end
37
- Spoom.exec(*T.unsafe(arg), path: path, capture_err: capture_err)
38
- end
17
+ class Killed < Error; end
18
+ class Segfault < Error; end
39
19
 
40
- sig do
41
- params(
42
- arg: String,
43
- path: String,
44
- capture_err: T::Boolean,
45
- sorbet_bin: T.nilable(String),
46
- ).returns(ExecResult)
47
- end
48
- def srb_tc(*arg, path: ".", capture_err: false, sorbet_bin: nil)
49
- arg.prepend("tc") unless sorbet_bin
50
- srb(*T.unsafe(arg), path: path, capture_err: capture_err, sorbet_bin: sorbet_bin)
51
- end
52
-
53
- # List all files typechecked by Sorbet from its `config`
54
- sig { params(config: Config, path: String).returns(T::Array[String]) }
55
- def srb_files(config, path: ".")
56
- regs = config.ignore.map { |string| Regexp.new(Regexp.escape(string)) }
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
- regs.any? { |re| re.match?(f) }
60
- end.sort
61
- end
20
+ sig { returns(ExecResult) }
21
+ attr_reader :result
62
22
 
63
23
  sig do
64
24
  params(
65
- arg: String,
66
- path: String,
67
- capture_err: T::Boolean,
68
- sorbet_bin: T.nilable(String),
69
- ).returns(T.nilable(String))
25
+ message: String,
26
+ result: ExecResult,
27
+ ).void
70
28
  end
71
- def srb_version(*arg, path: ".", capture_err: false, sorbet_bin: nil)
72
- result = T.let(T.unsafe(self).srb_tc(
73
- "--no-config",
74
- "--version",
75
- *arg,
76
- path: path,
77
- capture_err: capture_err,
78
- sorbet_bin: sorbet_bin,
79
- ), ExecResult)
80
- return nil unless result.status
29
+ def initialize(message, result)
30
+ super(message)
81
31
 
82
- result.out.split(" ")[2]
32
+ @result = result
83
33
  end
34
+ end
84
35
 
85
- sig do
86
- params(
87
- arg: String,
88
- path: String,
89
- capture_err: T::Boolean,
90
- sorbet_bin: T.nilable(String),
91
- ).returns(T.nilable(T::Hash[String, Integer]))
92
- end
93
- def srb_metrics(*arg, path: ".", capture_err: false, sorbet_bin: nil)
94
- metrics_file = "metrics.tmp"
95
- metrics_path = "#{path}/#{metrics_file}"
96
- T.unsafe(self).srb_tc(
97
- "--metrics-file",
98
- metrics_file,
99
- *arg,
100
- path: path,
101
- capture_err: capture_err,
102
- sorbet_bin: sorbet_bin,
103
- )
104
- if File.exist?(metrics_path)
105
- metrics = Spoom::Sorbet::MetricsParser.parse_file(metrics_path)
106
- File.delete(metrics_path)
107
- return metrics
108
- end
109
- nil
110
- end
111
-
112
- # Get `gem` version from the `Gemfile.lock` content
113
- #
114
- # Returns `nil` if `gem` cannot be found in the Gemfile.
115
- sig { params(gem: String, path: String).returns(T.nilable(String)) }
116
- def version_from_gemfile_lock(gem: "sorbet", path: ".")
117
- gemfile_path = "#{path}/Gemfile.lock"
118
- return nil unless File.exist?(gemfile_path)
119
-
120
- content = File.read(gemfile_path).match(/^ #{gem} \(.*(\d+\.\d+\.\d+).*\)/)
121
- return nil unless content
36
+ CONFIG_PATH = "sorbet/config"
37
+ GEM_PATH = T.let(Gem::Specification.find_by_name("sorbet-static").full_gem_path, String)
38
+ BIN_PATH = T.let((Pathname.new(GEM_PATH) / "libexec" / "sorbet").to_s, String)
122
39
 
123
- content[1]
124
- end
125
- end
40
+ KILLED_CODE = 137
41
+ SEGFAULT_CODE = 139
126
42
  end
127
43
  end
@@ -1,17 +1,15 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative "git"
5
-
6
4
  module Spoom
7
5
  class Timeline
8
6
  extend T::Sig
9
7
 
10
- sig { params(from: Time, to: Time, path: String).void }
11
- def initialize(from, to, path: ".")
8
+ sig { params(context: Context, from: Time, to: Time).void }
9
+ def initialize(context, from, to)
10
+ @context = context
12
11
  @from = from
13
12
  @to = to
14
- @path = path
15
13
  end
16
14
 
17
15
  # Return one commit for each month between `from` and `to`
@@ -37,17 +35,16 @@ module Spoom
37
35
  sig { params(dates: T::Array[Time]).returns(T::Array[Git::Commit]) }
38
36
  def commits_for_dates(dates)
39
37
  dates.map do |t|
40
- result = Spoom::Git.log(
38
+ result = @context.git_log(
41
39
  "--since='#{t}'",
42
40
  "--until='#{t.to_date.next_month}'",
43
41
  "--format='format:%h %at'",
44
42
  "--author-date-order",
45
43
  "-1",
46
- path: @path,
47
44
  )
48
45
  next if result.out.empty?
49
46
 
50
- Git.parse_commit(result.out.strip)
47
+ Spoom::Git::Commit.parse_line(result.out.strip)
51
48
  end.compact.uniq(&:sha)
52
49
  end
53
50
  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.15"
5
+ VERSION = "1.2.0"
6
6
  end
data/lib/spoom.rb CHANGED
@@ -10,58 +10,6 @@ module Spoom
10
10
  SPOOM_PATH = T.let((Pathname.new(__FILE__) / ".." / "..").to_s, String)
11
11
 
12
12
  class Error < StandardError; end
13
-
14
- class ExecResult < T::Struct
15
- extend T::Sig
16
-
17
- const :out, String
18
- const :err, String
19
- const :status, T::Boolean
20
- const :exit_code, Integer
21
-
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
32
- end
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
63
- end
64
- end
65
13
  end
66
14
 
67
15
  require "spoom/context"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spoom
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.15
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre Terrasa
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-14 00:00:00.000000000 Z
11
+ date: 2023-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -130,6 +130,11 @@ files:
130
130
  - lib/spoom/cli/run.rb
131
131
  - lib/spoom/colors.rb
132
132
  - lib/spoom/context.rb
133
+ - lib/spoom/context/bundle.rb
134
+ - lib/spoom/context/exec.rb
135
+ - lib/spoom/context/file_system.rb
136
+ - lib/spoom/context/git.rb
137
+ - lib/spoom/context/sorbet.rb
133
138
  - lib/spoom/coverage.rb
134
139
  - lib/spoom/coverage/d3.rb
135
140
  - lib/spoom/coverage/d3/base.rb
@@ -139,7 +144,6 @@ files:
139
144
  - lib/spoom/coverage/report.rb
140
145
  - lib/spoom/coverage/snapshot.rb
141
146
  - lib/spoom/file_tree.rb
142
- - lib/spoom/git.rb
143
147
  - lib/spoom/printer.rb
144
148
  - lib/spoom/sorbet.rb
145
149
  - lib/spoom/sorbet/config.rb
@@ -175,7 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
179
  - !ruby/object:Gem::Version
176
180
  version: '0'
177
181
  requirements: []
178
- rubygems_version: 3.3.3
182
+ rubygems_version: 3.4.9
179
183
  signing_key:
180
184
  specification_version: 4
181
185
  summary: Useful tools for Sorbet enthusiasts.
data/lib/spoom/git.rb DELETED
@@ -1,130 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require "time"
5
-
6
- module Spoom
7
- # Execute git commands
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
-
21
- class << self
22
- extend T::Sig
23
-
24
- # Execute a `command`
25
- sig { params(command: String, arg: String, path: String).returns(ExecResult) }
26
- def exec(command, *arg, path: ".")
27
- return ExecResult.new(
28
- out: "",
29
- err: "Error: `#{path}` is not a directory.",
30
- status: false,
31
- exit_code: 1,
32
- ) unless File.directory?(path)
33
-
34
- T.unsafe(Open3).popen3(command, *arg, chdir: path) do |_, stdout, stderr, thread|
35
- status = T.cast(thread.value, Process::Status)
36
- ExecResult.new(
37
- out: stdout.read,
38
- err: stderr.read,
39
- status: T.must(status.success?),
40
- exit_code: T.must(status.exitstatus),
41
- )
42
- end
43
- end
44
-
45
- # Git commands
46
-
47
- sig { params(arg: String, path: String).returns(ExecResult) }
48
- def checkout(*arg, path: ".")
49
- exec("git checkout -q #{arg.join(" ")}", path: path)
50
- end
51
-
52
- sig { params(arg: String, path: String).returns(ExecResult) }
53
- def diff(*arg, path: ".")
54
- exec("git diff #{arg.join(" ")}", path: path)
55
- end
56
-
57
- sig { params(arg: String, path: String).returns(ExecResult) }
58
- def log(*arg, path: ".")
59
- exec("git log #{arg.join(" ")}", path: path)
60
- end
61
-
62
- sig { params(arg: String, path: String).returns(ExecResult) }
63
- def show(*arg, path: ".")
64
- exec("git show #{arg.join(" ")}", path: path)
65
- end
66
-
67
- sig { params(path: String).returns(T.nilable(String)) }
68
- def current_branch(path: ".")
69
- result = exec("git branch --show-current", path: path)
70
- return nil unless result.status
71
-
72
- result.out.strip
73
- end
74
-
75
- # Utils
76
-
77
- # Get the last commit in the currently checked out branch
78
- sig { params(path: String, short_sha: T::Boolean).returns(T.nilable(Commit)) }
79
- def last_commit(path: ".", short_sha: true)
80
- result = log("HEAD --format='%#{short_sha ? "h" : "H"} %at' -1", path: path)
81
- return nil unless result.status
82
-
83
- out = result.out.strip
84
- return nil if out.empty?
85
-
86
- parse_commit(out)
87
- end
88
-
89
- # Is there uncommited changes in `path`?
90
- sig { params(path: String).returns(T::Boolean) }
91
- def workdir_clean?(path: ".")
92
- diff("HEAD", path: path).out.empty?
93
- end
94
-
95
- # Get the commit introducing the `sorbet/config` file
96
- sig { params(path: String).returns(T.nilable(Commit)) }
97
- def sorbet_intro_commit(path: ".")
98
- result = log("--diff-filter=A --format='%h %at' -1 -- sorbet/config", path: path)
99
- return nil unless result.status
100
-
101
- out = result.out.strip
102
- return nil if out.empty?
103
-
104
- parse_commit(out)
105
- end
106
-
107
- # Get the commit removing the `sorbet/config` file
108
- sig { params(path: String).returns(T.nilable(Commit)) }
109
- def sorbet_removal_commit(path: ".")
110
- result = log("--diff-filter=D --format='%h %at' -1 -- sorbet/config", path: path)
111
- return nil unless result.status
112
-
113
- out = result.out.strip
114
- return nil if out.empty?
115
-
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)
127
- end
128
- end
129
- end
130
- end