From ff4e98670c13bba4ff73b5f4e4cc86f2f8e5057b Mon Sep 17 00:00:00 2001 From: fresh Date: Wed, 5 Aug 2026 12:21:57 -0300 Subject: [PATCH 1/3] Show skipped gem RBI generation --- lib/tapioca/commands/abstract_gem.rb | 1 + lib/tapioca/commands/gem_generate.rb | 29 ++++++++++--- spec/tapioca/cli/gem_spec.rb | 61 ++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 6 deletions(-) diff --git a/lib/tapioca/commands/abstract_gem.rb b/lib/tapioca/commands/abstract_gem.rb index 83c52e355..baabaa1af 100644 --- a/lib/tapioca/commands/abstract_gem.rb +++ b/lib/tapioca/commands/abstract_gem.rb @@ -71,6 +71,7 @@ def initialize( @include_doc = include_doc #: bool @include_loc = include_loc #: bool @include_exported_rbis = include_exported_rbis + @skipped_gems = [] #: Array[String] @halt_upon_load_error = halt_upon_load_error end diff --git a/lib/tapioca/commands/gem_generate.rb b/lib/tapioca/commands/gem_generate.rb index 6362655e5..cbd33c225 100644 --- a/lib/tapioca/commands/gem_generate.rb +++ b/lib/tapioca/commands/gem_generate.rb @@ -17,7 +17,8 @@ def execute halt_upon_load_error: @halt_upon_load_error, ) - gem_queue = gems_to_generate(@gem_names).reject { |gem| @exclude.include?(gem.name) } + gem_queue = gems_to_generate(@gem_names) + gem_queue.reject! { |gem| @exclude.include?(gem.name) } anything_done = [ perform_removals, gem_queue.any?, @@ -30,6 +31,18 @@ def execute end end + unless @skipped_gems.empty? + say("\nNote: Tapioca skipped RBI generation for the following gems because they are ignored by default:", [:yellow, :bold]) + say(@skipped_gems.join(", "), [:yellow, :bold]) + end + + user_excluded_gems = @gem_names & @exclude + + unless user_excluded_gems.empty? + say("\nNote: Tapioca skipped RBI generation for the following gems because they were excluded:", [:yellow, :bold]) + say(user_excluded_gems.join(", "), [:yellow, :bold]) + end + if anything_done validate_rbi_files( command: default_command(:gem, @gem_names.join(" ")), @@ -52,15 +65,19 @@ def execute def gems_to_generate(gem_names) return @bundle.dependencies if gem_names.empty? - (gem_names - @exclude).each_with_object([]) do |gem_name, gems| + gem_names.each_with_object([]) do |gem_name, gems| gem = @bundle.gem(gem_name) if gem.nil? - next if @lsp_addon - - raise Tapioca::Error, set_color("Error: Cannot find gem '#{gem_name}'", :red) + if @lsp_addon + next + elsif Gemfile::GemSpec::IGNORED_GEMS.include?(gem_name) + @skipped_gems << gem_name + next + else + raise Tapioca::Error, set_color("Error: Cannot find gem '#{gem_name}'", :red) + end end - gems.concat(gem_dependencies(gem)) if @include_dependencies gems << gem end diff --git a/spec/tapioca/cli/gem_spec.rb b/spec/tapioca/cli/gem_spec.rb index 61484ad51..9d8eebbef 100644 --- a/spec/tapioca/cli/gem_spec.rb +++ b/spec/tapioca/cli/gem_spec.rb @@ -877,6 +877,67 @@ class Secret; end assert_success_status(result) end + it "reports explicitly requested ignored gems" do + result = @project.tapioca("gem sorbet", exclude: []) + + assert_stdout_includes(result, <<~OUT) + Note: Tapioca skipped RBI generation for the following gems because they are ignored by default: + sorbet + OUT + refute_includes(result.out, "Compiled sorbet") + + assert_empty_stderr(result) + assert_success_status(result) + end + + it "reports gems excluded by built-in and user configuration" do + result = @project.tapioca("gem sorbet rbi --exclude rbi") + + assert_stdout_includes(result, <<~OUT) + Note: Tapioca skipped RBI generation for the following gems because they are ignored by default: + sorbet + OUT + assert_stdout_includes(result, <<~OUT) + Note: Tapioca skipped RBI generation for the following gems because they were excluded: + rbi + OUT + refute_includes(result.out, "Compiled rbi") + + assert_empty_stderr(result) + assert_success_status(result) + end + + it "reports gems excluded by user configuration" do + result = @project.tapioca("gem rbi --exclude rbi") + + assert_stdout_includes(result, <<~OUT) + Note: Tapioca skipped RBI generation for the following gems because they were excluded: + rbi + OUT + refute_includes(result.out, "Compiled rbi") + + assert_empty_stderr(result) + assert_success_status(result) + end + + it "does not report exclusions when no gems are explicitly requested" do + result = @project.tapioca("gem --exclude rbi") + + refute_includes(result.out, "because they were excluded") + + assert_empty_stderr(result) + assert_success_status(result) + end + + it "does not report exclusions when all gems are requested" do + result = @project.tapioca("gem --all --exclude rbi") + + refute_includes(result.out, "because they were excluded") + + assert_empty_stderr(result) + assert_success_status(result) + end + it "fails with error when gem cannot be found" do result = @project.tapioca("gem non_existent_gem") From 84d12d254512d95c0f69fc77490db80c9698de2c Mon Sep 17 00:00:00 2001 From: Kaan Ozkan Date: Fri, 28 Aug 2026 17:02:02 +0300 Subject: [PATCH 2/3] Skip excluded gems before dependency expansion Skip explicitly excluded gems before resolving the requested gem list. This preserves `main` behavior and prevents `--include-dependencies` from generating dependencies of an excluded gem. --- lib/tapioca/commands/gem_generate.rb | 2 +- spec/tapioca/cli/gem_spec.rb | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/tapioca/commands/gem_generate.rb b/lib/tapioca/commands/gem_generate.rb index cbd33c225..ab927d4f0 100644 --- a/lib/tapioca/commands/gem_generate.rb +++ b/lib/tapioca/commands/gem_generate.rb @@ -65,7 +65,7 @@ def execute def gems_to_generate(gem_names) return @bundle.dependencies if gem_names.empty? - gem_names.each_with_object([]) do |gem_name, gems| + (gem_names - @exclude).each_with_object([]) do |gem_name, gems| gem = @bundle.gem(gem_name) if gem.nil? diff --git a/spec/tapioca/cli/gem_spec.rb b/spec/tapioca/cli/gem_spec.rb index 9d8eebbef..261207ac8 100644 --- a/spec/tapioca/cli/gem_spec.rb +++ b/spec/tapioca/cli/gem_spec.rb @@ -920,6 +920,26 @@ class Secret; end assert_success_status(result) end + it "does not generate dependencies of explicitly excluded gems" do + @project.require_mock_gem(mock_gem("foo", "0.0.1", dependencies: ["bar"])) + @project.require_mock_gem(mock_gem("bar", "0.0.1")) + # Keep foo materialized after Bundler excludes it as a direct dependency. + @project.require_mock_gem(mock_gem("baz", "0.0.1", dependencies: ["foo"])) + @project.bundle_install! + + result = @project.tapioca("gem foo --include-dependencies --exclude foo") + + assert_stdout_includes(result, <<~OUT) + Note: Tapioca skipped RBI generation for the following gems because they were excluded: + foo + OUT + refute_includes(result.out, "Compiled foo") + refute_includes(result.out, "Compiled bar") + + assert_empty_stderr(result) + assert_success_status(result) + end + it "does not report exclusions when no gems are explicitly requested" do result = @project.tapioca("gem --exclude rbi") From 85b6cca2ab639a849704436f2aaa783f551f0e06 Mon Sep 17 00:00:00 2001 From: Kaan Ozkan Date: Fri, 28 Aug 2026 17:12:28 +0300 Subject: [PATCH 3/3] style --- lib/tapioca/commands/gem_generate.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/tapioca/commands/gem_generate.rb b/lib/tapioca/commands/gem_generate.rb index ab927d4f0..302e1f0fe 100644 --- a/lib/tapioca/commands/gem_generate.rb +++ b/lib/tapioca/commands/gem_generate.rb @@ -17,8 +17,7 @@ def execute halt_upon_load_error: @halt_upon_load_error, ) - gem_queue = gems_to_generate(@gem_names) - gem_queue.reject! { |gem| @exclude.include?(gem.name) } + gem_queue = gems_to_generate(@gem_names).reject { |gem| @exclude.include?(gem.name) } anything_done = [ perform_removals, gem_queue.any?,