Module: Dependabot::Bundler::Helpers

Extended by:
T::Helpers, T::Sig
Defined in:
lib/dependabot/bundler/helpers.rb

Constant Summary collapse

V1 =
"1"
V2 =
"2"
DEFAULT =
V2
BUNDLER_MAJOR_VERSION_REGEX =
/BUNDLED WITH\s+(?<version>\d+)\./m
RUBY_GEMFILE_REGEX =
/^ruby\s+['"]([^'"]+)['"]/
RUBY_GEMSPEC_REGEX =
/required_ruby_version\s+=\s+['"]([^'"]+)['"]/
GEMFILE =
"Gemfile"
GEMSPEC_EXTENSION =
".gemspec"
BUNDLER_GEM_NAME =
"bundler"
LANGUAGE =
"ruby"

Class Method Summary collapse

Class Method Details

.bundler_version(lockfile) ⇒ Object



25
26
27
28
29
30
31
32
33
# File 'lib/dependabot/bundler/helpers.rb', line 25

def self.bundler_version(lockfile)
  return DEFAULT unless lockfile

  if (matches = T.let(lockfile.content, T.nilable(String))&.match(BUNDLER_MAJOR_VERSION_REGEX))
    matches[:version].to_i >= 2 ? V2 : V1
  else
    DEFAULT
  end
end

.combined_dependency_constraints(files, dependency_name) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/dependabot/bundler/helpers.rb', line 71

def self.combined_dependency_constraints(files, dependency_name)
  files.each_with_object([]) do |file, result|
    content = file.content
    next unless content

    # Select the appropriate regex based on file type and dependency name
    regex = if dependency_name == LANGUAGE
              ruby_version_regex(file.name)
            elsif file.name.end_with?(GEMFILE)
              gemfile_dependency_regex(dependency_name)
            elsif file.name.end_with?(GEMSPEC_EXTENSION)
              gemspec_dependency_regex(dependency_name)
            else
              next # Skip unsupported file types, including .ruby-version
            end

    # If regex is nil (unsupported for this file type), skip to the next file
    next unless regex

    # Extract constraints using the chosen regex
    result.concat(extract_constraints_from_file(content, regex))
  end.uniq
end

.dependency_requirement(dependency_name, files) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/dependabot/bundler/helpers.rb', line 53

def self.dependency_requirement(dependency_name, files)
  constraints = combined_dependency_constraints(files, dependency_name)
  return nil if constraints.empty?

  combined_constraint = constraints.join(", ")

  Dependabot::Bundler::Requirement.new(combined_constraint)
rescue StandardError => e
  Dependabot.logger.error(
    "Failed to create Requirement with constraints '#{constraints&.join(', ')}': #{e.message}"
  )
  nil
end

.detected_bundler_version(lockfile) ⇒ Object



36
37
38
39
40
41
42
43
44
# File 'lib/dependabot/bundler/helpers.rb', line 36

def self.detected_bundler_version(lockfile)
  return "unknown" unless lockfile

  if (matches = T.let(lockfile.content, T.nilable(String))&.match(BUNDLER_MAJOR_VERSION_REGEX))
    matches[:version].to_i.to_s
  else
    "unspecified"
  end
end

.extract_constraints_from_file(content, regex) ⇒ Object



119
120
121
122
123
124
125
# File 'lib/dependabot/bundler/helpers.rb', line 119

def self.extract_constraints_from_file(content, regex)
  if content.match(regex)
    content.scan(regex).flatten
  else
    []
  end
end

.gemfile_dependency_regex(dependency_name) ⇒ Object



107
108
109
# File 'lib/dependabot/bundler/helpers.rb', line 107

def self.gemfile_dependency_regex(dependency_name)
  /gem\s+['"]#{Regexp.escape(dependency_name)}['"](?:,\s*['"]([^'"]+)['"])?/
end

.gemspec_dependency_regex(dependency_name) ⇒ Object



113
114
115
# File 'lib/dependabot/bundler/helpers.rb', line 113

def self.gemspec_dependency_regex(dependency_name)
  /add_(?:runtime_)?dependency\s+['"]#{Regexp.escape(dependency_name)}['"],\s*['"]([^'"]+)['"]/
end

.ruby_version_regex(file_name) ⇒ Object



97
98
99
100
101
102
103
# File 'lib/dependabot/bundler/helpers.rb', line 97

def self.ruby_version_regex(file_name)
  if file_name.end_with?(GEMFILE)
    RUBY_GEMFILE_REGEX
  elsif file_name.end_with?(GEMSPEC_EXTENSION)
    RUBY_GEMSPEC_REGEX
  end
end