spoom 1.1.15 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,121 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Spoom
5
+ module Git
6
+ class Commit < T::Struct
7
+ extend T::Sig
8
+
9
+ class << self
10
+ extend T::Sig
11
+
12
+ # Parse a line formated as `%h %at` into a `Commit`
13
+ sig { params(string: String).returns(T.nilable(Commit)) }
14
+ def parse_line(string)
15
+ sha, epoch = string.split(" ", 2)
16
+ return nil unless sha && epoch
17
+
18
+ time = Time.strptime(epoch, "%s")
19
+ Commit.new(sha: sha, time: time)
20
+ end
21
+ end
22
+
23
+ const :sha, String
24
+ const :time, Time
25
+
26
+ sig { returns(Integer) }
27
+ def timestamp
28
+ time.to_i
29
+ end
30
+ end
31
+ end
32
+
33
+ class Context
34
+ # Git features for a context
35
+ module Git
36
+ extend T::Sig
37
+ extend T::Helpers
38
+
39
+ requires_ancestor { Context }
40
+
41
+ # Run a command prefixed by `git` in this context directory
42
+ sig { params(command: String).returns(ExecResult) }
43
+ def git(command)
44
+ exec("git #{command}")
45
+ end
46
+
47
+ # Run `git init` in this context directory
48
+ #
49
+ # Warning: passing a branch will run `git init -b <branch>` which is only available in git 2.28+.
50
+ # In older versions, use `git_init!` followed by `git("checkout -b <branch>")`.
51
+ sig { params(branch: T.nilable(String)).returns(ExecResult) }
52
+ def git_init!(branch: nil)
53
+ if branch
54
+ git("init -b #{branch}")
55
+ else
56
+ git("init")
57
+ end
58
+ end
59
+
60
+ # Run `git checkout` in this context directory
61
+ sig { params(ref: String).returns(ExecResult) }
62
+ def git_checkout!(ref: "main")
63
+ git("checkout #{ref}")
64
+ end
65
+
66
+ # Run `git add . && git commit` in this context directory
67
+ sig { params(message: String, time: Time, allow_empty: T::Boolean).void }
68
+ def git_commit!(message: "message", time: Time.now.utc, allow_empty: false)
69
+ git("add --all")
70
+
71
+ args = ["-m '#{message}'", "--date '#{time}'"]
72
+ args << "--allow-empty" if allow_empty
73
+
74
+ exec("GIT_COMMITTER_DATE=\"#{time}\" git -c commit.gpgsign=false commit #{args.join(" ")}")
75
+ end
76
+
77
+ # Get the current git branch in this context directory
78
+ sig { returns(T.nilable(String)) }
79
+ def git_current_branch
80
+ res = git("branch --show-current")
81
+ return nil unless res.status
82
+
83
+ res.out.strip
84
+ end
85
+
86
+ # Run `git diff` in this context directory
87
+ sig { params(arg: String).returns(ExecResult) }
88
+ def git_diff(*arg)
89
+ git("diff #{arg.join(" ")}")
90
+ end
91
+
92
+ # Get the last commit in the currently checked out branch
93
+ sig { params(short_sha: T::Boolean).returns(T.nilable(Spoom::Git::Commit)) }
94
+ def git_last_commit(short_sha: true)
95
+ res = git_log("HEAD --format='%#{short_sha ? "h" : "H"} %at' -1")
96
+ return nil unless res.status
97
+
98
+ out = res.out.strip
99
+ return nil if out.empty?
100
+
101
+ Spoom::Git::Commit.parse_line(out)
102
+ end
103
+
104
+ sig { params(arg: String).returns(ExecResult) }
105
+ def git_log(*arg)
106
+ git("log #{arg.join(" ")}")
107
+ end
108
+
109
+ sig { params(arg: String).returns(ExecResult) }
110
+ def git_show(*arg)
111
+ git("show #{arg.join(" ")}")
112
+ end
113
+
114
+ # Is there uncommited changes in this context directory?
115
+ sig { params(path: String).returns(T::Boolean) }
116
+ def git_workdir_clean?(path: ".")
117
+ git_diff("HEAD").out.empty?
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,136 @@
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)).returns(T::Array[String]) }
65
+ def srb_files(with_config: nil)
66
+ config = with_config || sorbet_config
67
+ regs = config.ignore.map { |string| Regexp.new(Regexp.escape(string)) }
68
+ exts = config.allowed_extensions.empty? ? [".rb", ".rbi"] : config.allowed_extensions
69
+ glob("**/*{#{exts.join(",")}}").reject do |f|
70
+ regs.any? { |re| re.match?(f) }
71
+ end.sort
72
+ end
73
+
74
+ sig { params(arg: String, sorbet_bin: T.nilable(String), capture_err: T::Boolean).returns(T.nilable(String)) }
75
+ def srb_version(*arg, sorbet_bin: nil, capture_err: true)
76
+ res = T.unsafe(self).srb_tc("--no-config", "--version", *arg, sorbet_bin: sorbet_bin, capture_err: capture_err)
77
+ return nil unless res.status
78
+
79
+ res.out.split(" ")[2]
80
+ end
81
+
82
+ # Does this context has a `sorbet/config` file?
83
+ sig { returns(T::Boolean) }
84
+ def has_sorbet_config?
85
+ file?(Spoom::Sorbet::CONFIG_PATH)
86
+ end
87
+
88
+ sig { returns(Spoom::Sorbet::Config) }
89
+ def sorbet_config
90
+ Spoom::Sorbet::Config.parse_string(read_sorbet_config)
91
+ end
92
+
93
+ # Read the contents of `sorbet/config` in this context directory
94
+ sig { returns(String) }
95
+ def read_sorbet_config
96
+ read(Spoom::Sorbet::CONFIG_PATH)
97
+ end
98
+
99
+ # Set the `contents` of `sorbet/config` in this context directory
100
+ sig { params(contents: String, append: T::Boolean).void }
101
+ def write_sorbet_config!(contents, append: false)
102
+ write!(Spoom::Sorbet::CONFIG_PATH, contents, append: append)
103
+ end
104
+
105
+ # Read the strictness sigil from the file at `relative_path` (returns `nil` if no sigil)
106
+ sig { params(relative_path: String).returns(T.nilable(String)) }
107
+ def read_file_strictness(relative_path)
108
+ Spoom::Sorbet::Sigils.file_strictness(absolute_path_to(relative_path))
109
+ end
110
+
111
+ # Get the commit introducing the `sorbet/config` file
112
+ sig { returns(T.nilable(Spoom::Git::Commit)) }
113
+ def sorbet_intro_commit
114
+ res = git_log("--diff-filter=A --format='%h %at' -1 -- sorbet/config")
115
+ return nil unless res.status
116
+
117
+ out = res.out.strip
118
+ return nil if out.empty?
119
+
120
+ Spoom::Git::Commit.parse_line(out)
121
+ end
122
+
123
+ # Get the commit removing the `sorbet/config` file
124
+ sig { returns(T.nilable(Spoom::Git::Commit)) }
125
+ def sorbet_removal_commit
126
+ res = git_log("--diff-filter=D --format='%h %at' -1 -- sorbet/config")
127
+ return nil unless res.status
128
+
129
+ out = res.out.strip
130
+ return nil if out.empty?
131
+
132
+ Spoom::Git::Commit.parse_line(out)
133
+ end
134
+ end
135
+ end
136
+ end
data/lib/spoom/context.rb CHANGED
@@ -3,6 +3,14 @@
3
3
 
4
4
  require "fileutils"
5
5
  require "open3"
6
+ require "time"
7
+ require "tmpdir"
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"
6
14
 
7
15
  module Spoom
8
16
  # An abstraction to a Ruby project context
@@ -12,9 +20,11 @@ module Spoom
12
20
  class Context
13
21
  extend T::Sig
14
22
 
15
- # The absolute path to the directory this context is about
16
- sig { returns(String) }
17
- attr_reader :absolute_path
23
+ include Bundle
24
+ include Exec
25
+ include FileSystem
26
+ include Git
27
+ include Sorbet
18
28
 
19
29
  class << self
20
30
  extend T::Sig
@@ -29,6 +39,10 @@ module Spoom
29
39
  end
30
40
  end
31
41
 
42
+ # The absolute path to the directory this context is about
43
+ sig { returns(String) }
44
+ attr_reader :absolute_path
45
+
32
46
  # Create a new context about `absolute_path`
33
47
  #
34
48
  # The directory will not be created if it doesn't exist.
@@ -37,195 +51,5 @@ module Spoom
37
51
  def initialize(absolute_path)
38
52
  @absolute_path = T.let(::File.expand_path(absolute_path), String)
39
53
  end
40
-
41
- # Returns the absolute path to `relative_path` in the context's directory
42
- sig { params(relative_path: String).returns(String) }
43
- def absolute_path_to(relative_path)
44
- File.join(@absolute_path, relative_path)
45
- end
46
-
47
- # File System
48
-
49
- # Does the context directory at `absolute_path` exist and is a directory?
50
- sig { returns(T::Boolean) }
51
- def exist?
52
- File.directory?(@absolute_path)
53
- end
54
-
55
- # Create the context directory at `absolute_path`
56
- sig { void }
57
- def mkdir!
58
- FileUtils.rm_rf(@absolute_path)
59
- FileUtils.mkdir_p(@absolute_path)
60
- end
61
-
62
- # List all files in this context matching `pattern`
63
- sig { params(pattern: String).returns(T::Array[String]) }
64
- def glob(pattern = "**/*")
65
- Dir.glob(absolute_path_to(pattern)).map do |path|
66
- Pathname.new(path).relative_path_from(@absolute_path).to_s
67
- end.sort
68
- end
69
-
70
- # List all files at the top level of this context directory
71
- sig { returns(T::Array[String]) }
72
- def list
73
- glob("*")
74
- end
75
-
76
- # Does `relative_path` point to an existing file in this context directory?
77
- sig { params(relative_path: String).returns(T::Boolean) }
78
- def file?(relative_path)
79
- File.file?(absolute_path_to(relative_path))
80
- end
81
-
82
- # Return the contents of the file at `relative_path` in this context directory
83
- #
84
- # Will raise if the file doesn't exist.
85
- sig { params(relative_path: String).returns(String) }
86
- def read(relative_path)
87
- File.read(absolute_path_to(relative_path))
88
- end
89
-
90
- # Write `contents` in the file at `relative_path` in this context directory
91
- #
92
- # Append to the file if `append` is true.
93
- sig { params(relative_path: String, contents: String, append: T::Boolean).void }
94
- def write!(relative_path, contents = "", append: false)
95
- absolute_path = absolute_path_to(relative_path)
96
- FileUtils.mkdir_p(File.dirname(absolute_path))
97
- File.write(absolute_path, contents, mode: append ? "a" : "w")
98
- end
99
-
100
- # Remove the path at `relative_path` (recursive + force) in this context directory
101
- sig { params(relative_path: String).void }
102
- def remove!(relative_path)
103
- FileUtils.rm_rf(absolute_path_to(relative_path))
104
- end
105
-
106
- # Move the file or directory from `from_relative_path` to `to_relative_path`
107
- sig { params(from_relative_path: String, to_relative_path: String).void }
108
- def move!(from_relative_path, to_relative_path)
109
- destination_path = absolute_path_to(to_relative_path)
110
- FileUtils.mkdir_p(File.dirname(destination_path))
111
- FileUtils.mv(absolute_path_to(from_relative_path), destination_path)
112
- end
113
-
114
- # Delete this context and its content
115
- #
116
- # Warning: it will `rm -rf` the context directory on the file system.
117
- sig { void }
118
- def destroy!
119
- FileUtils.rm_rf(@absolute_path)
120
- end
121
-
122
- # Execution
123
-
124
- # Run a command in this context directory
125
- sig { params(command: String, capture_err: T::Boolean).returns(ExecResult) }
126
- def exec(command, capture_err: true)
127
- Bundler.with_unbundled_env do
128
- opts = T.let({ chdir: @absolute_path }, T::Hash[Symbol, T.untyped])
129
-
130
- if capture_err
131
- out, err, status = Open3.capture3(command, opts)
132
- ExecResult.new(out: out, err: err, status: T.must(status.success?), exit_code: T.must(status.exitstatus))
133
- else
134
- out, status = Open3.capture2(command, opts)
135
- ExecResult.new(out: out, err: "", status: T.must(status.success?), exit_code: T.must(status.exitstatus))
136
- end
137
- end
138
- end
139
-
140
- # Bundle
141
-
142
- # Read the `contents` of the Gemfile in this context directory
143
- sig { returns(T.nilable(String)) }
144
- def read_gemfile
145
- read("Gemfile")
146
- end
147
-
148
- # Set the `contents` of the Gemfile in this context directory
149
- sig { params(contents: String, append: T::Boolean).void }
150
- def write_gemfile!(contents, append: false)
151
- write!("Gemfile", contents, append: append)
152
- end
153
-
154
- # Run a command with `bundle` in this context directory
155
- sig { params(command: String, version: T.nilable(String)).returns(ExecResult) }
156
- def bundle(command, version: nil)
157
- command = "_#{version}_ #{command}" if version
158
- exec("bundle #{command}")
159
- end
160
-
161
- # Run `bundle install` in this context directory
162
- sig { params(version: T.nilable(String)).returns(ExecResult) }
163
- def bundle_install!(version: nil)
164
- bundle("install", version: version)
165
- end
166
-
167
- # Run a command `bundle exec` in this context directory
168
- sig { params(command: String, version: T.nilable(String)).returns(ExecResult) }
169
- def bundle_exec(command, version: nil)
170
- bundle("exec #{command}", version: version)
171
- end
172
-
173
- # Git
174
-
175
- # Run a command prefixed by `git` in this context directory
176
- sig { params(command: String).returns(ExecResult) }
177
- def git(command)
178
- exec("git #{command}")
179
- end
180
-
181
- # Run `git init` in this context directory
182
- sig { params(branch: String).void }
183
- def git_init!(branch: "main")
184
- git("init -q -b #{branch}")
185
- end
186
-
187
- # Run `git checkout` in this context directory
188
- sig { params(ref: String).returns(ExecResult) }
189
- def git_checkout!(ref: "main")
190
- git("checkout #{ref}")
191
- end
192
-
193
- # Get the current git branch in this context directory
194
- sig { returns(T.nilable(String)) }
195
- def git_current_branch
196
- Spoom::Git.current_branch(path: @absolute_path)
197
- end
198
-
199
- # Get the last commit in the currently checked out branch
200
- sig { params(short_sha: T::Boolean).returns(T.nilable(Git::Commit)) }
201
- def git_last_commit(short_sha: true)
202
- Spoom::Git.last_commit(path: @absolute_path, short_sha: short_sha)
203
- end
204
-
205
- # Sorbet
206
-
207
- # Run `bundle exec srb` in this context directory
208
- sig { params(command: String).returns(ExecResult) }
209
- def srb(command)
210
- bundle_exec("srb #{command}")
211
- end
212
-
213
- # Read the contents of `sorbet/config` in this context directory
214
- sig { returns(String) }
215
- def read_sorbet_config
216
- read(Spoom::Sorbet::CONFIG_PATH)
217
- end
218
-
219
- # Set the `contents` of `sorbet/config` in this context directory
220
- sig { params(contents: String, append: T::Boolean).void }
221
- def write_sorbet_config!(contents, append: false)
222
- write!(Spoom::Sorbet::CONFIG_PATH, contents, append: append)
223
- end
224
-
225
- # Read the strictness sigil from the file at `relative_path` (returns `nil` if no sigil)
226
- sig { params(relative_path: String).returns(T.nilable(String)) }
227
- def read_file_strictness(relative_path)
228
- Spoom::Sorbet::Sigils.file_strictness(absolute_path_to(relative_path))
229
- end
230
54
  end
231
55
  end
@@ -147,7 +147,7 @@ module Spoom
147
147
  def print_map(hash, total)
148
148
  indent
149
149
  hash.each do |key, value|
150
- next unless value > 0
150
+ next if value <= 0
151
151
 
152
152
  printl("#{key}: #{value}#{percent(value, total)}")
153
153
  end
@@ -12,9 +12,9 @@ module Spoom
12
12
  class << self
13
13
  extend T::Sig
14
14
 
15
- sig { params(path: String, rbi: T::Boolean, sorbet_bin: T.nilable(String)).returns(Snapshot) }
16
- def snapshot(path: ".", rbi: true, sorbet_bin: nil)
17
- config = sorbet_config(path: path)
15
+ sig { params(context: Context, rbi: T::Boolean, sorbet_bin: T.nilable(String)).returns(Snapshot) }
16
+ def snapshot(context, rbi: true, sorbet_bin: nil)
17
+ config = context.sorbet_config
18
18
  config.allowed_extensions.push(".rb", ".rbi") if config.allowed_extensions.empty?
19
19
 
20
20
  new_config = config.copy
@@ -27,25 +27,16 @@ module Spoom
27
27
  new_config.options_string,
28
28
  ]
29
29
 
30
- metrics = Spoom::Sorbet.srb_metrics(
31
- *flags,
32
- path: path,
33
- capture_err: true,
34
- sorbet_bin: sorbet_bin,
35
- )
30
+ metrics = context.srb_metrics(*flags, sorbet_bin: sorbet_bin)
31
+
36
32
  # Collect extra information using a different configuration
37
33
  flags << "--ignore sorbet/rbi/"
38
- metrics_without_rbis = Spoom::Sorbet.srb_metrics(
39
- *flags,
40
- path: path,
41
- capture_err: true,
42
- sorbet_bin: sorbet_bin,
43
- )
34
+ metrics_without_rbis = context.srb_metrics(*flags, sorbet_bin: sorbet_bin)
44
35
 
45
36
  snapshot = Snapshot.new
46
37
  return snapshot unless metrics
47
38
 
48
- last_commit = Spoom::Git.last_commit(path: path)
39
+ last_commit = context.git_last_commit
49
40
  snapshot.commit_sha = last_commit&.sha
50
41
  snapshot.commit_timestamp = last_commit&.timestamp
51
42
 
@@ -63,8 +54,10 @@ module Spoom
63
54
 
64
55
  if metrics_without_rbis
65
56
  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
57
+ snapshot.methods_without_sig_excluding_rbis = metrics_without_rbis.fetch(
58
+ "types.input.methods.total",
59
+ 0,
60
+ ) - snapshot.methods_with_sig_excluding_rbis
68
61
  end
69
62
 
70
63
  Snapshot::STRICTNESSES.each do |strictness|
@@ -77,40 +70,34 @@ module Spoom
77
70
  end
78
71
  end
79
72
 
80
- snapshot.version_static = Spoom::Sorbet.version_from_gemfile_lock(gem: "sorbet-static", path: path)
81
- snapshot.version_runtime = Spoom::Sorbet.version_from_gemfile_lock(gem: "sorbet-runtime", path: path)
73
+ snapshot.version_static = context.gem_version_from_gemfile_lock("sorbet-static")
74
+ snapshot.version_runtime = context.gem_version_from_gemfile_lock("sorbet-runtime")
82
75
 
83
- files = Spoom::Sorbet.srb_files(new_config, path: path)
76
+ files = context.srb_files(with_config: new_config)
84
77
  snapshot.rbi_files = files.count { |file| file.end_with?(".rbi") }
85
78
 
86
79
  snapshot
87
80
  end
88
81
 
89
- sig { params(snapshots: T::Array[Snapshot], palette: D3::ColorPalette, path: String).returns(Report) }
90
- def report(snapshots, palette:, path: ".")
91
- intro_commit = Git.sorbet_intro_commit(path: path)
82
+ sig { params(context: Context, snapshots: T::Array[Snapshot], palette: D3::ColorPalette).returns(Report) }
83
+ def report(context, snapshots, palette:)
84
+ intro_commit = context.sorbet_intro_commit
92
85
 
93
86
  Report.new(
94
- project_name: File.basename(File.expand_path(path)),
87
+ project_name: File.basename(context.absolute_path),
95
88
  palette: palette,
96
89
  snapshots: snapshots,
97
- sigils_tree: sigils_tree(path: path),
90
+ sigils_tree: sigils_tree(context),
98
91
  sorbet_intro_commit: intro_commit&.sha,
99
92
  sorbet_intro_date: intro_commit&.time,
100
93
  )
101
94
  end
102
95
 
103
- sig { params(path: String).returns(Sorbet::Config) }
104
- def sorbet_config(path: ".")
105
- Sorbet::Config.parse_file("#{path}/#{Spoom::Sorbet::CONFIG_PATH}")
106
- end
107
-
108
- sig { params(path: String).returns(FileTree) }
109
- def sigils_tree(path: ".")
110
- config = sorbet_config(path: path)
111
- files = Sorbet.srb_files(config, path: path)
96
+ sig { params(context: Context).returns(FileTree) }
97
+ def sigils_tree(context)
98
+ files = context.srb_files
112
99
 
113
- extensions = config.allowed_extensions
100
+ extensions = context.sorbet_config.allowed_extensions
114
101
  extensions = [".rb"] if extensions.empty?
115
102
  extensions -= [".rbi"]
116
103
 
@@ -118,7 +105,7 @@ module Spoom
118
105
  files.select! { |file| file =~ pattern }
119
106
  files.reject! { |file| file =~ %r{/test/} }
120
107
 
121
- FileTree.new(files, strip_prefix: path)
108
+ FileTree.new(files, strip_prefix: context.absolute_path)
122
109
  end
123
110
  end
124
111
  end
@@ -18,13 +18,16 @@ module Spoom
18
18
  class Parser
19
19
  extend T::Sig
20
20
 
21
- HEADER = T.let([
22
- "👋 Hey there! Heads up that this is not a release build of sorbet.",
23
- "Release builds are faster and more well-supported by the Sorbet team.",
24
- "Check out the README to learn how to build Sorbet in release mode.",
25
- "To forcibly silence this error, either pass --silence-dev-message,",
26
- "or set SORBET_SILENCE_DEV_MESSAGE=1 in your shell environment.",
27
- ], T::Array[String])
21
+ HEADER = T.let(
22
+ [
23
+ "👋 Hey there! Heads up that this is not a release build of sorbet.",
24
+ "Release builds are faster and more well-supported by the Sorbet team.",
25
+ "Check out the README to learn how to build Sorbet in release mode.",
26
+ "To forcibly silence this error, either pass --silence-dev-message,",
27
+ "or set SORBET_SILENCE_DEV_MESSAGE=1 in your shell environment.",
28
+ ],
29
+ T::Array[String],
30
+ )
28
31
 
29
32
  class << self
30
33
  extend T::Sig