dependabot-uv 0.355.0 → 0.356.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 +4 -4
- data/helpers/requirements.txt +1 -1
- data/lib/dependabot/uv/file_fetcher/workspace_fetcher.rb +3 -2
- data/lib/dependabot/uv/file_fetcher.rb +62 -350
- data/lib/dependabot/uv/file_updater/compile_file_updater.rb +1 -1
- data/lib/dependabot/uv/file_updater/lock_file_updater.rb +85 -4
- data/lib/dependabot/uv/file_updater/requirement_file_updater.rb +6 -86
- data/lib/dependabot/uv/file_updater/requirement_replacer.rb +6 -247
- data/lib/dependabot/uv/update_checker/latest_version_finder.rb +5 -26
- data/lib/dependabot/uv/update_checker/pip_compile_version_resolver.rb +1 -1
- data/lib/dependabot/uv/update_checker/pip_version_resolver.rb +5 -107
- data/lib/dependabot/uv/update_checker/requirements_updater.rb +6 -439
- data/lib/dependabot/uv/update_checker.rb +21 -180
- metadata +6 -6
|
@@ -1,96 +1,16 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "dependabot/
|
|
4
|
+
require "dependabot/python/file_updater/requirement_file_updater"
|
|
5
5
|
require "dependabot/uv/file_updater"
|
|
6
|
-
require "dependabot/shared_helpers"
|
|
7
|
-
require "dependabot/uv/native_helpers"
|
|
8
|
-
require "sorbet-runtime"
|
|
9
6
|
|
|
10
7
|
module Dependabot
|
|
11
8
|
module Uv
|
|
12
9
|
class FileUpdater
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
sig { returns(T::Array[Dependency]) }
|
|
19
|
-
attr_reader :dependencies
|
|
20
|
-
|
|
21
|
-
sig { returns(T::Array[DependencyFile]) }
|
|
22
|
-
attr_reader :dependency_files
|
|
23
|
-
|
|
24
|
-
sig { returns(T::Array[Dependabot::Credential]) }
|
|
25
|
-
attr_reader :credentials
|
|
26
|
-
|
|
27
|
-
sig do
|
|
28
|
-
params(
|
|
29
|
-
dependencies: T::Array[Dependency],
|
|
30
|
-
dependency_files: T::Array[DependencyFile],
|
|
31
|
-
credentials: T::Array[Dependabot::Credential],
|
|
32
|
-
index_urls: T.nilable(T::Array[T.nilable(String)])
|
|
33
|
-
).void
|
|
34
|
-
end
|
|
35
|
-
def initialize(dependencies:, dependency_files:, credentials:, index_urls: nil)
|
|
36
|
-
@dependencies = dependencies
|
|
37
|
-
@dependency_files = dependency_files
|
|
38
|
-
@credentials = credentials
|
|
39
|
-
@index_urls = index_urls
|
|
40
|
-
@updated_dependency_files = T.let(nil, T.nilable(T::Array[DependencyFile]))
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
44
|
-
def updated_dependency_files
|
|
45
|
-
@updated_dependency_files ||= fetch_updated_dependency_files
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
sig { returns(Dependency) }
|
|
51
|
-
def dependency
|
|
52
|
-
# For now, we'll only ever be updating a single dependency
|
|
53
|
-
T.must(dependencies.first)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
sig { returns(T::Array[DependencyFile]) }
|
|
57
|
-
def fetch_updated_dependency_files
|
|
58
|
-
previous_requirements = dependency.previous_requirements || []
|
|
59
|
-
reqs = dependency.requirements.zip(previous_requirements)
|
|
60
|
-
|
|
61
|
-
reqs.filter_map do |(new_req, old_req)|
|
|
62
|
-
next if new_req == old_req
|
|
63
|
-
|
|
64
|
-
file = get_original_file(new_req.fetch(:file)).dup
|
|
65
|
-
updated_content =
|
|
66
|
-
updated_requirement_or_setup_file_content(new_req, T.must(old_req))
|
|
67
|
-
next if updated_content == file&.content
|
|
68
|
-
|
|
69
|
-
file&.content = updated_content
|
|
70
|
-
file
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
sig { params(new_req: T::Hash[Symbol, T.untyped], old_req: T::Hash[Symbol, T.untyped]).returns(String) }
|
|
75
|
-
def updated_requirement_or_setup_file_content(new_req, old_req)
|
|
76
|
-
original_file = get_original_file(new_req.fetch(:file))
|
|
77
|
-
raise "Could not find a dependency file for #{new_req}" unless original_file
|
|
78
|
-
|
|
79
|
-
RequirementReplacer.new(
|
|
80
|
-
content: T.must(original_file.content),
|
|
81
|
-
dependency_name: dependency.name,
|
|
82
|
-
old_requirement: old_req.fetch(:requirement),
|
|
83
|
-
new_requirement: new_req.fetch(:requirement),
|
|
84
|
-
new_hash_version: dependency.version,
|
|
85
|
-
index_urls: @index_urls
|
|
86
|
-
).updated_content
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
sig { params(filename: String).returns(T.nilable(DependencyFile)) }
|
|
90
|
-
def get_original_file(filename)
|
|
91
|
-
dependency_files.find { |f| f.name == filename }
|
|
92
|
-
end
|
|
93
|
-
end
|
|
10
|
+
# UV uses the same requirement file update logic as Python.
|
|
11
|
+
# Both ecosystems share RequirementReplacer and NativeHelpers
|
|
12
|
+
# via aliases, so we reuse Python's implementation.
|
|
13
|
+
RequirementFileUpdater = Dependabot::Python::FileUpdater::RequirementFileUpdater
|
|
94
14
|
end
|
|
95
15
|
end
|
|
96
16
|
end
|
|
@@ -1,257 +1,16 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "
|
|
5
|
-
|
|
6
|
-
require "dependabot/dependency"
|
|
7
|
-
require "dependabot/uv/requirement_parser"
|
|
4
|
+
require "dependabot/python/file_updater/requirement_replacer"
|
|
8
5
|
require "dependabot/uv/file_updater"
|
|
9
|
-
require "dependabot/shared_helpers"
|
|
10
|
-
require "dependabot/uv/native_helpers"
|
|
11
|
-
require "dependabot/uv/name_normaliser"
|
|
12
6
|
|
|
13
7
|
module Dependabot
|
|
14
8
|
module Uv
|
|
15
9
|
class FileUpdater
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
CERTIFICATE_VERIFY_FAILED = /CERTIFICATE_VERIFY_FAILED/
|
|
22
|
-
|
|
23
|
-
sig do
|
|
24
|
-
params(
|
|
25
|
-
content: String,
|
|
26
|
-
dependency_name: String,
|
|
27
|
-
old_requirement: T.nilable(String),
|
|
28
|
-
new_requirement: T.nilable(String),
|
|
29
|
-
new_hash_version: T.nilable(String),
|
|
30
|
-
index_urls: T.nilable(T::Array[T.nilable(String)])
|
|
31
|
-
).void
|
|
32
|
-
end
|
|
33
|
-
def initialize(
|
|
34
|
-
content:,
|
|
35
|
-
dependency_name:,
|
|
36
|
-
old_requirement:,
|
|
37
|
-
new_requirement:,
|
|
38
|
-
new_hash_version: nil,
|
|
39
|
-
index_urls: nil
|
|
40
|
-
)
|
|
41
|
-
@content = T.let(content, String)
|
|
42
|
-
@dependency_name = T.let(normalise(dependency_name), String)
|
|
43
|
-
@old_requirement = T.let(old_requirement, T.nilable(String))
|
|
44
|
-
@new_requirement = T.let(new_requirement, T.nilable(String))
|
|
45
|
-
@new_hash_version = T.let(new_hash_version, T.nilable(String))
|
|
46
|
-
@index_urls = T.let(index_urls, T.nilable(T::Array[T.nilable(String)]))
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
sig { returns(String) }
|
|
50
|
-
def updated_content
|
|
51
|
-
updated_content =
|
|
52
|
-
content.gsub(original_declaration_replacement_regex) do |mtch|
|
|
53
|
-
# If the "declaration" is setting an option (e.g., no-binary)
|
|
54
|
-
# ignore it, since it isn't actually a declaration
|
|
55
|
-
next mtch if Regexp.last_match&.pre_match&.match?(/--.*\z/)
|
|
56
|
-
|
|
57
|
-
updated_dependency_declaration_string
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
raise "Expected content to change!" if old_requirement != new_requirement && content == updated_content
|
|
61
|
-
|
|
62
|
-
updated_content
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
private
|
|
66
|
-
|
|
67
|
-
sig { returns(String) }
|
|
68
|
-
attr_reader :content
|
|
69
|
-
|
|
70
|
-
sig { returns(String) }
|
|
71
|
-
attr_reader :dependency_name
|
|
72
|
-
|
|
73
|
-
sig { returns(T.nilable(String)) }
|
|
74
|
-
attr_reader :old_requirement
|
|
75
|
-
|
|
76
|
-
sig { returns(T.nilable(String)) }
|
|
77
|
-
attr_reader :new_requirement
|
|
78
|
-
|
|
79
|
-
sig { returns(T.nilable(String)) }
|
|
80
|
-
attr_reader :new_hash_version
|
|
81
|
-
|
|
82
|
-
sig { returns(T::Boolean) }
|
|
83
|
-
def update_hashes?
|
|
84
|
-
!new_hash_version.nil?
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
sig { returns(T.nilable(String)) }
|
|
88
|
-
def updated_requirement_string
|
|
89
|
-
new_req_string = new_requirement
|
|
90
|
-
|
|
91
|
-
new_req_string = new_req_string&.gsub(/,\s*/, ", ") if add_space_after_commas?
|
|
92
|
-
|
|
93
|
-
if add_space_after_operators?
|
|
94
|
-
new_req_string =
|
|
95
|
-
new_req_string
|
|
96
|
-
&.gsub(/(#{RequirementParser::COMPARISON})\s*(?=\d)/o, '\1 ')
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
new_req_string
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
sig { returns(String) }
|
|
103
|
-
def updated_dependency_declaration_string
|
|
104
|
-
old_req = old_requirement
|
|
105
|
-
updated_string =
|
|
106
|
-
if old_req
|
|
107
|
-
original_dependency_declaration_string(old_req)
|
|
108
|
-
.sub(RequirementParser::REQUIREMENTS, updated_requirement_string || "")
|
|
109
|
-
else
|
|
110
|
-
original_dependency_declaration_string(old_req)
|
|
111
|
-
.sub(RequirementParser::NAME_WITH_EXTRAS) do |nm|
|
|
112
|
-
nm + (updated_requirement_string || "")
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
return updated_string unless update_hashes? && requirement_includes_hashes?(old_req)
|
|
117
|
-
|
|
118
|
-
updated_string.sub(
|
|
119
|
-
RequirementParser::HASHES,
|
|
120
|
-
package_hashes_for(
|
|
121
|
-
name: dependency_name,
|
|
122
|
-
version: new_hash_version,
|
|
123
|
-
algorithm: hash_algorithm(old_req)
|
|
124
|
-
).join(hash_separator(old_req) || "")
|
|
125
|
-
)
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
sig { returns(T::Boolean) }
|
|
129
|
-
def add_space_after_commas?
|
|
130
|
-
original_dependency_declaration_string(old_requirement)
|
|
131
|
-
.match(RequirementParser::REQUIREMENTS)
|
|
132
|
-
.to_s.include?(", ")
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
sig { returns(T::Boolean) }
|
|
136
|
-
def add_space_after_operators?
|
|
137
|
-
original_dependency_declaration_string(old_requirement)
|
|
138
|
-
.match(RequirementParser::REQUIREMENTS)
|
|
139
|
-
.to_s.match?(/#{RequirementParser::COMPARISON}\s+\d/o)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
sig { returns(Regexp) }
|
|
143
|
-
def original_declaration_replacement_regex
|
|
144
|
-
original_string =
|
|
145
|
-
original_dependency_declaration_string(old_requirement)
|
|
146
|
-
/(?<![\-\w\.\[])#{Regexp.escape(original_string)}(?![\-\w\.])/
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
sig { params(requirement: T.nilable(String)).returns(T::Boolean) }
|
|
150
|
-
def requirement_includes_hashes?(requirement)
|
|
151
|
-
original_dependency_declaration_string(requirement)
|
|
152
|
-
.match?(RequirementParser::HASHES)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
sig { params(requirement: T.nilable(String)).returns(T.nilable(String)) }
|
|
156
|
-
def hash_algorithm(requirement)
|
|
157
|
-
return unless requirement_includes_hashes?(requirement)
|
|
158
|
-
|
|
159
|
-
matches = original_dependency_declaration_string(requirement).match(RequirementParser::HASHES)
|
|
160
|
-
return unless matches
|
|
161
|
-
|
|
162
|
-
matches.named_captures.fetch("algorithm")
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
sig { params(requirement: T.nilable(String)).returns(T.nilable(String)) }
|
|
166
|
-
def hash_separator(requirement)
|
|
167
|
-
return unless requirement_includes_hashes?(requirement)
|
|
168
|
-
|
|
169
|
-
hash_regex = RequirementParser::HASH
|
|
170
|
-
match_result = original_dependency_declaration_string(requirement)
|
|
171
|
-
.match(/#{hash_regex}((?<separator>\s*\\?\s*?)#{hash_regex})*/)
|
|
172
|
-
current_separator = match_result&.named_captures&.fetch("separator", nil)
|
|
173
|
-
|
|
174
|
-
default_match = original_dependency_declaration_string(requirement)
|
|
175
|
-
.match(RequirementParser::HASH)
|
|
176
|
-
default_separator = default_match&.pre_match&.match(/(?<separator>\s*\\?\s*?)\z/)
|
|
177
|
-
&.named_captures&.fetch("separator", nil)
|
|
178
|
-
|
|
179
|
-
current_separator || default_separator
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
sig { params(name: String, version: T.nilable(String), algorithm: T.nilable(String)).returns(T::Array[String]) }
|
|
183
|
-
def package_hashes_for(name:, version:, algorithm:)
|
|
184
|
-
index_urls = @index_urls || [nil]
|
|
185
|
-
|
|
186
|
-
index_urls.map do |index_url|
|
|
187
|
-
args = [name, version, algorithm]
|
|
188
|
-
args << index_url unless index_url.nil?
|
|
189
|
-
|
|
190
|
-
begin
|
|
191
|
-
result = SharedHelpers.run_helper_subprocess(
|
|
192
|
-
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
193
|
-
function: "get_dependency_hash",
|
|
194
|
-
args: args
|
|
195
|
-
)
|
|
196
|
-
rescue SharedHelpers::HelperSubprocessFailed => e
|
|
197
|
-
requirement_error_handler(e)
|
|
198
|
-
|
|
199
|
-
raise unless e.message.include?("PackageNotFoundError")
|
|
200
|
-
|
|
201
|
-
next
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
return result.map { |h| "--hash=#{algorithm}:#{h['hash']}" } if result.is_a?(Array)
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
raise Dependabot::DependencyFileNotResolvable, "Unable to find hashes for package #{name}"
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
sig { params(old_req: T.nilable(String)).returns(String) }
|
|
211
|
-
def original_dependency_declaration_string(old_req)
|
|
212
|
-
matches = []
|
|
213
|
-
|
|
214
|
-
dec =
|
|
215
|
-
if old_req.nil?
|
|
216
|
-
regex = RequirementParser::INSTALL_REQ_WITHOUT_REQUIREMENT
|
|
217
|
-
content.scan(regex) { matches << Regexp.last_match }
|
|
218
|
-
matches.find { |m| normalise(m[:name]) == dependency_name }
|
|
219
|
-
else
|
|
220
|
-
regex = RequirementParser::INSTALL_REQ_WITH_REQUIREMENT
|
|
221
|
-
content.scan(regex) { matches << Regexp.last_match }
|
|
222
|
-
matches
|
|
223
|
-
.select { |m| normalise(m[:name]) == dependency_name }
|
|
224
|
-
.find { |m| requirements_match(m[:requirements], old_req) }
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
raise "Declaration not found for #{dependency_name}!" unless dec
|
|
228
|
-
|
|
229
|
-
dec.to_s.strip
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
sig { params(name: String).returns(String) }
|
|
233
|
-
def normalise(name)
|
|
234
|
-
NameNormaliser.normalise(name)
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
sig { params(req1: T.nilable(String), req2: T.nilable(String)).returns(T::Boolean) }
|
|
238
|
-
def requirements_match(req1, req2)
|
|
239
|
-
req1&.split(",")&.map { |r| r.gsub(/\s/, "") }&.sort ==
|
|
240
|
-
req2&.split(",")&.map { |r| r.gsub(/\s/, "") }&.sort
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
public
|
|
244
|
-
|
|
245
|
-
sig { params(error: Exception).void }
|
|
246
|
-
def requirement_error_handler(error)
|
|
247
|
-
Dependabot.logger.warn(error.message)
|
|
248
|
-
|
|
249
|
-
return unless error.message.match?(CERTIFICATE_VERIFY_FAILED)
|
|
250
|
-
|
|
251
|
-
msg = "Error resolving dependency."
|
|
252
|
-
raise DependencyFileNotResolvable, msg
|
|
253
|
-
end
|
|
254
|
-
end
|
|
10
|
+
# UV uses the same requirement replacement logic as Python.
|
|
11
|
+
# Both ecosystems share RequirementParser, NativeHelpers, and NameNormaliser
|
|
12
|
+
# via aliases, so we reuse Python's implementation.
|
|
13
|
+
RequirementReplacer = Dependabot::Python::FileUpdater::RequirementReplacer
|
|
255
14
|
end
|
|
256
15
|
end
|
|
257
16
|
end
|
|
@@ -1,37 +1,16 @@
|
|
|
1
1
|
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "
|
|
4
|
+
require "dependabot/python/update_checker/latest_version_finder"
|
|
5
5
|
require "dependabot/uv/update_checker"
|
|
6
|
-
require "dependabot/uv/package"
|
|
7
|
-
require "dependabot/package/package_latest_version_finder"
|
|
8
6
|
|
|
9
7
|
module Dependabot
|
|
10
8
|
module Uv
|
|
11
9
|
class UpdateChecker
|
|
12
|
-
# UV uses the same PyPI registry for package lookups as Python
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
sig do
|
|
17
|
-
override.returns(T.nilable(Dependabot::Package::PackageDetails))
|
|
18
|
-
end
|
|
19
|
-
def package_details
|
|
20
|
-
@package_details ||= T.let(
|
|
21
|
-
Package::PackageDetailsFetcher.new(
|
|
22
|
-
dependency: dependency,
|
|
23
|
-
dependency_files: dependency_files,
|
|
24
|
-
credentials: credentials
|
|
25
|
-
).fetch,
|
|
26
|
-
T.nilable(Dependabot::Package::PackageDetails)
|
|
27
|
-
)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
sig { override.returns(T::Boolean) }
|
|
31
|
-
def cooldown_enabled?
|
|
32
|
-
true
|
|
33
|
-
end
|
|
34
|
-
end
|
|
10
|
+
# UV uses the same PyPI registry for package lookups as Python.
|
|
11
|
+
# Both ecosystems use the same PackageDetailsFetcher (via Uv::Package alias)
|
|
12
|
+
# and identical LatestVersionFinder logic, so we reuse Python's implementation.
|
|
13
|
+
LatestVersionFinder = Dependabot::Python::UpdateChecker::LatestVersionFinder
|
|
35
14
|
end
|
|
36
15
|
end
|
|
37
16
|
end
|
|
@@ -497,7 +497,7 @@ module Dependabot
|
|
|
497
497
|
|
|
498
498
|
sig { returns(T::Hash[String, T::Array[String]]) }
|
|
499
499
|
def requirement_map
|
|
500
|
-
child_req_regex =
|
|
500
|
+
child_req_regex = Python::SharedFileFetcher::CHILD_REQUIREMENT_REGEX
|
|
501
501
|
@requirement_map ||= T.let(
|
|
502
502
|
pip_compile_files.each_with_object({}) do |file, req_map|
|
|
503
503
|
paths = T.must(file.content).scan(child_req_regex).flatten
|
|
@@ -1,118 +1,16 @@
|
|
|
1
1
|
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "
|
|
5
|
-
|
|
6
|
-
require "dependabot/uv/language_version_manager"
|
|
4
|
+
require "dependabot/python/update_checker/pip_version_resolver"
|
|
7
5
|
require "dependabot/uv/update_checker"
|
|
8
|
-
require "dependabot/uv/update_checker/latest_version_finder"
|
|
9
|
-
require "dependabot/uv/file_parser/python_requirement_parser"
|
|
10
6
|
|
|
11
7
|
module Dependabot
|
|
12
8
|
module Uv
|
|
13
9
|
class UpdateChecker
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
params(
|
|
19
|
-
dependency: Dependabot::Dependency,
|
|
20
|
-
dependency_files: T::Array[Dependabot::DependencyFile],
|
|
21
|
-
credentials: T::Array[Dependabot::Credential],
|
|
22
|
-
ignored_versions: T::Array[String],
|
|
23
|
-
security_advisories: T::Array[Dependabot::SecurityAdvisory],
|
|
24
|
-
update_cooldown: T.nilable(Dependabot::Package::ReleaseCooldownOptions),
|
|
25
|
-
raise_on_ignored: T::Boolean
|
|
26
|
-
).void
|
|
27
|
-
end
|
|
28
|
-
def initialize(
|
|
29
|
-
dependency:,
|
|
30
|
-
dependency_files:,
|
|
31
|
-
credentials:,
|
|
32
|
-
ignored_versions:,
|
|
33
|
-
security_advisories:,
|
|
34
|
-
update_cooldown: nil,
|
|
35
|
-
raise_on_ignored: false
|
|
36
|
-
)
|
|
37
|
-
@dependency = T.let(dependency, Dependabot::Dependency)
|
|
38
|
-
@dependency_files = T.let(dependency_files, T::Array[Dependabot::DependencyFile])
|
|
39
|
-
@credentials = T.let(credentials, T::Array[Dependabot::Credential])
|
|
40
|
-
@ignored_versions = T.let(ignored_versions, T::Array[String])
|
|
41
|
-
@update_cooldown = T.let(update_cooldown, T.nilable(Dependabot::Package::ReleaseCooldownOptions))
|
|
42
|
-
@raise_on_ignored = T.let(raise_on_ignored, T::Boolean)
|
|
43
|
-
@security_advisories = T.let(security_advisories, T::Array[Dependabot::SecurityAdvisory])
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
sig { returns(T.nilable(Dependabot::Version)) }
|
|
47
|
-
def latest_resolvable_version
|
|
48
|
-
latest_version_finder.latest_version(language_version: language_version_manager.python_version)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
sig { returns(T.nilable(Dependabot::Version)) }
|
|
52
|
-
def latest_resolvable_version_with_no_unlock
|
|
53
|
-
latest_version_finder
|
|
54
|
-
.latest_version_with_no_unlock(language_version: language_version_manager.python_version)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
sig { returns(T.nilable(Dependabot::Version)) }
|
|
58
|
-
def lowest_resolvable_security_fix_version
|
|
59
|
-
latest_version_finder
|
|
60
|
-
.lowest_security_fix_version(language_version: language_version_manager.python_version)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
sig { returns(Dependabot::Dependency) }
|
|
66
|
-
attr_reader :dependency
|
|
67
|
-
|
|
68
|
-
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
69
|
-
attr_reader :dependency_files
|
|
70
|
-
|
|
71
|
-
sig { returns(T::Array[Dependabot::Credential]) }
|
|
72
|
-
attr_reader :credentials
|
|
73
|
-
|
|
74
|
-
sig { returns(T::Array[String]) }
|
|
75
|
-
attr_reader :ignored_versions
|
|
76
|
-
|
|
77
|
-
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
|
78
|
-
attr_reader :security_advisories
|
|
79
|
-
|
|
80
|
-
sig { returns(LatestVersionFinder) }
|
|
81
|
-
def latest_version_finder
|
|
82
|
-
@latest_version_finder ||= T.let(
|
|
83
|
-
LatestVersionFinder.new(
|
|
84
|
-
dependency: dependency,
|
|
85
|
-
dependency_files: dependency_files,
|
|
86
|
-
credentials: credentials,
|
|
87
|
-
ignored_versions: ignored_versions,
|
|
88
|
-
raise_on_ignored: @raise_on_ignored,
|
|
89
|
-
cooldown_options: @update_cooldown,
|
|
90
|
-
security_advisories: security_advisories
|
|
91
|
-
),
|
|
92
|
-
T.nilable(LatestVersionFinder)
|
|
93
|
-
)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
sig { returns(FileParser::PythonRequirementParser) }
|
|
97
|
-
def python_requirement_parser
|
|
98
|
-
@python_requirement_parser ||= T.let(
|
|
99
|
-
FileParser::PythonRequirementParser.new(
|
|
100
|
-
dependency_files: dependency_files
|
|
101
|
-
),
|
|
102
|
-
T.nilable(FileParser::PythonRequirementParser)
|
|
103
|
-
)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
sig { returns(LanguageVersionManager) }
|
|
107
|
-
def language_version_manager
|
|
108
|
-
@language_version_manager ||= T.let(
|
|
109
|
-
LanguageVersionManager.new(
|
|
110
|
-
python_requirement_parser: python_requirement_parser
|
|
111
|
-
),
|
|
112
|
-
T.nilable(LanguageVersionManager)
|
|
113
|
-
)
|
|
114
|
-
end
|
|
115
|
-
end
|
|
10
|
+
# UV uses the same pip version resolution logic as Python.
|
|
11
|
+
# Both ecosystems share LanguageVersionManager, LatestVersionFinder,
|
|
12
|
+
# and PythonRequirementParser via aliases, so we reuse Python's implementation.
|
|
13
|
+
PipVersionResolver = Dependabot::Python::UpdateChecker::PipVersionResolver
|
|
116
14
|
end
|
|
117
15
|
end
|
|
118
16
|
end
|