diff --git a/bundler/lib/dependabot/bundler/file_parser.rb b/bundler/lib/dependabot/bundler/file_parser.rb index aa82aae43f1..95656625798 100644 --- a/bundler/lib/dependabot/bundler/file_parser.rb +++ b/bundler/lib/dependabot/bundler/file_parser.rb @@ -60,17 +60,17 @@ def gemfile_dependencies return dependencies unless gemfile [gemfile, *evaled_gemfiles].each do |file| + gemfile_declaration_finder = GemfileDeclarationFinder.new(gemfile: file) + parsed_gemfile.each do |dep| - gemfile_declaration_finder = - GemfileDeclarationFinder.new(dependency: dep, gemfile: file) - next unless gemfile_declaration_finder.gemfile_includes_dependency? + next unless gemfile_declaration_finder.gemfile_includes_dependency?(dep) dependencies << Dependency.new( name: dep.fetch("name"), version: dependency_version(dep.fetch("name"))&.to_s, requirements: [{ - requirement: gemfile_declaration_finder.enhanced_req_string, + requirement: gemfile_declaration_finder.enhanced_req_string(dep), groups: dep.fetch("groups").map(&:to_sym), source: dep.fetch("source")&.transform_keys(&:to_sym), file: file.name diff --git a/bundler/lib/dependabot/bundler/file_parser/gemfile_declaration_finder.rb b/bundler/lib/dependabot/bundler/file_parser/gemfile_declaration_finder.rb index c480c0aba64..ebed8281f82 100644 --- a/bundler/lib/dependabot/bundler/file_parser/gemfile_declaration_finder.rb +++ b/bundler/lib/dependabot/bundler/file_parser/gemfile_declaration_finder.rb @@ -8,20 +8,20 @@ module Bundler class FileParser # Checks whether a dependency is declared in a Gemfile class GemfileDeclarationFinder - def initialize(dependency:, gemfile:) - @dependency = dependency + def initialize(gemfile:) @gemfile = gemfile + @declaration_nodes = {} end - def gemfile_includes_dependency? - !declaration_node.nil? + def gemfile_includes_dependency?(dependency) + !declaration_node(dependency).nil? end - def enhanced_req_string - return unless gemfile_includes_dependency? + def enhanced_req_string(dependency) + return unless gemfile_includes_dependency?(dependency) fallback_string = dependency.fetch("requirement") - req_nodes = declaration_node.children[3..-1] + req_nodes = declaration_node(dependency).children[3..-1] req_nodes = req_nodes.reject { |child| child.type == :hash } return fallback_string if req_nodes.none? @@ -39,31 +39,35 @@ def enhanced_req_string private - attr_reader :dependency, :gemfile + attr_reader :gemfile - def declaration_node - return @declaration_node if defined?(@declaration_node) - return unless Parser::CurrentRuby.parse(gemfile.content) + def parsed_gemfile + @parsed_gemfile ||= Parser::CurrentRuby.parse(gemfile.content) + end + + def declaration_node(dependency) + return @declaration_nodes[dependency] if @declaration_nodes.key?(dependency) + return unless parsed_gemfile - @declaration_node = nil - Parser::CurrentRuby.parse(gemfile.content).children.any? do |node| - @declaration_node = deep_search_for_gem(node) + @declaration_nodes[dependency] = nil + parsed_gemfile.children.any? do |node| + @declaration_nodes[dependency] = deep_search_for_gem(node, dependency) end - @declaration_node + @declaration_nodes[dependency] end - def deep_search_for_gem(node) - return node if declares_targeted_gem?(node) + def deep_search_for_gem(node, dependency) + return node if declares_targeted_gem?(node, dependency) return unless node.is_a?(Parser::AST::Node) declaration_node = nil node.children.find do |child_node| - declaration_node = deep_search_for_gem(child_node) + declaration_node = deep_search_for_gem(child_node, dependency) end declaration_node end - def declares_targeted_gem?(node) + def declares_targeted_gem?(node, dependency) return false unless node.is_a?(Parser::AST::Node) return false unless node.children[1] == :gem diff --git a/bundler/spec/dependabot/bundler/file_parser/gemfile_declaration_finder_spec.rb b/bundler/spec/dependabot/bundler/file_parser/gemfile_declaration_finder_spec.rb index 4b3b22aff34..cb94bf6b0b8 100644 --- a/bundler/spec/dependabot/bundler/file_parser/gemfile_declaration_finder_spec.rb +++ b/bundler/spec/dependabot/bundler/file_parser/gemfile_declaration_finder_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Dependabot::Bundler::FileParser::GemfileDeclarationFinder do let(:checker) do - described_class.new(dependency: dependency, gemfile: gemfile) + described_class.new(gemfile: gemfile) end let(:dependency) do @@ -25,7 +25,7 @@ describe "#gemfile_includes_dependency?" do subject(:gemfile_includes_dependency) do - checker.gemfile_includes_dependency? + checker.gemfile_includes_dependency?(dependency) end context "when the file does not include the dependency" do @@ -61,7 +61,7 @@ end describe "#enhanced_req_string" do - subject(:enhanced_req_string) { checker.enhanced_req_string } + subject(:enhanced_req_string) { checker.enhanced_req_string(dependency) } context "when the file does not include the dependency" do let(:dependency_name) { "dependabot-core" }