From 6c1fe395ad9d36658e09e67b7ceff32998ae64de Mon Sep 17 00:00:00 2001 From: Vinicius Stock Date: Fri, 14 Jun 2024 14:51:52 -0400 Subject: [PATCH] Make Rails engine path check more specific --- lib/tapioca/static/symbol_loader.rb | 2 +- spec/tapioca/cli/gem_spec.rb | 57 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/lib/tapioca/static/symbol_loader.rb b/lib/tapioca/static/symbol_loader.rb index ff41f610a..f8599b2b1 100644 --- a/lib/tapioca/static/symbol_loader.rb +++ b/lib/tapioca/static/symbol_loader.rb @@ -22,7 +22,7 @@ def payload_symbols sig { params(gem: Gemfile::GemSpec).returns(T::Set[String]) } def engine_symbols(gem) gem_engine = engines.find do |engine| - gem.contains_path?(engine.config.root.to_s) + gem.full_gem_path == engine.config.root.to_s end return Set.new unless gem_engine diff --git a/spec/tapioca/cli/gem_spec.rb b/spec/tapioca/cli/gem_spec.rb index ce0fbc58f..78049afd9 100644 --- a/spec/tapioca/cli/gem_spec.rb +++ b/spec/tapioca/cli/gem_spec.rb @@ -1505,6 +1505,63 @@ class Application < Rails::Application assert_empty_stderr(result) assert_success_status(result) end + + it "properly filters eager loaded Rails engines when gem is installed from git source" do + # When Rails is installed through a release version, each gem contained inside `rails` is placed in a + # different sibling directory. However, when Rails is installed through a git source, all gems are placed + # nested under the Rails directory. When we check if an engine belongs to a gem, we need to take that into + # account to avoid placing symbols that do not belong to the Rails RBI inside of it + # + # Example of path for git installed Rails: + # /Users/me/.gem/ruby/3.3.0/bundler/gems/rails-e3ea4c74124f/ + # /Users/me/.gem/ruby/3.3.0/bundler/gems/rails-e3ea4c74124f/activestorage + # /Users/me/.gem/ruby/3.3.0/bundler/gems/rails-e3ea4c74124f/actionmailbox + # + # The engines defined by `activestorage` and `actionmailbox` should not be placed in the Rails RBI. They + # belong in their own respective RBIs. + # + # Note that this problem only happens if another gem somehow eager loads the engines. By default, Rails + # would've not loaded those classes and they would have not been placed in the Rails RBI. + + @project.write_gemfile!(<<~GEMFILE, append: true) + gem("rails", git: "https://github.com/rails/rails", branch: "main") + GEMFILE + + # Create a gem that eager loads the ActionMailbox engine + gem = mock_gem("eager_loader", "1.0.0") do + write!("lib/eager_loader.rb", <<~RUBY) + require "action_mailbox/engine" + + module EagerLoader + end + RUBY + end + @project.require_mock_gem(gem) + + install_result = @project.bundle_install! + assert_predicate(install_result, :status, "Bundle install failed\n\n#{install_result.err}") + + result = @project.tapioca("gem rails") + assert_empty_stderr(result) + assert_success_status(result) + + assert_stdout_includes(result, "Compiled rails") + rails_rbi = T.must(Dir.glob("#{@project.absolute_path}/sorbet/rbi/gems/rails@*.rbi").first) + + expected_rbi = <<~RBI + # typed: true + + # DO NOT EDIT MANUALLY + # This is an autogenerated file for types exported from the `rails` gem. + # Please instead update this file by running `bin/tapioca gem rails`. + + + # THIS IS AN EMPTY RBI FILE. + # see https://github.com/Shopify/tapioca#manually-requiring-parts-of-a-gem + RBI + + assert_equal(expected_rbi, File.read(rails_rbi)) + end end describe "verify" do