dependabot-bundler 0.284.0 → 0.286.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48a9435c67c8a6b58134c7a80486d74ab609273e937c10eed74191426d6cded8
4
- data.tar.gz: a139d9cc839fddffc0e0ca6ef3b8a7ab87d9a1ae2d82e5404e16b1823502cf2e
3
+ metadata.gz: 0ce0397383ee54f28c18dd936362de171d27f055d66754451e17ba8c57e4885a
4
+ data.tar.gz: 49ac7f319dcb2c6b7a84d434b171cb66ec4757db1f6f68c92be8e3a3b3f448e2
5
5
  SHA512:
6
- metadata.gz: 9612d984f30f3e0cfa5079a1c34be49112fe4de0e93aabca848a70f5438ae722acd958746950f7ff94404f66ce14bc50ec8604014e933e7877d7fb0cdf013bdc
7
- data.tar.gz: c2edeee8f3df7b37c19b747b4e54a6d34846efde4ab76a26d14302124432b77901c57afedc3cad21a95695c619f445b7d08e10dfa72e882fe8fc7688367b5e9c
6
+ metadata.gz: 87221c02650ec120d7dce3b5f65386f9585d2554ced84b6d7ead43449871955a13e621a2cf1d72ad8442caf598105c0bfda19f16e0d17f3d36a848c1d85fb250
7
+ data.tar.gz: a0a20ecf386feb119de3b653f6fb598a061bda76521c456c713b5683cf2d94ec945b37fa4fa3e01471bee97e5de8888a7638caf014cc5afd8ddb7f7ad3ad1054
@@ -173,4 +173,12 @@ module Functions
173
173
  credentials
174
174
  .select { |cred| cred["type"] == "git_source" }
175
175
  end
176
+
177
+ def self.bundler_raw_version
178
+ Bundler::VERSION
179
+ end
180
+
181
+ def self.ruby_raw_version
182
+ RUBY_VERSION
183
+ end
176
184
  end
@@ -2,6 +2,8 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "parallel"
5
+ require "dependabot/bundler/language"
6
+ require "dependabot/bundler/package_manager"
5
7
  require "dependabot/dependency"
6
8
  require "dependabot/file_parsers"
7
9
  require "dependabot/file_parsers/base"
@@ -37,7 +39,8 @@ module Dependabot
37
39
  @ecosystem ||= T.let(
38
40
  Ecosystem.new(
39
41
  name: ECOSYSTEM,
40
- package_manager: package_manager
42
+ package_manager: package_manager,
43
+ language: language
41
44
  ),
42
45
  T.nilable(Ecosystem)
43
46
  )
@@ -47,7 +50,28 @@ module Dependabot
47
50
 
48
51
  sig { returns(Ecosystem::VersionManager) }
49
52
  def package_manager
50
- PackageManager.new(bundler_version)
53
+ @package_manager ||= PackageManager.new(bundler_raw_version, package_manager_requirement)
54
+ end
55
+
56
+ def package_manager_requirement
57
+ @package_manager_requirement ||= Helpers.dependency_requirement(
58
+ Helpers::BUNDLER_GEM_NAME, dependency_files
59
+ )
60
+ end
61
+
62
+ sig { returns(T.nilable(Ecosystem::VersionManager)) }
63
+ def language
64
+ return @language if defined?(@language)
65
+
66
+ return nil if package_manager.unsupported?
67
+
68
+ Language.new(ruby_raw_version, language_requirement)
69
+ end
70
+
71
+ def language_requirement
72
+ @language_requirement ||= Helpers.dependency_requirement(
73
+ Helpers::LANGUAGE, dependency_files
74
+ )
51
75
  end
52
76
 
53
77
  def check_external_code(dependencies)
@@ -327,6 +351,51 @@ module Dependabot
327
351
  .reject { |f| f.name == "gems.rb" }
328
352
  end
329
353
 
354
+ sig { returns(String) }
355
+ def bundler_raw_version
356
+ return bundler_raw_version if defined?(@bundler_raw_version)
357
+
358
+ package_manager = PackageManager.new(bundler_version)
359
+
360
+ # If the selected version is unsupported, an unsupported error will be raised,
361
+ # so there’s no need to attempt retrieving the raw version.
362
+ return bundler_version if package_manager.unsupported?
363
+
364
+ # read raw version directly from the ecosystem environment
365
+ bundler_raw_version = SharedHelpers.in_a_temporary_repo_directory(
366
+ base_directory,
367
+ repo_contents_path
368
+ ) do
369
+ write_temporary_dependency_files
370
+ NativeHelpers.run_bundler_subprocess(
371
+ function: "bundler_raw_version",
372
+ args: {},
373
+ bundler_version: bundler_version,
374
+ options: { timeout_per_operation_seconds: 10 }
375
+ )
376
+ end
377
+ bundler_raw_version || ::Bundler::VERSION
378
+ end
379
+
380
+ sig { returns(String) }
381
+ def ruby_raw_version
382
+ return @ruby_raw_version if defined?(@ruby_raw_version)
383
+
384
+ ruby_raw_version = SharedHelpers.in_a_temporary_repo_directory(
385
+ base_directory,
386
+ repo_contents_path
387
+ ) do
388
+ write_temporary_dependency_files
389
+ NativeHelpers.run_bundler_subprocess(
390
+ function: "ruby_raw_version",
391
+ args: {},
392
+ bundler_version: bundler_version,
393
+ options: { timeout_per_operation_seconds: 10 }
394
+ )
395
+ end
396
+ ruby_raw_version || RUBY_VERSION
397
+ end
398
+
330
399
  sig { returns(String) }
331
400
  def bundler_version
332
401
  @bundler_version ||= Helpers.bundler_version(lockfile)
@@ -1,6 +1,8 @@
1
1
  # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "dependabot/bundler/requirement"
5
+
4
6
  module Dependabot
5
7
  module Bundler
6
8
  module Helpers
@@ -9,16 +11,21 @@ module Dependabot
9
11
 
10
12
  V1 = "1"
11
13
  V2 = "2"
12
- # If we are updating a project with no Gemfile.lock, we default to the
13
- # newest version we support
14
14
  DEFAULT = V2
15
15
  BUNDLER_MAJOR_VERSION_REGEX = /BUNDLED WITH\s+(?<version>\d+)\./m
16
+ RUBY_GEMFILE_REGEX = /^ruby\s+['"]([^'"]+)['"]/
17
+ RUBY_GEMSPEC_REGEX = /required_ruby_version\s+=\s+['"]([^'"]+)['"]/
18
+
19
+ GEMFILE = "Gemfile"
20
+ GEMSPEC_EXTENSION = ".gemspec"
21
+ BUNDLER_GEM_NAME = "bundler"
22
+ LANGUAGE = "ruby"
16
23
 
17
24
  sig { params(lockfile: T.nilable(Dependabot::DependencyFile)).returns(String) }
18
25
  def self.bundler_version(lockfile)
19
26
  return DEFAULT unless lockfile
20
27
 
21
- if (matches = lockfile.content&.match(BUNDLER_MAJOR_VERSION_REGEX))
28
+ if (matches = T.let(lockfile.content, T.nilable(String))&.match(BUNDLER_MAJOR_VERSION_REGEX))
22
29
  matches[:version].to_i >= 2 ? V2 : V1
23
30
  else
24
31
  DEFAULT
@@ -29,12 +36,93 @@ module Dependabot
29
36
  def self.detected_bundler_version(lockfile)
30
37
  return "unknown" unless lockfile
31
38
 
32
- if (matches = lockfile.content&.match(BUNDLER_MAJOR_VERSION_REGEX))
39
+ if (matches = T.let(lockfile.content, T.nilable(String))&.match(BUNDLER_MAJOR_VERSION_REGEX))
33
40
  matches[:version].to_i.to_s
34
41
  else
35
42
  "unspecified"
36
43
  end
37
44
  end
45
+
46
+ # Method to get the Requirement object for the 'bundler' dependency
47
+ sig do
48
+ params(
49
+ dependency_name: String,
50
+ files: T::Array[Dependabot::DependencyFile]
51
+ ).returns(T.nilable(Dependabot::Bundler::Requirement))
52
+ end
53
+ def self.dependency_requirement(dependency_name, files)
54
+ constraints = combined_dependency_constraints(files, dependency_name)
55
+ return nil if constraints.empty?
56
+
57
+ combined_constraint = constraints.join(", ")
58
+
59
+ Dependabot::Bundler::Requirement.new(combined_constraint)
60
+ rescue StandardError => e
61
+ Dependabot.logger.error(
62
+ "Failed to create Requirement with constraints '#{constraints&.join(', ')}': #{e.message}"
63
+ )
64
+ nil
65
+ end
66
+
67
+ # Method to gather and combine constraints for a specified dependency from multiple files
68
+ sig do
69
+ params(files: T::Array[Dependabot::DependencyFile], dependency_name: String).returns(T::Array[String])
70
+ end
71
+ def self.combined_dependency_constraints(files, dependency_name)
72
+ files.each_with_object([]) do |file, result|
73
+ content = file.content
74
+ next unless content
75
+
76
+ # Select the appropriate regex based on file type and dependency name
77
+ regex = if dependency_name == LANGUAGE
78
+ ruby_version_regex(file.name)
79
+ elsif file.name.end_with?(GEMFILE)
80
+ gemfile_dependency_regex(dependency_name)
81
+ elsif file.name.end_with?(GEMSPEC_EXTENSION)
82
+ gemspec_dependency_regex(dependency_name)
83
+ else
84
+ next # Skip unsupported file types, including .ruby-version
85
+ end
86
+
87
+ # If regex is nil (unsupported for this file type), skip to the next file
88
+ next unless regex
89
+
90
+ # Extract constraints using the chosen regex
91
+ result.concat(extract_constraints_from_file(content, regex))
92
+ end.uniq
93
+ end
94
+
95
+ # Method to generate the regex pattern for Ruby version in Gemfile or gemspec
96
+ sig { params(file_name: String).returns(T.nilable(Regexp)) }
97
+ def self.ruby_version_regex(file_name)
98
+ if file_name.end_with?(GEMFILE)
99
+ RUBY_GEMFILE_REGEX
100
+ elsif file_name.end_with?(GEMSPEC_EXTENSION)
101
+ RUBY_GEMSPEC_REGEX
102
+ end
103
+ end
104
+
105
+ # Method to generate the regex pattern for a dependency in a Gemfile
106
+ sig { params(dependency_name: String).returns(Regexp) }
107
+ def self.gemfile_dependency_regex(dependency_name)
108
+ /gem\s+['"]#{Regexp.escape(dependency_name)}['"](?:,\s*['"]([^'"]+)['"])?/
109
+ end
110
+
111
+ # Method to generate the regex pattern for a dependency in a gemspec file
112
+ sig { params(dependency_name: String).returns(Regexp) }
113
+ def self.gemspec_dependency_regex(dependency_name)
114
+ /add_(?:runtime_)?dependency\s+['"]#{Regexp.escape(dependency_name)}['"],\s*['"]([^'"]+)['"]/
115
+ end
116
+
117
+ # Extracts constraints from file content based on a dependency regex
118
+ sig { params(content: String, regex: Regexp).returns(T::Array[String]) }
119
+ def self.extract_constraints_from_file(content, regex)
120
+ if content.match(regex)
121
+ content.scan(regex).flatten
122
+ else
123
+ []
124
+ end
125
+ end
38
126
  end
39
127
  end
40
128
  end
@@ -0,0 +1,21 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "dependabot/bundler/version"
6
+ require "dependabot/ecosystem"
7
+
8
+ module Dependabot
9
+ module Bundler
10
+ LANGUAGE = "ruby"
11
+
12
+ class Language < Dependabot::Ecosystem::VersionManager
13
+ extend T::Sig
14
+
15
+ sig { params(raw_version: String, requirement: T.nilable(Requirement)).void }
16
+ def initialize(raw_version, requirement = nil)
17
+ super(LANGUAGE, Version.new(raw_version), [], [], requirement)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -4,6 +4,7 @@
4
4
  require "sorbet-runtime"
5
5
  require "dependabot/bundler/version"
6
6
  require "dependabot/ecosystem"
7
+ require "dependabot/bundler/requirement"
7
8
 
8
9
  module Dependabot
9
10
  module Bundler
@@ -22,13 +23,19 @@ module Dependabot
22
23
  class PackageManager < Dependabot::Ecosystem::VersionManager
23
24
  extend T::Sig
24
25
 
25
- sig { params(raw_version: String).void }
26
- def initialize(raw_version)
26
+ sig do
27
+ params(
28
+ raw_version: String,
29
+ requirement: T.nilable(Requirement)
30
+ ).void
31
+ end
32
+ def initialize(raw_version, requirement = nil)
27
33
  super(
28
34
  PACKAGE_MANAGER,
29
35
  Version.new(raw_version),
30
36
  DEPRECATED_BUNDLER_VERSIONS,
31
37
  SUPPORTED_BUNDLER_VERSIONS,
38
+ requirement,
32
39
  )
33
40
  end
34
41
  end
@@ -3,6 +3,8 @@
3
3
 
4
4
  # These all need to be required so the various classes can be registered in a
5
5
  # lookup table of package manager names to concrete classes.
6
+ require "dependabot/bundler/language"
7
+ require "dependabot/bundler/package_manager"
6
8
  require "dependabot/bundler/file_fetcher"
7
9
  require "dependabot/bundler/file_parser"
8
10
  require "dependabot/bundler/update_checker"
@@ -10,7 +12,6 @@ require "dependabot/bundler/file_updater"
10
12
  require "dependabot/bundler/metadata_finder"
11
13
  require "dependabot/bundler/requirement"
12
14
  require "dependabot/bundler/version"
13
- require "dependabot/bundler/package_manager"
14
15
 
15
16
  require "dependabot/pull_request_creator/labeler"
16
17
  Dependabot::PullRequestCreator::Labeler
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-bundler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.284.0
4
+ version: 0.286.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-05 00:00:00.000000000 Z
11
+ date: 2024-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.284.0
19
+ version: 0.286.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.284.0
26
+ version: 0.286.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: parallel
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -302,6 +302,7 @@ files:
302
302
  - lib/dependabot/bundler/file_updater/requirement_replacer.rb
303
303
  - lib/dependabot/bundler/file_updater/ruby_requirement_setter.rb
304
304
  - lib/dependabot/bundler/helpers.rb
305
+ - lib/dependabot/bundler/language.rb
305
306
  - lib/dependabot/bundler/metadata_finder.rb
306
307
  - lib/dependabot/bundler/native_helpers.rb
307
308
  - lib/dependabot/bundler/package_manager.rb
@@ -321,7 +322,7 @@ licenses:
321
322
  - MIT
322
323
  metadata:
323
324
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
324
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.284.0
325
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.286.0
325
326
  post_install_message:
326
327
  rdoc_options: []
327
328
  require_paths: