diff --git a/lib/rails_preflight/deprecation_analyzer.rb b/lib/rails_preflight/deprecation_analyzer.rb index f44d587..f7f7e0c 100644 --- a/lib/rails_preflight/deprecation_analyzer.rb +++ b/lib/rails_preflight/deprecation_analyzer.rb @@ -109,7 +109,9 @@ def scan_files(rules) rule.fetch('files', ['code']).include?(kind) && (rule['paths'].nil? || under.(rule['paths'])) end next if applicable.empty? - content = File.read(file) + # UTF-8 whatever the locale (LANG=C reads US-ASCII); a compiled binary under bin/ (e.g. a Rust CLI) isn't text to scan. + content = File.read(file, encoding: "UTF-8") + next unless content.valid_encoding? # Only `x.errors` counts under `needs_receiver_in:` (a bare `errors` in a helper or view is a local), and in a # file that assigns `errors` or takes it as a parameter (`skip_bare_if_local:`), where the bare name is that local. # ponytail: file-wide, so a model with an `errors` local in one method loses bare hits in the others. diff --git a/test/deprecation_analyzer_test.rb b/test/deprecation_analyzer_test.rb index bc22de6..1e7c074 100644 --- a/test/deprecation_analyzer_test.rb +++ b/test/deprecation_analyzer_test.rb @@ -153,6 +153,22 @@ def test_scans_migrations_and_rake_tasks check[:files].map { |d| d[:file] }.sort end + def test_skips_binary_files + FileUtils.mkdir_p(File.join(@tmp_dir, "bin")) + File.binwrite(File.join(@tmp_dir, "bin", "cli"), "\xCF\xFA\xED\xFE\x00rake db:structure:dump\n".b) + write_app_file("bin/setup", "rake db:structure:dump # café") + + # LANG=C, common in Docker and CI: text is still read as UTF-8, so bin/setup is scanned. + verbose, $VERBOSE = $VERBOSE, nil + external, Encoding.default_external = Encoding.default_external, Encoding::US_ASCII + files = RailsPreflight::DeprecationAnalyzer.new(@tmp_dir).run[:checks].flat_map { |c| (c[:files] || []).map { |d| d[:file] } } + + assert_equal ["bin/setup"], files + ensure + Encoding.default_external = external if external + $VERBOSE = verbose + end + def test_scans_packwerk_packs_like_the_app_root write_app_file("packs/billing/app/models/invoice.rb", " deprecated_method") write_app_file("packs/billing/spec/models/invoice_spec.rb", " deprecated_method")