dependabot-bundler 0.302.0 → 0.304.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d3c8c83c273d821557584676f42488234689de03421a45e2c49f8e2ab6a26a8
4
- data.tar.gz: eeab730ddbd286dec2eb0b273ee3958a41ddd2d605f52e2575f8043dbc03d3fa
3
+ metadata.gz: afac5aac6bfb6ee45bfa6a928dcd47663352670e32334a78859f6062cdf5e38e
4
+ data.tar.gz: 9a5c98bda93d938912881fdc6d4407304d485795e6e170c2256b462f8a967546
5
5
  SHA512:
6
- metadata.gz: 7695d38798ab69af473e091bbf9697875c9216fc6c9272a76fa6ad678bb406274a0e0d96b7a84b78f2924c9065015352294506bce74e0c09f53d03c67ab7af43
7
- data.tar.gz: a586a5c50a26304af971e5947398efc1017017c52f9850f840ff083e1e447ade3516db99124c8d1e14cdfff25d7d624ea5019d82e6a5fa4353e664b693816e4d
6
+ metadata.gz: 19e479a5ea88a9a770c780172b9a1e07cd8a694a3b22825adb348257126871490fe044d56da48a81ca02973cbd0835e5d681a752e4405c3fe0cda3f7c2cda57e
7
+ data.tar.gz: 45aa64aef52bfca8cb704e1eab1af719ac4a59d3f806e5a4cd412f7ebf234a336fcab74f8e0b56ee749f1ceb92a0b578e0aecf715886a4f1d1960249c7badf11
@@ -0,0 +1,228 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require "time"
6
+ require "cgi"
7
+ require "excon"
8
+ require "nokogiri"
9
+ require "sorbet-runtime"
10
+ require "dependabot/registry_client"
11
+ require "dependabot/bundler"
12
+ require "dependabot/package/package_release"
13
+ require "dependabot/package/package_details"
14
+
15
+ module Dependabot
16
+ module Bundler
17
+ module Package
18
+ class PackageDetailsFetcher
19
+ extend T::Sig
20
+
21
+ require_relative "../update_checker/shared_bundler_helpers"
22
+ include Dependabot::Bundler::UpdateChecker::SharedBundlerHelpers
23
+
24
+ RELEASES_URL = "https://rubygems.org/api/v1/versions/%s.json"
25
+ GEM_URL = "https://rubygems.org/gems/%s.gem"
26
+ PACKAGE_TYPE = "gem"
27
+ PACKAGE_LANGUAGE = "ruby"
28
+ APPLICATION_JSON = "application/json"
29
+
30
+ RUBYGEMS = "rubygems"
31
+ PRIVATE_REGISTRY = "private"
32
+ GIT = "git"
33
+ OTHER = "other"
34
+
35
+ sig do
36
+ params(
37
+ dependency: Dependabot::Dependency,
38
+ dependency_files: T::Array[Dependabot::DependencyFile],
39
+ credentials: T::Array[Dependabot::Credential]
40
+ ).void
41
+ end
42
+ def initialize(dependency:, dependency_files:, credentials:)
43
+ @dependency = dependency
44
+ @dependency_files = dependency_files
45
+ @credentials = credentials
46
+
47
+ @source_type = T.let(nil, T.nilable(String))
48
+ end
49
+
50
+ sig { returns(Dependabot::Dependency) }
51
+ attr_reader :dependency
52
+
53
+ sig { returns(T::Array[T.untyped]) }
54
+ attr_reader :dependency_files
55
+
56
+ sig { returns(T::Array[T.untyped]) }
57
+ attr_reader :credentials
58
+
59
+ sig { returns(Dependabot::Package::PackageDetails) }
60
+ def fetch
61
+ return rubygems_versions if dependency.name == "bundler"
62
+ return rubygems_versions unless gemfile
63
+
64
+ case source_type
65
+ when OTHER, GIT, PRIVATE_REGISTRY
66
+ package_details([])
67
+ else
68
+ rubygems_versions
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ # Example JSON Response Format:
75
+ # eg https://rubygems.org/api/v1/versions/dependabot-common.json
76
+ # response:
77
+ # [
78
+ # {
79
+ # authors: "Dependabot",
80
+ # built_at: "2025-03-20T00:00:00.000Z",
81
+ # created_at: "2025-03-20T14:48:33.295Z",
82
+ # description: "Dependabot-Common provides the shared code used across Dependabot. If you want support for
83
+ # multiple package managers, you probably want the meta-gem dependabot-omnibus.",
84
+ # downloads_count: 382,
85
+ # metadata: {
86
+ # changelog_uri: "https://github.com/dependabot/dependabot-core/releases/tag/v0.302.0",
87
+ # bug_tracker_uri: "https://github.com/dependabot/dependabot-core/issues"
88
+ # },
89
+ # number: "0.302.0",
90
+ # summary: "Shared code used across Dependabot Core",
91
+ # platform: "ruby",
92
+ # rubygems_version: ">= 3.3.7",
93
+ # ruby_version: ">= 3.1.0",
94
+ # prerelease: false,
95
+ # licenses: [
96
+ # "MIT"
97
+ # ],
98
+ # requirements: [ ],
99
+ # sha: "e8ef286a91add81534c297425f2f2efc0c5671f3307307f7fad62c059ed8fca2",
100
+ # spec_sha: "cd0ac8f3462449bf19e7356dbc2ec83eec378b41702e03221ededc49875b1e1c"
101
+ # },
102
+ # {
103
+ # authors: "Dependabot",
104
+ # built_at: "2025-03-14T00:00:00.000Z",
105
+ # created_at: "2025-03-14T18:46:18.547Z",
106
+ # description: "Dependabot-Common provides the shared code used across Dependabot. If you want support for
107
+ # multiple package managers, you probably want the meta-gem dependabot-omnibus.",
108
+ # downloads_count: 324,
109
+ # metadata: {
110
+ # changelog_uri: "https://github.com/dependabot/dependabot-core/releases/tag/v0.301.1",
111
+ # bug_tracker_uri: "https://github.com/dependabot/dependabot-core/issues"
112
+ # },
113
+ # number: "0.301.1",
114
+ # summary: "Shared code used across Dependabot Core",
115
+ # platform: "ruby",
116
+ # rubygems_version: ">= 3.3.7",
117
+ # ruby_version: ">= 3.1.0",
118
+ # prerelease: false,
119
+ # licenses: [
120
+ # "MIT"
121
+ # ],
122
+ # requirements: [ ],
123
+ # sha: "47e5948069571271d72c12f8c03106b415a00550857b6c5fb22aeb780cfe1da7",
124
+ # spec_sha: "7191388ac6fa0ea72ed7588f848b2b244a0dc5a4ec3e6b7c9d395296b0fa93d9"
125
+ # },
126
+ # ...
127
+ # ]
128
+ sig { returns(Dependabot::Package::PackageDetails) }
129
+ def rubygems_versions
130
+ response = registry_json_response_for_dependency
131
+ raise unless response.status == 200
132
+
133
+ package_releases = JSON.parse(response.body).map do |release|
134
+ package_release(
135
+ version: release["number"],
136
+ released_at: Time.parse(release["created_at"]),
137
+ downloads: release["downloads_count"],
138
+ url: GEM_URL % "#{@dependency.name}-#{release['number']}",
139
+ ruby_version: release["ruby_version"]
140
+ )
141
+ end
142
+
143
+ package_details(package_releases)
144
+ end
145
+
146
+ sig { returns(Excon::Response) }
147
+ def registry_json_response_for_dependency
148
+ url = RELEASES_URL % dependency.name
149
+ Dependabot::RegistryClient.get(
150
+ url: url,
151
+ headers: { "Accept" => APPLICATION_JSON }
152
+ )
153
+ end
154
+
155
+ sig { params(req_string: String).returns(Requirement) }
156
+ def language_requirement(req_string)
157
+ Requirement.new(req_string)
158
+ end
159
+
160
+ sig { returns(String) }
161
+ def source_type
162
+ @source_type ||= begin
163
+ return @source_type = RUBYGEMS unless gemfile
164
+
165
+ @source_type = in_a_native_bundler_context do |tmp_dir|
166
+ NativeHelpers.run_bundler_subprocess(
167
+ bundler_version: bundler_version,
168
+ function: "dependency_source_type",
169
+ options: {}, # options,
170
+ args: {
171
+ dir: tmp_dir,
172
+ gemfile_name: gemfile.name,
173
+ dependency_name: dependency.name,
174
+ credentials: credentials
175
+ }
176
+ )
177
+ end
178
+ end
179
+ end
180
+
181
+ sig { override.returns(String) }
182
+ def bundler_version
183
+ @bundler_version ||= T.let(Helpers.bundler_version(lockfile), T.nilable(String))
184
+ end
185
+
186
+ sig do
187
+ params(releases: T::Array[Dependabot::Package::PackageRelease])
188
+ .returns(Dependabot::Package::PackageDetails)
189
+ end
190
+ def package_details(releases)
191
+ @package_details ||= T.let(
192
+ Dependabot::Package::PackageDetails.new(
193
+ dependency: dependency,
194
+ releases: releases.reverse.uniq(&:version)
195
+ ), T.nilable(Dependabot::Package::PackageDetails)
196
+ )
197
+ end
198
+
199
+ sig do
200
+ params(
201
+ version: String,
202
+ released_at: Time,
203
+ downloads: Integer,
204
+ url: String,
205
+ ruby_version: String,
206
+ yanked: T::Boolean
207
+ ).returns(Dependabot::Package::PackageRelease)
208
+ end
209
+ def package_release(version:, released_at:, downloads:, url:, ruby_version:, yanked: false)
210
+ Dependabot::Package::PackageRelease.new(
211
+ version: Dependabot::Bundler::Version.new(version),
212
+ released_at: released_at,
213
+ yanked: yanked,
214
+ yanked_reason: nil,
215
+ downloads: downloads,
216
+ url: url,
217
+ package_type: PACKAGE_TYPE,
218
+ language: Dependabot::Package::PackageLanguage.new(
219
+ name: PACKAGE_LANGUAGE,
220
+ version: nil,
221
+ requirement: language_requirement(ruby_version)
222
+ )
223
+ )
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end
@@ -4,12 +4,13 @@
4
4
  require "dependabot/registry_client"
5
5
  require "dependabot/bundler/native_helpers"
6
6
  require "dependabot/bundler/helpers"
7
+ require "dependabot/bundler/update_checker/latest_version_finder"
7
8
  require "sorbet-runtime"
8
9
 
9
10
  module Dependabot
10
11
  module Bundler
11
12
  class UpdateChecker
12
- class LatestVersionFinder
13
+ class LatestVersionFinder < Dependabot::Package::PackageLatestVersionFinder
13
14
  class DependencySource
14
15
  extend T::Sig
15
16
 
@@ -8,46 +8,54 @@ require "dependabot/update_checkers/version_filters"
8
8
  require "dependabot/bundler/requirement"
9
9
  require "dependabot/shared_helpers"
10
10
  require "dependabot/errors"
11
+ require "dependabot/package/package_latest_version_finder"
11
12
  require "dependabot/bundler/update_checker/latest_version_finder/" \
12
13
  "dependency_source"
14
+ require "dependabot/bundler/package/package_details_fetcher"
13
15
  require "sorbet-runtime"
14
16
 
15
17
  module Dependabot
16
18
  module Bundler
17
19
  class UpdateChecker
18
- class LatestVersionFinder
20
+ class LatestVersionFinder < Dependabot::Package::PackageLatestVersionFinder
19
21
  extend T::Sig
20
22
 
21
- def initialize(dependency:, dependency_files:, repo_contents_path: nil,
22
- credentials:, ignored_versions:, raise_on_ignored: false,
23
- security_advisories:, options:)
24
- @dependency = dependency
25
- @dependency_files = dependency_files
26
- @repo_contents_path = repo_contents_path
27
- @credentials = credentials
28
- @ignored_versions = ignored_versions
29
- @raise_on_ignored = raise_on_ignored
30
- @security_advisories = security_advisories
31
- @options = options
23
+ sig { override.returns(T.nilable(Dependabot::Package::PackageDetails)) }
24
+ def package_details
25
+ @package_details ||= Package::PackageDetailsFetcher.new(
26
+ dependency: dependency,
27
+ dependency_files: dependency_files,
28
+ credentials: credentials
29
+ ).fetch
32
30
  end
33
31
 
34
32
  def latest_version_details
35
- @latest_version_details ||= fetch_latest_version_details
33
+ @latest_version_details ||= if cooldown_enabled?
34
+ latest_version = fetch_latest_version(language_version: nil)
35
+ latest_version ? { version: latest_version } : nil
36
+ else
37
+ fetch_latest_version_details
38
+ end
36
39
  end
37
40
 
38
- def lowest_security_fix_version
39
- @lowest_security_fix_version ||= fetch_lowest_security_fix_version
41
+ sig { override.returns(T::Boolean) }
42
+ def cooldown_enabled?
43
+ Dependabot::Experiments.enabled?(:enable_cooldown_for_bundler)
40
44
  end
41
45
 
42
- private
46
+ sig { override.returns(T.nilable(T::Array[Dependabot::Package::PackageRelease])) }
47
+ def available_versions
48
+ return nil if package_details&.releases.nil?
49
+
50
+ source_versions = dependency_source.versions
51
+ return [] if source_versions.empty?
43
52
 
44
- attr_reader :dependency
45
- attr_reader :dependency_files
46
- attr_reader :repo_contents_path
47
- attr_reader :credentials
48
- attr_reader :ignored_versions
49
- attr_reader :security_advisories
50
- attr_reader :options
53
+ T.must(package_details).releases.select do |release|
54
+ source_versions.any? { |v| v.to_s == release.version.to_s }
55
+ end
56
+ end
57
+
58
+ private
51
59
 
52
60
  def fetch_latest_version_details
53
61
  return dependency_source.latest_git_version_details if dependency_source.git?
@@ -59,7 +67,7 @@ module Dependabot
59
67
  relevant_versions.empty? ? nil : { version: relevant_versions.max }
60
68
  end
61
69
 
62
- def fetch_lowest_security_fix_version
70
+ def fetch_lowest_security_fix_version(*)
63
71
  return if dependency_source.git?
64
72
 
65
73
  relevant_versions = dependency_source.versions
@@ -72,41 +80,9 @@ module Dependabot
72
80
  relevant_versions.min
73
81
  end
74
82
 
75
- sig { params(versions_array: T::Array[Gem::Version]).returns(T::Array[Gem::Version]) }
76
- def filter_prerelease_versions(versions_array)
77
- return versions_array if wants_prerelease?
78
-
79
- filtered = versions_array.reject(&:prerelease?)
80
- if versions_array.count > filtered.count
81
- Dependabot.logger.info("Filtered out #{versions_array.count - filtered.count} pre-release versions")
82
- end
83
- filtered
84
- end
85
-
86
- sig { params(versions_array: T::Array[Gem::Version]).returns(T::Array[Gem::Version]) }
87
- def filter_ignored_versions(versions_array)
88
- filtered = versions_array
89
- .reject { |v| ignore_requirements.any? { |r| r.satisfied_by?(v) } }
90
- if @raise_on_ignored && filter_lower_versions(filtered).empty? && filter_lower_versions(versions_array).any?
91
- raise AllVersionsIgnored
92
- end
93
-
94
- if versions_array.count > filtered.count
95
- Dependabot.logger.info("Filtered out #{versions_array.count - filtered.count} ignored versions")
96
- end
97
-
98
- filtered
99
- end
100
-
101
- def filter_lower_versions(versions_array)
102
- return versions_array unless dependency.numeric_version
103
-
104
- versions_array
105
- .select { |version| version > dependency.numeric_version }
106
- end
107
-
83
+ sig { returns(T::Boolean) }
108
84
  def wants_prerelease?
109
- @wants_prerelease ||=
85
+ @wants_prerelease ||= T.let(
110
86
  begin
111
87
  current_version = dependency.numeric_version
112
88
  if current_version&.prerelease?
@@ -116,30 +92,21 @@ module Dependabot
116
92
  req[:requirement].match?(/[a-z]/i)
117
93
  end
118
94
  end
119
- end
95
+ end, T.nilable(T::Boolean)
96
+ )
120
97
  end
121
98
 
99
+ # sig { returns(DependencySource) }
122
100
  def dependency_source
123
- @dependency_source ||= DependencySource.new(
124
- dependency: dependency,
125
- dependency_files: dependency_files,
126
- credentials: credentials,
127
- options: options
101
+ @dependency_source ||= T.let(
102
+ DependencySource.new(
103
+ dependency: dependency,
104
+ dependency_files: dependency_files,
105
+ credentials: credentials,
106
+ options: options
107
+ ), T.nilable(DependencySource)
128
108
  )
129
109
  end
130
-
131
- def ignore_requirements
132
- ignored_versions.flat_map { |req| requirement_class.requirements_array(req) }
133
- end
134
-
135
- def requirement_class
136
- dependency.requirement_class
137
- end
138
-
139
- def gemfile
140
- dependency_files.find { |f| f.name == "Gemfile" } ||
141
- dependency_files.find { |f| f.name == "gems.rb" }
142
- end
143
110
  end
144
111
  end
145
112
  end
@@ -26,6 +26,7 @@ module Dependabot
26
26
  replacement_git_pin: nil, remove_git_source: false,
27
27
  unlock_requirement: true,
28
28
  latest_allowable_version: nil,
29
+ cooldown_options: {},
29
30
  options:)
30
31
  @dependency = dependency
31
32
  @unprepared_dependency_files = unprepared_dependency_files
@@ -37,6 +38,7 @@ module Dependabot
37
38
  @remove_git_source = remove_git_source
38
39
  @unlock_requirement = unlock_requirement
39
40
  @latest_allowable_version = latest_allowable_version
41
+ @cooldown_options = cooldown_options
40
42
  @options = options
41
43
 
42
44
  @latest_allowable_version_incompatible_with_ruby = false
@@ -183,7 +185,6 @@ module Dependabot
183
185
  LatestVersionFinder.new(
184
186
  dependency: dependency,
185
187
  dependency_files: dependency_files,
186
- repo_contents_path: repo_contents_path,
187
188
  credentials: credentials,
188
189
  ignored_versions: ignored_versions,
189
190
  raise_on_ignored: @raise_on_ignored,
@@ -367,7 +367,6 @@ module Dependabot
367
367
  LatestVersionFinder.new(
368
368
  dependency: dependency,
369
369
  dependency_files: prepared_dependency_files,
370
- repo_contents_path: repo_contents_path,
371
370
  credentials: credentials,
372
371
  ignored_versions: ignored_versions,
373
372
  raise_on_ignored: raise_on_ignored,
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.302.0
4
+ version: 0.304.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-20 00:00:00.000000000 Z
11
+ date: 2025-04-03 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.302.0
19
+ version: 0.304.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.302.0
26
+ version: 0.304.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: parallel
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -170,14 +170,14 @@ dependencies:
170
170
  requirements:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: 0.8.5
173
+ version: 0.8.7
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: 0.8.5
180
+ version: 0.8.7
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: simplecov
183
183
  requirement: !ruby/object:Gem::Requirement
@@ -305,6 +305,7 @@ files:
305
305
  - lib/dependabot/bundler/language.rb
306
306
  - lib/dependabot/bundler/metadata_finder.rb
307
307
  - lib/dependabot/bundler/native_helpers.rb
308
+ - lib/dependabot/bundler/package/package_details_fetcher.rb
308
309
  - lib/dependabot/bundler/package_manager.rb
309
310
  - lib/dependabot/bundler/requirement.rb
310
311
  - lib/dependabot/bundler/update_checker.rb
@@ -322,7 +323,7 @@ licenses:
322
323
  - MIT
323
324
  metadata:
324
325
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
325
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.302.0
326
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.304.0
326
327
  post_install_message:
327
328
  rdoc_options: []
328
329
  require_paths: