Skip to content

Commit 0aa9400

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 0aa9400

5 files changed

Lines changed: 384 additions & 12 deletions

File tree

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: 49 additions & 9 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
module Commands
68
# @abstract
@@ -26,7 +28,8 @@ class AbstractDsl < CommandWithoutTracker
2628
#| ?app_root: String,
2729
#| ?halt_upon_load_error: bool,
2830
#| ?compiler_options: Hash[String, untyped],
29-
#| ?lsp_addon: bool
31+
#| ?lsp_addon: bool,
32+
#| ?max_diff_lines: Integer
3033
#| ) -> void
3134
def initialize(
3235
requested_constants:,
@@ -46,7 +49,8 @@ def initialize(
4649
app_root: ".",
4750
halt_upon_load_error: true,
4851
compiler_options: {},
49-
lsp_addon: false
52+
lsp_addon: false,
53+
max_diff_lines: DEFAULT_MAX_DIFF_LINES
5054
)
5155
@requested_constants = requested_constants
5256
@requested_paths = requested_paths
@@ -66,6 +70,7 @@ def initialize(
6670
@skip_constant = skip_constant
6771
@compiler_options = compiler_options
6872
@lsp_addon = lsp_addon
73+
@max_diff_lines = max_diff_lines
6974

7075
super()
7176
end
@@ -240,9 +245,9 @@ def compile_dsl_rbi(constant_name, rbi, outpath: @outpath, quiet: false)
240245

241246
#: (Pathname dir) -> void
242247
def perform_dsl_verification(dir)
243-
diff = verify_dsl_rbi(tmp_dir: dir)
248+
diff, diff_output = verify_dsl_rbi(tmp_dir: dir)
244249

245-
report_diff_and_exit_if_out_of_date(diff, :dsl)
250+
report_diff_and_exit_if_out_of_date(diff, diff_output, :dsl)
246251
ensure
247252
FileUtils.remove_entry(dir)
248253
end
@@ -264,9 +269,10 @@ def dsl_rbi_filename(constant_name)
264269
@outpath / "#{underscore(constant_name)}.rbi"
265270
end
266271

267-
#: (tmp_dir: Pathname) -> Hash[String, Symbol]
272+
#: (tmp_dir: Pathname) -> [Hash[String, Symbol], String]
268273
def verify_dsl_rbi(tmp_dir:)
269274
diff = {}
275+
diff_output = String.new
270276

271277
existing_rbis = rbi_files_in(@outpath)
272278
new_rbis = rbi_files_in(tmp_dir)
@@ -275,12 +281,14 @@ def verify_dsl_rbi(tmp_dir:)
275281

276282
added_files.each do |file|
277283
diff[file] = :added
284+
diff_output << file_diff(file, File::NULL, tmp_dir / file)
278285
end
279286

280287
removed_files = (existing_rbis - new_rbis)
281288

282289
removed_files.each do |file|
283290
diff[file] = :removed
291+
diff_output << file_diff(file, @outpath / file, File::NULL)
284292
end
285293

286294
common_files = (existing_rbis & new_rbis)
@@ -291,9 +299,30 @@ def verify_dsl_rbi(tmp_dir:)
291299

292300
changed_files.each do |file|
293301
diff[file] = :changed
302+
diff_output << file_diff(file, @outpath / file, tmp_dir / file)
294303
end
295304

296-
diff
305+
[diff, diff_output]
306+
end
307+
308+
#: (Pathname filename, String | Pathname old_path, String | Pathname new_path) -> String
309+
def file_diff(filename, old_path, new_path)
310+
stdout, stderr, status = Open3.capture3(
311+
"diff",
312+
"-u",
313+
"--label",
314+
filename.to_s,
315+
"--label",
316+
filename.to_s,
317+
old_path.to_s,
318+
new_path.to_s,
319+
)
320+
raise stderr.chomp unless [0, 1].include?(status.exitstatus)
321+
322+
stdout
323+
rescue => e
324+
say_error("Failed to create #{filename} diff. #{e.message}", :red)
325+
""
297326
end
298327

299328
#: (Symbol cause, Array[String] files) -> String
@@ -305,16 +334,25 @@ def build_error_for_files(cause, files)
305334
" File(s) #{cause}:\n - #{filenames}"
306335
end
307336

308-
#: (Hash[String, Symbol] diff, Symbol command) -> void
309-
def report_diff_and_exit_if_out_of_date(diff, command)
337+
#: (Hash[String, Symbol] diff, String diff_output, Symbol command) -> void
338+
def report_diff_and_exit_if_out_of_date(diff, diff_output, command)
310339
if diff.empty?
311340
say("Nothing to do, all RBIs are up-to-date.")
312341
else
313342
reasons = diff.group_by(&:last).sort.map do |cause, diff_for_cause|
314343
build_error_for_files(cause, diff_for_cause.map(&:first))
315344
end.join("\n")
316345

317-
raise Tapioca::Error, <<~ERROR
346+
diff_lines = diff_output.lines.count
347+
file_diff = if diff_lines.between?(1, @max_diff_lines)
348+
"#{set_color("Diff:", :red)}\n#{diff_output.chomp}"
349+
elsif diff_lines > @max_diff_lines
350+
set_color("Diff not displayed as it exceeds #{@max_diff_lines} lines", :red)
351+
else
352+
""
353+
end
354+
355+
raise Tapioca::Error, <<~ERROR.rstrip
318356
#{set_color("RBI files are out-of-date. In your development environment, please run:", :green)}
319357
#{set_color("`#{default_command(command)}`", :green, :bold)}
320358
#{set_color("Once it is complete, be sure to commit and push any changes", :green)}
@@ -323,6 +361,8 @@ def report_diff_and_exit_if_out_of_date(diff, command)
323361
324362
#{set_color("Reason:", :red)}
325363
#{reasons}
364+
365+
#{file_diff}
326366
ERROR
327367
end
328368
end

0 commit comments

Comments
 (0)