diff --git a/lib/packwerk/file_processor.rb b/lib/packwerk/file_processor.rb index 0fa28ffe8..6c3a4c1ac 100644 --- a/lib/packwerk/file_processor.rb +++ b/lib/packwerk/file_processor.rb @@ -53,6 +53,17 @@ def call(relative_file) ProcessedFile.new(unresolved_references: unresolved_references) rescue Parsers::ParseError => e ProcessedFile.new(offenses: [e.result]) + rescue StandardError => e + message = <<~MSG + Packwerk encountered an internal error. + For now, you can add this file to `packwerk.yml` `exclude` list. + Please file an issue and include this error message and stacktrace: + + #{e.message} #{e.backtrace}" + MSG + + offense = Parsers::ParseResult.new(file: relative_file, message: message) + ProcessedFile.new(offenses: [offense]) end private diff --git a/test/integration/packwerk/custom_executable_integration_test.rb b/test/integration/packwerk/custom_executable_integration_test.rb index a87500beb..2289a46fd 100644 --- a/test/integration/packwerk/custom_executable_integration_test.rb +++ b/test/integration/packwerk/custom_executable_integration_test.rb @@ -128,6 +128,29 @@ class CustomExecutableIntegrationTest < Minitest::Test end end + test "'packwerk check' does not blow up when parsing files with syntax issues from a false positive association" do + open_app_file(TIMELINE_PATH.join("app", "models", "bad_file.rb")) do |file| + # This is an example of a file that has an object called `belongs_to` that accepts methods + content = <<~CONTENT + belongs_to.some_method + CONTENT + + file.write(content) + file.flush + + refute_successful_run("check") + + assert_match(/Packwerk is inspecting 13 files/, captured_output) + assert_match(%r{components/timeline/app/models/bad_file.rb}, captured_output) + assert_match(/Packwerk encountered an internal error/, captured_output) + assert_match(/For now, you can add this file to `packwerk.yml` `exclude` list./, captured_output) + assert_match(/Please file an issue and include this error message and stacktrace:/, captured_output) + assert_match(/Passed `nil` into T.must/, captured_output) + assert_match(/1 offense detected/, captured_output) + assert_match(/No stale violations detected/, captured_output) + end + end + private def assert_successful_run(command) diff --git a/test/unit/packwerk/file_processor_test.rb b/test/unit/packwerk/file_processor_test.rb index 931a0bb7d..4b3b49821 100644 --- a/test/unit/packwerk/file_processor_test.rb +++ b/test/unit/packwerk/file_processor_test.rb @@ -109,9 +109,14 @@ class FileProcessorTest < Minitest::Test ) ) - tempfile(name: "foo", content: "def error") do |file_path| + processed_file = tempfile(name: "foo", content: "def error") do |file_path| file_processor.call(file_path) end + + assert_equal 0, processed_file.unresolved_references.count + offenses = processed_file.offenses + assert_equal 1, offenses.length + assert_equal "Syntax error: unexpected token $end", offenses.first.message end test "#call with a path that can't be parsed outputs error message" do