Skip to content

Commit

Permalink
Merge branch 'main' into harry/pnpm_9_support
Browse files Browse the repository at this point in the history
  • Loading branch information
thavaahariharangit authored Jun 24, 2024
2 parents a99c524 + 486b646 commit 59948a2
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 22 deletions.
30 changes: 21 additions & 9 deletions bundler/lib/dependabot/bundler/file_fetcher/path_gemspec_finder.rb
Original file line number Diff line number Diff line change
@@ -1,47 +1,54 @@
# typed: true
# typed: strict
# frozen_string_literal: true

require "pathname"
require "parser/current"
require "dependabot/bundler/file_fetcher"
require "dependabot/errors"
require "sorbet-runtime"

module Dependabot
module Bundler
class FileFetcher
# Finds the paths of any gemspecs declared using `path: ` in the
# passed Gemfile.
class PathGemspecFinder
extend T::Sig

sig { params(gemfile: Dependabot::DependencyFile).void }
def initialize(gemfile:)
@gemfile = gemfile
end

sig { returns(T::Array[String]) }
def path_gemspec_paths
ast = Parser::CurrentRuby.parse(gemfile.content)
ast = Parser::CurrentRuby.parse(gemfile&.content)
find_path_gemspec_paths(ast)
rescue Parser::SyntaxError
raise Dependabot::DependencyFileNotParseable, gemfile.path
raise Dependabot::DependencyFileNotParseable, T.must(gemfile).path
end

private

sig { returns(T.nilable(Dependabot::DependencyFile)) }
attr_reader :gemfile

sig { params(node: T.untyped).returns(T::Array[T.untyped]) }
def find_path_gemspec_paths(node)
return [] unless node.is_a?(Parser::AST::Node)

if declares_path_dependency?(node)
path_node = path_node_for_gem_declaration(node)

unless path_node.type == :str
path = gemfile.path
unless path_node&.type == :str
path = gemfile&.path
msg = "Dependabot only supports uninterpolated string arguments " \
"for path dependencies. Got " \
"`#{path_node.loc.expression.source}`"
raise Dependabot::DependencyFileNotParseable.new(path, msg)
"`#{path_node&.loc&.expression&.source}`"
raise Dependabot::DependencyFileNotParseable.new(T.must(path), msg)
end

path = path_node.loc.expression.source.gsub(/['"]/, "")
path = T.must(path_node).loc.expression.source.gsub(/['"]/, "")
return [clean_path(path)]
end

Expand All @@ -50,19 +57,22 @@ def find_path_gemspec_paths(node)
end
end

sig { returns(T.nilable(String)) }
def current_dir
@current_dir ||= gemfile.name.rpartition("/").first
@current_dir ||= T.let(gemfile&.name&.rpartition("/")&.first, T.nilable(String))
@current_dir = nil if @current_dir == ""
@current_dir
end

sig { params(node: Parser::AST::Node).returns(T::Boolean) }
def declares_path_dependency?(node)
return false unless node.is_a?(Parser::AST::Node)
return false unless node.children[1] == :gem

!path_node_for_gem_declaration(node).nil?
end

sig { params(path: String).returns(Pathname) }
def clean_path(path)
if Pathname.new(path).absolute?
base_path = Pathname.new(File.expand_path(Dir.pwd))
Expand All @@ -72,6 +82,7 @@ def clean_path(path)
Pathname.new(path).cleanpath
end

sig { params(node: Parser::AST::Node).returns(T.nilable(Parser::AST::Node)) }
def path_node_for_gem_declaration(node)
return unless node.children.last.type == :hash

Expand All @@ -86,6 +97,7 @@ def path_node_for_gem_declaration(node)
path_hash_pair.children.last
end

sig { params(node: Parser::AST::Node).returns(Symbol) }
def key_from_hash_pair(node)
node.children.first.children.first.to_sym
end
Expand Down
35 changes: 22 additions & 13 deletions hex/lib/dependabot/hex/file_fetcher.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# typed: true
# typed: strict
# frozen_string_literal: true

require "sorbet-runtime"
Expand All @@ -13,14 +13,16 @@ class FileFetcher < Dependabot::FileFetchers::Base

APPS_PATH_REGEX = /apps_path:\s*"(?<path>.*?)"/m
STRING_ARG = %{(?:["'](.*?)["'])}
SUPPORTED_METHODS = %w(eval_file require_file).join("|").freeze
SUPPORTED_METHODS = T.let(%w(eval_file require_file).join("|").freeze, String)
SUPPORT_FILE = /Code\.(?:#{SUPPORTED_METHODS})\(#{STRING_ARG}(?:\s*,\s*#{STRING_ARG})?\)/
PATH_DEPS_REGEX = /{.*path: ?#{STRING_ARG}.*}/

sig { override.params(filenames: T::Array[String]).returns(T::Boolean) }
def self.required_files_in?(filenames)
filenames.include?("mix.exs")
end

sig { override.returns(String) }
def self.required_files_message
"Repo must contain a mix.exs."
end
Expand All @@ -37,36 +39,41 @@ def fetch_files

private

sig { returns(T.nilable(DependencyFile)) }
def mixfile
@mixfile ||= fetch_file_from_host("mix.exs")
@mixfile ||= T.let(fetch_file_from_host("mix.exs"), T.nilable(Dependabot::DependencyFile))
fetch_file_from_host("mix.exs")
end

sig { returns(T.nilable(Dependabot::DependencyFile)) }
def lockfile
return @lockfile if defined?(@lockfile)

@lockfile = fetch_lockfile
@lockfile ||= T.let(fetch_lockfile, T.nilable(DependencyFile))
end

sig { returns(T.nilable(Dependabot::DependencyFile)) }
def fetch_lockfile
fetch_file_from_host("mix.lock")
rescue Dependabot::DependencyFileNotFound
nil
end

sig { returns(T::Array[String]) }
def umbrella_app_directories
apps_path = mixfile.content.match(APPS_PATH_REGEX)
&.named_captures&.fetch("path")
apps_path = T.must(T.must(mixfile).content).match(APPS_PATH_REGEX)
&.named_captures&.fetch("path")
return [] unless apps_path

repo_contents(dir: apps_path)
.select { |f| f.type == "dir" }
.map { |f| File.join(apps_path, f.name) }
end

sig { returns(T::Array[String]) }
def sub_project_directories
mixfile.content.scan(PATH_DEPS_REGEX).flatten
T.must(T.must(mixfile).content).scan(PATH_DEPS_REGEX).flatten
end

sig { returns(T::Array[Dependabot::DependencyFile]) }
def subapp_mixfiles
subapp_directories = []
subapp_directories += umbrella_app_directories
Expand All @@ -86,15 +93,17 @@ def subapp_mixfiles
[]
end

sig { returns(T::Array[T.nilable(Dependabot::DependencyFile)]) }
def support_files
mixfiles = [mixfile] + subapp_mixfiles

mixfiles.flat_map do |mixfile|
mixfile_dir = mixfile.path.to_s.delete_prefix("/").delete_suffix("/mix.exs")
mixfile_dir = mixfile&.path&.to_s&.delete_prefix("/")&.delete_suffix("/mix.exs")

mixfile.content.gsub("__DIR__", "\"#{mixfile_dir}\"").scan(SUPPORT_FILE).map do |support_file_args|
path = Pathname.new(File.join(*support_file_args.compact.reverse))
.cleanpath.to_path
mixfile&.content&.gsub("__DIR__", "\"#{mixfile_dir}\"")&.scan(SUPPORT_FILE)&.map do |support_file_args|
path = Pathname.new(File.join(Array(support_file_args).compact.reverse))
.cleanpath
.to_path
fetch_file_from_host(path).tap { |f| f.support_file = true }
end
end
Expand Down

0 comments on commit 59948a2

Please sign in to comment.