Skip to content

Commit 6bdba8a

Browse files
committed
Display line diffs in dsl --verify error messages
When `dsl --verify` detects out of date RBI files, the error message lists which files were added, removed, or changed. We could make it easier to understand what has changed by including the line diff output in the error message as well This commit grabs the line diff output during RBI verification and includes it in the error message when the diff is 250 lines or less
1 parent 5e3ad72 commit 6bdba8a

7 files changed

Lines changed: 385 additions & 12 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,8 @@ Options:
502502
-w, [--workers=N] # Number of parallel workers to use when generating RBIs (default: auto)
503503
[--rbi-max-line-length=N] # Set the max line length of generated RBIs. Signatures longer than the max line length will be wrapped
504504
# Default: 120
505+
[--max-diff-lines=N] # Max number of diff lines to include in the `dsl --verify` output
506+
# Default: 250
505507
-e, [--environment=ENVIRONMENT] # The Rack/Rails environment to use when generating RBIs
506508
# Default: development
507509
-l, [--list-compilers], [--no-list-compilers], [--skip-list-compilers] # List all loaded compilers
@@ -960,6 +962,7 @@ dsl:
960962
quiet: false
961963
workers: 1
962964
rbi_max_line_length: 120
965+
max_diff_lines: 250
963966
environment: development
964967
list_compilers: false
965968
app_root: "."

lib/tapioca.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class Error < StandardError; end
3232

3333
DEFAULT_RBI_MAX_LINE_LENGTH = 120
3434
DEFAULT_ENVIRONMENT = "development"
35+
DEFAULT_MAX_DIFF_LINES = 250
3536

3637
CENTRAL_REPO_ROOT_URI = "https://raw.githubusercontent.com/Shopify/rbi-central/main"
3738
CENTRAL_REPO_INDEX_PATH = "index.json"

lib/tapioca/cli.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ def todo
116116
type: :numeric,
117117
desc: "Set the max line length of generated RBIs. Signatures longer than the max line length will be wrapped",
118118
default: DEFAULT_RBI_MAX_LINE_LENGTH
119+
option :max_diff_lines,
120+
type: :numeric,
121+
desc: "Max number of diff lines to include in the `dsl --verify` output",
122+
default: DEFAULT_MAX_DIFF_LINES
119123
option :environment,
120124
aliases: ["-e"],
121125
type: :string,
@@ -166,6 +170,7 @@ def dsl(*constant_or_paths)
166170
halt_upon_load_error: options[:halt_upon_load_error],
167171
compiler_options: options[:compiler_options],
168172
lsp_addon: self.class.addon_mode,
173+
max_diff_lines: options[:max_diff_lines],
169174
}
170175

171176
command = if options[:verify]

lib/tapioca/commands/abstract_dsl.rb

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ class AbstractDsl < CommandWithoutTracker
2626
#| ?app_root: String,
2727
#| ?halt_upon_load_error: bool,
2828
#| ?compiler_options: Hash[String, untyped],
29-
#| ?lsp_addon: bool
29+
#| ?lsp_addon: bool,
30+
#| ?max_diff_lines: Integer
3031
#| ) -> void
3132
def initialize(
3233
requested_constants:,
@@ -46,7 +47,8 @@ def initialize(
4647
app_root: ".",
4748
halt_upon_load_error: true,
4849
compiler_options: {},
49-
lsp_addon: false
50+
lsp_addon: false,
51+
max_diff_lines: DEFAULT_MAX_DIFF_LINES
5052
)
5153
@requested_constants = requested_constants
5254
@requested_paths = requested_paths
@@ -66,6 +68,7 @@ def initialize(
6668
@skip_constant = skip_constant
6769
@compiler_options = compiler_options
6870
@lsp_addon = lsp_addon
71+
@max_diff_lines = max_diff_lines
6972

7073
super()
7174
end
@@ -240,9 +243,9 @@ def compile_dsl_rbi(constant_name, rbi, outpath: @outpath, quiet: false)
240243

241244
#: (Pathname dir) -> void
242245
def perform_dsl_verification(dir)
243-
diff = verify_dsl_rbi(tmp_dir: dir)
246+
diff, diff_output = verify_dsl_rbi(tmp_dir: dir)
244247

245-
report_diff_and_exit_if_out_of_date(diff, :dsl)
248+
report_diff_and_exit_if_out_of_date(diff, diff_output, :dsl)
246249
ensure
247250
FileUtils.remove_entry(dir)
248251
end
@@ -264,9 +267,10 @@ def dsl_rbi_filename(constant_name)
264267
@outpath / "#{underscore(constant_name)}.rbi"
265268
end
266269

267-
#: (tmp_dir: Pathname) -> Hash[String, Symbol]
270+
#: (tmp_dir: Pathname) -> [Hash[String, Symbol], String]
268271
def verify_dsl_rbi(tmp_dir:)
269272
diff = {}
273+
diff_output = String.new
270274

271275
existing_rbis = rbi_files_in(@outpath)
272276
new_rbis = rbi_files_in(tmp_dir)
@@ -275,12 +279,14 @@ def verify_dsl_rbi(tmp_dir:)
275279

276280
added_files.each do |file|
277281
diff[file] = :added
282+
diff_output << file_diff(file, File::NULL, tmp_dir / file)
278283
end
279284

280285
removed_files = (existing_rbis - new_rbis)
281286

282287
removed_files.each do |file|
283288
diff[file] = :removed
289+
diff_output << file_diff(file, @outpath / file, File::NULL)
284290
end
285291

286292
common_files = (existing_rbis & new_rbis)
@@ -291,9 +297,10 @@ def verify_dsl_rbi(tmp_dir:)
291297

292298
changed_files.each do |file|
293299
diff[file] = :changed
300+
diff_output << file_diff(file, @outpath / file, tmp_dir / file)
294301
end
295302

296-
diff
303+
[diff, diff_output]
297304
end
298305

299306
#: (Symbol cause, Array[String] files) -> String
@@ -305,16 +312,25 @@ def build_error_for_files(cause, files)
305312
" File(s) #{cause}:\n - #{filenames}"
306313
end
307314

308-
#: (Hash[String, Symbol] diff, Symbol command) -> void
309-
def report_diff_and_exit_if_out_of_date(diff, command)
315+
#: (Hash[String, Symbol] diff, String diff_output, Symbol command) -> void
316+
def report_diff_and_exit_if_out_of_date(diff, diff_output, command)
310317
if diff.empty?
311318
say("Nothing to do, all RBIs are up-to-date.")
312319
else
313320
reasons = diff.group_by(&:last).sort.map do |cause, diff_for_cause|
314321
build_error_for_files(cause, diff_for_cause.map(&:first))
315322
end.join("\n")
316323

317-
raise Tapioca::Error, <<~ERROR
324+
diff_lines = diff_output.lines.count
325+
file_diff = if diff_lines.between?(1, @max_diff_lines)
326+
"#{set_color("Diff:", :red)}\n#{diff_output.chomp}"
327+
elsif diff_lines > @max_diff_lines
328+
set_color("Diff not displayed as it exceeds #{@max_diff_lines} lines", :red)
329+
else
330+
""
331+
end
332+
333+
raise Tapioca::Error, <<~ERROR.rstrip
318334
#{set_color("RBI files are out-of-date. In your development environment, please run:", :green)}
319335
#{set_color("`#{default_command(command)}`", :green, :bold)}
320336
#{set_color("Once it is complete, be sure to commit and push any changes", :green)}
@@ -323,6 +339,8 @@ def report_diff_and_exit_if_out_of_date(diff, command)
323339
324340
#{set_color("Reason:", :red)}
325341
#{reasons}
342+
343+
#{file_diff}
326344
ERROR
327345
end
328346
end

lib/tapioca/helpers/rbi_files_helper.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# typed: strict
22
# frozen_string_literal: true
33

4+
require "open3"
5+
46
module Tapioca
57
# @requires_ancestor: Thor::Shell
68
# @requires_ancestor: SorbetHelper
@@ -137,6 +139,26 @@ def validate_rbi_files(command:, gem_dir:, dsl_dir:, auto_strictness:, gems: [],
137139
Kernel.raise Tapioca::Error, error_messages.join("\n") if parse_errors.any?
138140
end
139141

142+
#: (Pathname filename, String | Pathname old_path, String | Pathname new_path) -> String
143+
def file_diff(filename, old_path, new_path)
144+
stdout, stderr, status = Open3.capture3(
145+
"diff",
146+
"-u",
147+
"--label",
148+
filename.to_s,
149+
"--label",
150+
filename.to_s,
151+
old_path.to_s,
152+
new_path.to_s,
153+
)
154+
Kernel.raise stderr.chomp unless [0, 1].include?(status.exitstatus)
155+
156+
stdout
157+
rescue => e
158+
say_error("Failed to create #{filename} diff. #{e.message}", :red)
159+
""
160+
end
161+
140162
private
141163

142164
#: (RBI::Index index, Array[String] files, number_of_workers: Integer?) -> void

0 commit comments

Comments
 (0)