dependabot-uv 0.393.0 → 0.395.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 +5 -5
- data/lib/dependabot/uv/file_parser/pyproject_files_parser.rb +122 -89
- data/lib/dependabot/uv/file_updater/compile_file_updater.rb +13 -7
- data/lib/dependabot/uv/file_updater/lock_file_updater.rb +26 -6
- data/lib/dependabot/uv/file_updater/version_config_parser.rb +48 -15
- data/lib/dependabot/uv/update_checker/lock_file_resolver.rb +228 -14
- data/lib/dependabot/uv/update_checker/pip_compile_version_resolver.rb +1 -2
- data/lib/dependabot/uv/update_checker.rb +3 -3
- metadata +11 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c5e87aed24a3d0d1e38f69d064fa0d05ea3aa5db358ffe8b8aca51b0ba814f41
|
|
4
|
+
data.tar.gz: a79f5e14f753586b9a66310917f590bf7ac1065318cbd9f18cecf43c54a4ae24
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e5c993116408e7948b8d4622ad7d76e1a9a4a9fde594072883d0dd1d8e8275531a5f4d2be045fb599b61f26577d72bee2e1111a226fccb39f73058d826f66e1f
|
|
7
|
+
data.tar.gz: 3fb63ce5867dc87ee0ee729cb97d67c88069517f31b046d46ca9db30e27138d617af03499392543360bab156018b2ef67550d3b49c7f041468611acf50ad0097
|
data/helpers/requirements.txt
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
pip==26.
|
|
2
|
-
pip-tools==7.
|
|
1
|
+
pip==26.2.1
|
|
2
|
+
pip-tools==7.6.1
|
|
3
3
|
flake8==7.3.0
|
|
4
4
|
hashin==1.0.5
|
|
5
5
|
pipenv==2024.4.1
|
|
6
6
|
plette==2.2.1
|
|
7
|
-
poetry==2.
|
|
7
|
+
poetry==2.4.1
|
|
8
8
|
# TODO: Replace 3p package `tomli` with 3.11's new stdlib `tomllib` once we drop support for Python 3.10.
|
|
9
9
|
tomli==2.4.1
|
|
10
|
-
uv==0.12.
|
|
10
|
+
uv==0.12.7
|
|
11
11
|
|
|
12
12
|
# Some dependencies will only install if Cython is present
|
|
13
|
-
Cython==3.
|
|
13
|
+
Cython==3.3.0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "toml-rb"
|
|
@@ -9,6 +9,9 @@ require "dependabot/uv/file_parser"
|
|
|
9
9
|
require "dependabot/uv/requirement"
|
|
10
10
|
require "dependabot/errors"
|
|
11
11
|
require "dependabot/uv/name_normaliser"
|
|
12
|
+
require "dependabot/python/file_parser/pep_dependency"
|
|
13
|
+
require "dependabot/python/file_parser/poetry_lock"
|
|
14
|
+
require "dependabot/python/file_parser/pyproject_document"
|
|
12
15
|
|
|
13
16
|
module Dependabot
|
|
14
17
|
module Uv
|
|
@@ -16,6 +19,10 @@ module Dependabot
|
|
|
16
19
|
class PyprojectFilesParser
|
|
17
20
|
extend T::Sig
|
|
18
21
|
|
|
22
|
+
PepDependency = Dependabot::Python::FileParser::PepDependency
|
|
23
|
+
PoetryLock = Dependabot::Python::FileParser::PoetryLock
|
|
24
|
+
PyprojectDocument = Dependabot::Python::FileParser::PyprojectDocument
|
|
25
|
+
|
|
19
26
|
POETRY_DEPENDENCY_TYPES = %w(dependencies dev-dependencies).freeze
|
|
20
27
|
|
|
21
28
|
# https://python-poetry.org/docs/dependency-specification/
|
|
@@ -24,6 +31,8 @@ module Dependabot
|
|
|
24
31
|
sig { params(dependency_files: T::Array[Dependabot::DependencyFile]).void }
|
|
25
32
|
def initialize(dependency_files:)
|
|
26
33
|
@dependency_files = dependency_files
|
|
34
|
+
@pyproject_document = T.let(nil, T.nilable(PyprojectDocument))
|
|
35
|
+
@poetry_lock_document = T.let(nil, T.nilable(PoetryLock))
|
|
27
36
|
end
|
|
28
37
|
|
|
29
38
|
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
|
@@ -61,13 +70,11 @@ module Dependabot
|
|
|
61
70
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
|
62
71
|
|
|
63
72
|
POETRY_DEPENDENCY_TYPES.each do |type|
|
|
64
|
-
|
|
65
|
-
dependencies += parse_poetry_dependency_group(type, deps_hash)
|
|
73
|
+
dependencies += parse_poetry_dependency_group(type, pyproject_document.poetry_dependencies(type))
|
|
66
74
|
end
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
dependencies += parse_poetry_dependency_group(group, group_spec["dependencies"])
|
|
76
|
+
pyproject_document.poetry_groups.each do |group, dependencies_by_name|
|
|
77
|
+
dependencies += parse_poetry_dependency_group(group, dependencies_by_name)
|
|
71
78
|
end
|
|
72
79
|
dependencies
|
|
73
80
|
end
|
|
@@ -85,20 +92,20 @@ module Dependabot
|
|
|
85
92
|
parse_pep621_pep735_dependencies(pyproject_file).each do |dep|
|
|
86
93
|
# If a requirement has a `<` or `<=` marker then updating it is
|
|
87
94
|
# probably blocked. Ignore it.
|
|
88
|
-
next if dep
|
|
95
|
+
next if dep.markers&.include?("<")
|
|
89
96
|
|
|
90
97
|
# In uv no constraint means any version is acceptable
|
|
91
|
-
requirement_value = dep
|
|
98
|
+
requirement_value = dep.requirement == "" ? "*" : dep.requirement
|
|
92
99
|
|
|
93
100
|
dependencies <<
|
|
94
101
|
Dependency.new(
|
|
95
|
-
name: normalised_name(dep
|
|
96
|
-
version: dep
|
|
102
|
+
name: normalised_name(dep.name, dep.extras),
|
|
103
|
+
version: dep.version&.include?("*") ? nil : dep.version,
|
|
97
104
|
requirements: [{
|
|
98
105
|
requirement: requirement_value,
|
|
99
|
-
file: Pathname.new(dep
|
|
106
|
+
file: Pathname.new(dep.file).cleanpath.to_path,
|
|
100
107
|
source: nil,
|
|
101
|
-
groups: [dep
|
|
108
|
+
groups: [dep.requirement_type].compact
|
|
102
109
|
}],
|
|
103
110
|
package_manager: "uv"
|
|
104
111
|
)
|
|
@@ -139,8 +146,7 @@ module Dependabot
|
|
|
139
146
|
def workspace_globs(key)
|
|
140
147
|
return [] unless pyproject
|
|
141
148
|
|
|
142
|
-
|
|
143
|
-
globs.is_a?(Array) ? globs.grep(String) : []
|
|
149
|
+
pyproject_document.workspace_globs(key)
|
|
144
150
|
end
|
|
145
151
|
|
|
146
152
|
sig { params(file: Dependabot::DependencyFile).returns(T::Boolean) }
|
|
@@ -172,17 +178,16 @@ module Dependabot
|
|
|
172
178
|
sig do
|
|
173
179
|
params(
|
|
174
180
|
type: String,
|
|
175
|
-
deps_hash:
|
|
176
|
-
T.untyped]
|
|
181
|
+
deps_hash: PyprojectDocument::PoetryDependencyMap
|
|
177
182
|
).returns(Dependabot::FileParsers::Base::DependencySet)
|
|
178
183
|
end
|
|
179
184
|
def parse_poetry_dependency_group(type, deps_hash)
|
|
180
185
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
|
181
186
|
|
|
182
|
-
deps_hash.each do |name,
|
|
187
|
+
deps_hash.each do |name, requirements_data|
|
|
183
188
|
next if normalise(name) == "python"
|
|
184
189
|
|
|
185
|
-
requirements = parse_requirements_from(
|
|
190
|
+
requirements = parse_requirements_from(requirements_data, type)
|
|
186
191
|
next if requirements.empty?
|
|
187
192
|
|
|
188
193
|
dependencies << Dependency.new(
|
|
@@ -200,57 +205,62 @@ module Dependabot
|
|
|
200
205
|
NameNormaliser.normalise_including_extras(name, extras)
|
|
201
206
|
end
|
|
202
207
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
+
sig do
|
|
209
|
+
params(
|
|
210
|
+
requirements_data: T::Array[PyprojectDocument::PoetryRequirement],
|
|
211
|
+
type: String
|
|
212
|
+
).returns(T::Array[Dependabot::Dependency::RequirementInput])
|
|
213
|
+
end
|
|
214
|
+
def parse_requirements_from(requirements_data, type)
|
|
215
|
+
requirements_data.filter_map { |requirement| poetry_requirement(requirement, type) }
|
|
216
|
+
end
|
|
208
217
|
|
|
218
|
+
sig do
|
|
219
|
+
params(
|
|
220
|
+
requirement: PyprojectDocument::PoetryRequirement,
|
|
221
|
+
type: String
|
|
222
|
+
).returns(T.nilable(Dependabot::Dependency::RequirementInput))
|
|
223
|
+
end
|
|
224
|
+
def poetry_requirement(requirement, type)
|
|
225
|
+
if requirement.is_a?(String)
|
|
209
226
|
check_requirements(requirement)
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
groups: [type]
|
|
217
|
-
}
|
|
218
|
-
else
|
|
219
|
-
{
|
|
220
|
-
requirement: requirement["version"],
|
|
221
|
-
file: T.must(pyproject).name,
|
|
222
|
-
source: requirement.fetch("source", nil),
|
|
223
|
-
groups: [type]
|
|
224
|
-
}
|
|
225
|
-
end
|
|
227
|
+
return {
|
|
228
|
+
requirement: requirement,
|
|
229
|
+
file: T.must(pyproject).name,
|
|
230
|
+
source: nil,
|
|
231
|
+
groups: [type]
|
|
232
|
+
}
|
|
226
233
|
end
|
|
234
|
+
|
|
235
|
+
return if UNSUPPORTED_DEPENDENCY_TYPES.intersect?(requirement.keys)
|
|
236
|
+
|
|
237
|
+
check_requirements(requirement)
|
|
238
|
+
{
|
|
239
|
+
requirement: requirement_string(requirement, "version"),
|
|
240
|
+
file: T.must(pyproject).name,
|
|
241
|
+
source: poetry_source(requirement["source"]),
|
|
242
|
+
groups: [type]
|
|
243
|
+
}
|
|
227
244
|
end
|
|
228
245
|
|
|
229
|
-
sig { returns(T
|
|
246
|
+
sig { returns(T::Boolean) }
|
|
230
247
|
def using_poetry?
|
|
231
|
-
|
|
248
|
+
pyproject_document.poetry?
|
|
232
249
|
end
|
|
233
250
|
|
|
234
251
|
sig { returns(T::Boolean) }
|
|
235
252
|
def using_pep621?
|
|
236
|
-
|
|
237
|
-
!parsed_pyproject.dig("project", "optional-dependencies").nil? ||
|
|
238
|
-
!parsed_pyproject.dig("build-system", "requires").nil?
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
sig { returns(T.nilable(T::Hash[String, T.untyped])) }
|
|
242
|
-
def poetry_root
|
|
243
|
-
parsed_pyproject.dig("tool", "poetry")
|
|
253
|
+
pyproject_document.pep621?
|
|
244
254
|
end
|
|
245
255
|
|
|
246
256
|
sig { returns(T::Boolean) }
|
|
247
257
|
def using_pep735?
|
|
248
|
-
|
|
258
|
+
pyproject_document.pep735?
|
|
249
259
|
end
|
|
250
260
|
|
|
251
|
-
sig { returns(T
|
|
261
|
+
sig { returns(T::Boolean) }
|
|
252
262
|
def using_pdm?
|
|
253
|
-
using_pep621? && pdm_lock
|
|
263
|
+
using_pep621? && !pdm_lock.nil?
|
|
254
264
|
end
|
|
255
265
|
|
|
256
266
|
# Create a DependencySet where each element has no requirement. Any
|
|
@@ -261,15 +271,15 @@ module Dependabot
|
|
|
261
271
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
|
262
272
|
|
|
263
273
|
source_types = %w(directory git url)
|
|
264
|
-
|
|
265
|
-
next if source_types.include?(
|
|
274
|
+
poetry_lock_document.packages.each do |package|
|
|
275
|
+
next if source_types.include?(package.source_type)
|
|
266
276
|
|
|
267
|
-
name = normalise(
|
|
277
|
+
name = normalise(package.name)
|
|
268
278
|
|
|
269
279
|
dependencies <<
|
|
270
280
|
Dependency.new(
|
|
271
281
|
name: name,
|
|
272
|
-
version:
|
|
282
|
+
version: package.version,
|
|
273
283
|
requirements: [],
|
|
274
284
|
package_manager: "uv",
|
|
275
285
|
subdependency_metadata: [{
|
|
@@ -292,8 +302,10 @@ module Dependabot
|
|
|
292
302
|
sig { returns(T::Array[T.nilable(String)]) }
|
|
293
303
|
def parse_production_dependency_names
|
|
294
304
|
SharedHelpers.in_a_temporary_directory do
|
|
295
|
-
|
|
296
|
-
|
|
305
|
+
pyproject_file = T.must(pyproject)
|
|
306
|
+
lockfile_file = T.must(lockfile)
|
|
307
|
+
File.write(pyproject_file.name, pyproject_file.content)
|
|
308
|
+
File.write(lockfile_file.name, lockfile_file.content)
|
|
297
309
|
|
|
298
310
|
begin
|
|
299
311
|
output = SharedHelpers.run_shell_command("pyenv exec poetry show --only main")
|
|
@@ -312,18 +324,19 @@ module Dependabot
|
|
|
312
324
|
end
|
|
313
325
|
end
|
|
314
326
|
|
|
315
|
-
sig { params(dep_name: String).returns(T.
|
|
327
|
+
sig { params(dep_name: String).returns(T.nilable(String)) }
|
|
316
328
|
def version_from_lockfile(dep_name)
|
|
317
|
-
return unless
|
|
329
|
+
return unless poetry_lock
|
|
318
330
|
|
|
319
|
-
|
|
320
|
-
.find { |p| normalise(p.fetch("name")) == normalise(dep_name) }
|
|
321
|
-
&.fetch("version", nil)
|
|
331
|
+
poetry_lock_document.version_for(dep_name) { |name| normalise(name) }
|
|
322
332
|
end
|
|
323
333
|
|
|
324
|
-
sig
|
|
334
|
+
sig do
|
|
335
|
+
params(req: PyprojectDocument::PoetryRequirement)
|
|
336
|
+
.returns(T::Array[Dependabot::Uv::Requirement])
|
|
337
|
+
end
|
|
325
338
|
def check_requirements(req)
|
|
326
|
-
requirement = req.is_a?(String) ? req : req
|
|
339
|
+
requirement = req.is_a?(String) ? req : requirement_string(req, "version")
|
|
327
340
|
Uv::Requirement.requirements_array(requirement)
|
|
328
341
|
rescue Gem::Requirement::BadRequirementError => e
|
|
329
342
|
raise Dependabot::DependencyFileNotEvaluatable, e.message
|
|
@@ -334,21 +347,14 @@ module Dependabot
|
|
|
334
347
|
NameNormaliser.normalise(name)
|
|
335
348
|
end
|
|
336
349
|
|
|
337
|
-
sig { returns(
|
|
338
|
-
def
|
|
339
|
-
@
|
|
340
|
-
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
|
341
|
-
raise Dependabot::DependencyFileNotParseable, T.must(pyproject).path
|
|
350
|
+
sig { returns(PyprojectDocument) }
|
|
351
|
+
def pyproject_document
|
|
352
|
+
@pyproject_document ||= PyprojectDocument.from_file(T.must(pyproject))
|
|
342
353
|
end
|
|
343
354
|
|
|
344
|
-
sig { returns(
|
|
345
|
-
def
|
|
346
|
-
@
|
|
347
|
-
TomlRB.parse(T.must(poetry_lock).content),
|
|
348
|
-
T.nilable(T::Hash[String, T.untyped])
|
|
349
|
-
)
|
|
350
|
-
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
|
351
|
-
raise Dependabot::DependencyFileNotParseable, T.must(poetry_lock).path
|
|
355
|
+
sig { returns(PoetryLock) }
|
|
356
|
+
def poetry_lock_document
|
|
357
|
+
@poetry_lock_document ||= PoetryLock.from_file(T.must(poetry_lock))
|
|
352
358
|
end
|
|
353
359
|
|
|
354
360
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
@@ -359,20 +365,22 @@ module Dependabot
|
|
|
359
365
|
)
|
|
360
366
|
end
|
|
361
367
|
|
|
362
|
-
sig { returns(T.
|
|
368
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
363
369
|
def lockfile
|
|
364
370
|
poetry_lock
|
|
365
371
|
end
|
|
366
372
|
|
|
367
|
-
sig { params(pyproject_file: Dependabot::DependencyFile).returns(T
|
|
373
|
+
sig { params(pyproject_file: Dependabot::DependencyFile).returns(T::Array[PepDependency]) }
|
|
368
374
|
def parse_pep621_pep735_dependencies(pyproject_file)
|
|
369
375
|
SharedHelpers.in_a_temporary_directory do
|
|
370
376
|
write_temporary_pyproject(pyproject_file)
|
|
371
377
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
378
|
+
PepDependency.from_helper_result(
|
|
379
|
+
SharedHelpers.run_helper_subprocess(
|
|
380
|
+
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
381
|
+
function: "parse_pep621_pep735_dependencies",
|
|
382
|
+
args: [pyproject_file.name]
|
|
383
|
+
)
|
|
376
384
|
)
|
|
377
385
|
end
|
|
378
386
|
end
|
|
@@ -384,11 +392,6 @@ module Dependabot
|
|
|
384
392
|
File.write(path, pyproject_file.content)
|
|
385
393
|
end
|
|
386
394
|
|
|
387
|
-
sig { returns(T.untyped) }
|
|
388
|
-
def parsed_lockfile
|
|
389
|
-
parsed_poetry_lock if poetry_lock
|
|
390
|
-
end
|
|
391
|
-
|
|
392
395
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
393
396
|
def poetry_lock
|
|
394
397
|
@poetry_lock ||= T.let(
|
|
@@ -397,6 +400,36 @@ module Dependabot
|
|
|
397
400
|
)
|
|
398
401
|
end
|
|
399
402
|
|
|
403
|
+
sig do
|
|
404
|
+
params(
|
|
405
|
+
requirement: T::Hash[String, Object],
|
|
406
|
+
key: String
|
|
407
|
+
).returns(T.nilable(String))
|
|
408
|
+
end
|
|
409
|
+
def requirement_string(requirement, key)
|
|
410
|
+
value = requirement[key]
|
|
411
|
+
return if value.nil?
|
|
412
|
+
return value if value.is_a?(String)
|
|
413
|
+
|
|
414
|
+
raise TypeError, "Poetry dependency #{key} must be a string or nil"
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
sig { params(value: T.nilable(Object)).returns(T.nilable(Dependabot::DependencyRequirement::Source)) }
|
|
418
|
+
def poetry_source(value)
|
|
419
|
+
return if value.nil?
|
|
420
|
+
return value if value.is_a?(String)
|
|
421
|
+
raise TypeError, "Poetry dependency source must be a string, object, or nil" unless value.is_a?(Hash)
|
|
422
|
+
|
|
423
|
+
source = T.let({}, Dependabot::DependencyRequirement::ObjectHash)
|
|
424
|
+
value.each do |raw_key, raw_value|
|
|
425
|
+
key = T.cast(raw_key, Object)
|
|
426
|
+
raise TypeError, "Poetry dependency source keys must be strings" unless key.is_a?(String)
|
|
427
|
+
|
|
428
|
+
source[key] = T.cast(raw_value, Object)
|
|
429
|
+
end
|
|
430
|
+
source
|
|
431
|
+
end
|
|
432
|
+
|
|
400
433
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
401
434
|
def pdm_lock
|
|
402
435
|
@pdm_lock ||= T.let(
|
|
@@ -18,7 +18,7 @@ require "dependabot/uv/authed_url_builder"
|
|
|
18
18
|
module Dependabot
|
|
19
19
|
module Uv
|
|
20
20
|
class FileUpdater
|
|
21
|
-
# rubocop:disable Metrics/ClassLength
|
|
21
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
22
22
|
class CompileFileUpdater
|
|
23
23
|
extend T::Sig
|
|
24
24
|
|
|
@@ -434,12 +434,17 @@ module Dependabot
|
|
|
434
434
|
args << index_url if index_url
|
|
435
435
|
|
|
436
436
|
begin
|
|
437
|
+
helper_result = SharedHelpers.run_helper_subprocess(
|
|
438
|
+
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
439
|
+
function: "get_dependency_hash",
|
|
440
|
+
args: args
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
# Skip this index if helper returned nil (can happen with unavailable registries)
|
|
444
|
+
next if helper_result.nil?
|
|
445
|
+
|
|
437
446
|
native_helper_hashes = T.cast(
|
|
438
|
-
|
|
439
|
-
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
440
|
-
function: "get_dependency_hash",
|
|
441
|
-
args: args
|
|
442
|
-
),
|
|
447
|
+
helper_result,
|
|
443
448
|
T::Array[T::Hash[String, String]]
|
|
444
449
|
).map { |h| "--hash=#{algorithm}:#{h['hash']}" }
|
|
445
450
|
|
|
@@ -451,6 +456,8 @@ module Dependabot
|
|
|
451
456
|
end
|
|
452
457
|
end
|
|
453
458
|
|
|
459
|
+
raise DependencyFileNotResolvable, "Unable to find hashes for package #{name}" if hashes.empty?
|
|
460
|
+
|
|
454
461
|
hashes
|
|
455
462
|
end
|
|
456
463
|
|
|
@@ -665,7 +672,6 @@ module Dependabot
|
|
|
665
672
|
dependency_files.select { |f| f.name.end_with?(".txt") }
|
|
666
673
|
end
|
|
667
674
|
end
|
|
668
|
-
# rubocop:enable Metrics/ClassLength
|
|
669
675
|
end
|
|
670
676
|
end
|
|
671
677
|
end
|
|
@@ -18,7 +18,7 @@ require "dependabot/uv/requirement_suffix_helper"
|
|
|
18
18
|
module Dependabot
|
|
19
19
|
module Uv
|
|
20
20
|
class FileUpdater
|
|
21
|
-
# rubocop:disable Metrics/ClassLength
|
|
21
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
22
22
|
class LockFileUpdater
|
|
23
23
|
extend T::Sig
|
|
24
24
|
|
|
@@ -44,21 +44,33 @@ module Dependabot
|
|
|
44
44
|
sig { returns(T.nilable(String)) }
|
|
45
45
|
attr_reader :repo_contents_path
|
|
46
46
|
|
|
47
|
+
sig { returns(T.nilable(String)) }
|
|
48
|
+
attr_reader :target_requirement
|
|
49
|
+
|
|
47
50
|
sig do
|
|
48
51
|
params(
|
|
49
52
|
dependencies: T::Array[Dependency],
|
|
50
53
|
dependency_files: T::Array[DependencyFile],
|
|
51
54
|
credentials: T::Array[Dependabot::Credential],
|
|
52
55
|
index_urls: T.nilable(T::Array[T.nilable(String)]),
|
|
53
|
-
repo_contents_path: T.nilable(String)
|
|
56
|
+
repo_contents_path: T.nilable(String),
|
|
57
|
+
target_requirement: T.nilable(String)
|
|
54
58
|
).void
|
|
55
59
|
end
|
|
56
|
-
def initialize(
|
|
60
|
+
def initialize(
|
|
61
|
+
dependencies:,
|
|
62
|
+
dependency_files:,
|
|
63
|
+
credentials:,
|
|
64
|
+
index_urls: nil,
|
|
65
|
+
repo_contents_path: nil,
|
|
66
|
+
target_requirement: nil
|
|
67
|
+
)
|
|
57
68
|
@dependencies = dependencies
|
|
58
69
|
@dependency_files = dependency_files
|
|
59
70
|
@credentials = credentials
|
|
60
71
|
@index_urls = index_urls
|
|
61
72
|
@repo_contents_path = repo_contents_path
|
|
73
|
+
@target_requirement = target_requirement
|
|
62
74
|
@prepared_pyproject = T.let(nil, T.nilable(String))
|
|
63
75
|
@updated_lockfile_content = T.let(nil, T.nilable(String))
|
|
64
76
|
@pyproject = T.let(nil, T.nilable(Dependabot::DependencyFile))
|
|
@@ -112,7 +124,9 @@ module Dependabot
|
|
|
112
124
|
# Use updated_lockfile_content which might raise if the lockfile doesn't change
|
|
113
125
|
new_content = updated_lockfile_content
|
|
114
126
|
|
|
115
|
-
|
|
127
|
+
if T.must(lockfile).content == new_content
|
|
128
|
+
raise DependencyFileContentNotChanged, "Expected lockfile to change!"
|
|
129
|
+
end
|
|
116
130
|
|
|
117
131
|
updated_files << updated_file(file: T.must(lockfile), content: new_content)
|
|
118
132
|
end
|
|
@@ -291,7 +305,14 @@ module Dependabot
|
|
|
291
305
|
# Strip extras from the package name for the uv lock command
|
|
292
306
|
# uv lock --upgrade-package expects the base package name without extras
|
|
293
307
|
base_dep_name = normalise(dep_name)
|
|
294
|
-
package_spec =
|
|
308
|
+
package_spec =
|
|
309
|
+
if target_requirement
|
|
310
|
+
"#{base_dep_name}#{target_requirement}"
|
|
311
|
+
elsif dep_version
|
|
312
|
+
"#{base_dep_name}==#{dep_version}"
|
|
313
|
+
else
|
|
314
|
+
base_dep_name
|
|
315
|
+
end
|
|
295
316
|
|
|
296
317
|
command = "pyenv exec uv lock --upgrade-package #{package_spec} #{options}"
|
|
297
318
|
fingerprint = "pyenv exec uv lock --upgrade-package <dependency_name> #{options_fingerprint}"
|
|
@@ -777,7 +798,6 @@ module Dependabot
|
|
|
777
798
|
)
|
|
778
799
|
end
|
|
779
800
|
end
|
|
780
|
-
# rubocop:enable Metrics/ClassLength
|
|
781
801
|
end
|
|
782
802
|
end
|
|
783
803
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "toml-rb"
|
|
@@ -13,6 +13,8 @@ module Dependabot
|
|
|
13
13
|
class VersionConfigParser
|
|
14
14
|
extend T::Sig
|
|
15
15
|
|
|
16
|
+
ObjectHash = T.type_alias { T::Hash[String, Object] }
|
|
17
|
+
|
|
16
18
|
class VersionConfig < T::Struct
|
|
17
19
|
extend T::Sig
|
|
18
20
|
|
|
@@ -32,7 +34,7 @@ module Dependabot
|
|
|
32
34
|
@pyproject_content = pyproject_content
|
|
33
35
|
@base_path = base_path
|
|
34
36
|
@repo_root = repo_root
|
|
35
|
-
@parsed_pyproject = T.let(nil, T.nilable(
|
|
37
|
+
@parsed_pyproject = T.let(nil, T.nilable(ObjectHash))
|
|
36
38
|
end
|
|
37
39
|
|
|
38
40
|
sig { returns(VersionConfig) }
|
|
@@ -56,15 +58,46 @@ module Dependabot
|
|
|
56
58
|
sig { returns(String) }
|
|
57
59
|
attr_reader :repo_root
|
|
58
60
|
|
|
59
|
-
sig { returns(
|
|
61
|
+
sig { returns(ObjectHash) }
|
|
60
62
|
def parsed_pyproject
|
|
61
63
|
return @parsed_pyproject unless @parsed_pyproject.nil?
|
|
62
64
|
|
|
63
|
-
@parsed_pyproject = TomlRB.parse(pyproject_content)
|
|
65
|
+
@parsed_pyproject = object_hash(T.cast(TomlRB.parse(pyproject_content), Object))
|
|
64
66
|
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
|
65
67
|
@parsed_pyproject = {}
|
|
66
68
|
end
|
|
67
69
|
|
|
70
|
+
sig { params(value: Object).returns(ObjectHash) }
|
|
71
|
+
def object_hash(value)
|
|
72
|
+
raise TypeError, "Version configuration must be a table" unless value.is_a?(Hash)
|
|
73
|
+
|
|
74
|
+
result = T.let({}, ObjectHash)
|
|
75
|
+
value.each do |raw_key, raw_value|
|
|
76
|
+
key = T.cast(raw_key, Object)
|
|
77
|
+
raise TypeError, "Version configuration keys must be strings" unless key.is_a?(String)
|
|
78
|
+
|
|
79
|
+
result[key] = T.cast(raw_value, Object)
|
|
80
|
+
end
|
|
81
|
+
result
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
sig { params(path: T::Array[String]).returns(Object) }
|
|
85
|
+
def config_value(path)
|
|
86
|
+
value = T.let(parsed_pyproject, Object)
|
|
87
|
+
path.each do |key|
|
|
88
|
+
return nil if value.nil?
|
|
89
|
+
|
|
90
|
+
value = object_hash(value)[key]
|
|
91
|
+
end
|
|
92
|
+
value
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
sig { params(path: T::Array[String]).returns(T.nilable(ObjectHash)) }
|
|
96
|
+
def config_table(path)
|
|
97
|
+
value = config_value(path)
|
|
98
|
+
object_hash(value) if value.is_a?(Hash)
|
|
99
|
+
end
|
|
100
|
+
|
|
68
101
|
sig { returns(T::Array[String]) }
|
|
69
102
|
def collect_write_paths
|
|
70
103
|
paths = []
|
|
@@ -82,8 +115,8 @@ module Dependabot
|
|
|
82
115
|
|
|
83
116
|
sig { returns(T::Array[String]) }
|
|
84
117
|
def setuptools_scm_write_paths
|
|
85
|
-
scm_config =
|
|
86
|
-
return [] unless scm_config
|
|
118
|
+
scm_config = config_table(%w(tool setuptools_scm))
|
|
119
|
+
return [] unless scm_config
|
|
87
120
|
|
|
88
121
|
paths = []
|
|
89
122
|
|
|
@@ -98,8 +131,8 @@ module Dependabot
|
|
|
98
131
|
|
|
99
132
|
sig { returns(T::Array[String]) }
|
|
100
133
|
def hatch_vcs_build_hook_write_paths
|
|
101
|
-
vcs_hook =
|
|
102
|
-
return [] unless vcs_hook
|
|
134
|
+
vcs_hook = config_table(%w(tool hatch build hooks vcs))
|
|
135
|
+
return [] unless vcs_hook
|
|
103
136
|
|
|
104
137
|
paths = []
|
|
105
138
|
|
|
@@ -111,8 +144,8 @@ module Dependabot
|
|
|
111
144
|
|
|
112
145
|
sig { returns(T::Array[String]) }
|
|
113
146
|
def hatch_version_source_paths
|
|
114
|
-
hatch_version =
|
|
115
|
-
return [] unless hatch_version
|
|
147
|
+
hatch_version = config_table(%w(tool hatch version))
|
|
148
|
+
return [] unless hatch_version
|
|
116
149
|
|
|
117
150
|
paths = []
|
|
118
151
|
|
|
@@ -124,14 +157,14 @@ module Dependabot
|
|
|
124
157
|
|
|
125
158
|
sig { returns(T.nilable(String)) }
|
|
126
159
|
def extract_fallback_version
|
|
127
|
-
scm_config =
|
|
128
|
-
if scm_config
|
|
160
|
+
scm_config = config_table(%w(tool setuptools_scm))
|
|
161
|
+
if scm_config
|
|
129
162
|
fallback = scm_config["fallback_version"]
|
|
130
163
|
return fallback if fallback.is_a?(String)
|
|
131
164
|
end
|
|
132
165
|
|
|
133
|
-
raw_options =
|
|
134
|
-
if raw_options
|
|
166
|
+
raw_options = config_table(%w(tool hatch version raw-options))
|
|
167
|
+
if raw_options
|
|
135
168
|
fallback = raw_options["fallback_version"]
|
|
136
169
|
return fallback if fallback.is_a?(String)
|
|
137
170
|
end
|
|
@@ -141,7 +174,7 @@ module Dependabot
|
|
|
141
174
|
|
|
142
175
|
sig { returns(T.nilable(String)) }
|
|
143
176
|
def extract_package_name
|
|
144
|
-
name =
|
|
177
|
+
name = config_value(%w(project name))
|
|
145
178
|
return name if name.is_a?(String)
|
|
146
179
|
|
|
147
180
|
nil
|
|
@@ -2,9 +2,17 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "sorbet-runtime"
|
|
5
|
+
require "toml-rb"
|
|
5
6
|
|
|
7
|
+
require "dependabot/errors"
|
|
6
8
|
require "dependabot/package/release_cooldown_options"
|
|
9
|
+
require "dependabot/update_checkers/version_filters"
|
|
7
10
|
require "dependabot/uv/version"
|
|
11
|
+
require "dependabot/uv/file_updater/lock_file_error_handler"
|
|
12
|
+
require "dependabot/uv/file_updater/lock_file_updater"
|
|
13
|
+
require "dependabot/uv/file_parser/python_requirement_parser"
|
|
14
|
+
require "dependabot/uv/language_version_manager"
|
|
15
|
+
require "dependabot/uv/name_normaliser"
|
|
8
16
|
require "dependabot/uv/requirement"
|
|
9
17
|
require "dependabot/uv/update_checker"
|
|
10
18
|
require "dependabot/uv/update_checker/latest_version_finder"
|
|
@@ -42,33 +50,42 @@ module Dependabot
|
|
|
42
50
|
@security_advisories = security_advisories
|
|
43
51
|
@ignored_versions = ignored_versions
|
|
44
52
|
@update_cooldown = update_cooldown
|
|
53
|
+
@latest_resolvable_versions = T.let(
|
|
54
|
+
{},
|
|
55
|
+
T::Hash[String, T.nilable(Dependabot::Uv::Version)]
|
|
56
|
+
)
|
|
57
|
+
@resolved_versions = T.let(
|
|
58
|
+
{},
|
|
59
|
+
T::Hash[String, T.nilable(Dependabot::Uv::Version)]
|
|
60
|
+
)
|
|
61
|
+
@resolvable_versions = T.let({}, T::Hash[String, T::Boolean])
|
|
45
62
|
end
|
|
46
63
|
|
|
47
64
|
sig { params(requirement: T.nilable(String)).returns(T.nilable(Dependabot::Uv::Version)) }
|
|
48
65
|
def latest_resolvable_version(requirement:)
|
|
49
66
|
return nil unless requirement
|
|
67
|
+
return @latest_resolvable_versions[requirement] if @latest_resolvable_versions.key?(requirement)
|
|
50
68
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# Get the version from the dependency if available
|
|
54
|
-
version_from_dependency = dependency.version && Uv::Version.new(dependency.version)
|
|
55
|
-
return version_from_dependency if version_from_dependency && req.satisfied_by?(version_from_dependency)
|
|
56
|
-
|
|
57
|
-
nil
|
|
69
|
+
@latest_resolvable_versions[requirement] = fetch_latest_resolvable_version(requirement)
|
|
58
70
|
end
|
|
59
71
|
|
|
60
|
-
sig { params(
|
|
61
|
-
def resolvable?(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
72
|
+
sig { params(version: Gem::Version).returns(T::Boolean) }
|
|
73
|
+
def resolvable?(version:)
|
|
74
|
+
target_version = Uv::Version.new(version.to_s)
|
|
75
|
+
key = target_version.to_s
|
|
76
|
+
return T.must(@resolvable_versions[key]) if @resolvable_versions.key?(key)
|
|
77
|
+
|
|
78
|
+
@resolvable_versions[key] = resolved_version("==#{key}", target_version)&.to_s == key
|
|
65
79
|
end
|
|
66
80
|
|
|
67
81
|
sig { returns(T.nilable(Dependabot::Uv::Version)) }
|
|
68
82
|
def lowest_resolvable_security_fix_version
|
|
69
83
|
# Delegate to LatestVersionFinder which handles security advisory filtering
|
|
70
|
-
fix_version = latest_version_finder.lowest_security_fix_version
|
|
71
|
-
|
|
84
|
+
fix_version = latest_version_finder.lowest_security_fix_version(
|
|
85
|
+
language_version: python_version
|
|
86
|
+
)
|
|
87
|
+
return nil unless fix_version
|
|
88
|
+
return nil unless resolvable?(version: fix_version)
|
|
72
89
|
|
|
73
90
|
# Return the fix version cast to Uv::Version
|
|
74
91
|
Uv::Version.new(fix_version.to_s)
|
|
@@ -97,6 +114,191 @@ module Dependabot
|
|
|
97
114
|
sig { returns(T.nilable(Dependabot::Package::ReleaseCooldownOptions)) }
|
|
98
115
|
attr_reader :update_cooldown
|
|
99
116
|
|
|
117
|
+
sig { params(requirement_string: String).returns(T.nilable(Dependabot::Uv::Version)) }
|
|
118
|
+
def fetch_latest_resolvable_version(requirement_string)
|
|
119
|
+
requirement = Uv::Requirement.new(requirement_string)
|
|
120
|
+
current_version = dependency.version && Uv::Version.new(dependency.version)
|
|
121
|
+
eligible_versions = eligible_versions(requirement, current_version)
|
|
122
|
+
return current_version if no_newer_eligible_version?(requirement, current_version, eligible_versions)
|
|
123
|
+
|
|
124
|
+
native_version = resolved_version(
|
|
125
|
+
policy_requirement(requirement_string, requirement, current_version, eligible_versions),
|
|
126
|
+
nil
|
|
127
|
+
)
|
|
128
|
+
if eligible_native_version?(requirement, native_version, eligible_versions) &&
|
|
129
|
+
resolvable?(version: T.must(native_version))
|
|
130
|
+
return native_version
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
current_version if current_version && requirement.satisfied_by?(current_version)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
sig do
|
|
137
|
+
params(
|
|
138
|
+
requirement: Dependabot::Uv::Requirement,
|
|
139
|
+
current_version: T.nilable(Dependabot::Uv::Version),
|
|
140
|
+
eligible_versions: T.nilable(T::Array[Dependabot::Uv::Version])
|
|
141
|
+
).returns(T::Boolean)
|
|
142
|
+
end
|
|
143
|
+
def no_newer_eligible_version?(requirement, current_version, eligible_versions)
|
|
144
|
+
return false unless current_version && eligible_versions
|
|
145
|
+
|
|
146
|
+
requirement.satisfied_by?(current_version) && eligible_versions.empty?
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
sig do
|
|
150
|
+
params(
|
|
151
|
+
requirement: Dependabot::Uv::Requirement,
|
|
152
|
+
native_version: T.nilable(Dependabot::Uv::Version),
|
|
153
|
+
eligible_versions: T.nilable(T::Array[Dependabot::Uv::Version])
|
|
154
|
+
).returns(T::Boolean)
|
|
155
|
+
end
|
|
156
|
+
def eligible_native_version?(requirement, native_version, eligible_versions)
|
|
157
|
+
return false unless native_version && requirement.satisfied_by?(native_version)
|
|
158
|
+
|
|
159
|
+
!eligible_versions || eligible_versions.include?(native_version)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
sig do
|
|
163
|
+
params(
|
|
164
|
+
requirement: Dependabot::Uv::Requirement,
|
|
165
|
+
current_version: T.nilable(Dependabot::Uv::Version)
|
|
166
|
+
).returns(T.nilable(T::Array[Dependabot::Uv::Version]))
|
|
167
|
+
end
|
|
168
|
+
def eligible_versions(requirement, current_version)
|
|
169
|
+
releases = latest_version_finder.eligible_releases(
|
|
170
|
+
language_version: python_version
|
|
171
|
+
)
|
|
172
|
+
return unless releases
|
|
173
|
+
|
|
174
|
+
releases = Dependabot::UpdateCheckers::VersionFilters
|
|
175
|
+
.filter_vulnerable_versions(releases, security_advisories)
|
|
176
|
+
releases
|
|
177
|
+
.map { |release| Uv::Version.new(release.version.to_s) }
|
|
178
|
+
.select { |version| requirement.satisfied_by?(version) && (!current_version || version > current_version) }
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
sig do
|
|
182
|
+
params(
|
|
183
|
+
requirement_string: String,
|
|
184
|
+
requirement: Dependabot::Uv::Requirement,
|
|
185
|
+
current_version: T.nilable(Dependabot::Uv::Version),
|
|
186
|
+
eligible_versions: T.nilable(T::Array[Dependabot::Uv::Version])
|
|
187
|
+
).returns(String)
|
|
188
|
+
end
|
|
189
|
+
def policy_requirement(requirement_string, requirement, current_version, eligible_versions)
|
|
190
|
+
releases = latest_version_finder.available_versions
|
|
191
|
+
return requirement_string unless releases && eligible_versions
|
|
192
|
+
|
|
193
|
+
excluded_versions = releases
|
|
194
|
+
.map { |release| Uv::Version.new(release.version.to_s) }
|
|
195
|
+
.select do |version|
|
|
196
|
+
requirement.satisfied_by?(version) &&
|
|
197
|
+
(!current_version || version > current_version) &&
|
|
198
|
+
!eligible_versions.include?(version)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
([requirement_string] + excluded_versions.map { |version| "!=#{version}" }).join(",")
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
sig do
|
|
205
|
+
params(
|
|
206
|
+
requirement_string: String,
|
|
207
|
+
target_version: T.nilable(Dependabot::Uv::Version)
|
|
208
|
+
)
|
|
209
|
+
.returns(T.nilable(Dependabot::Uv::Version))
|
|
210
|
+
end
|
|
211
|
+
def resolved_version(requirement_string, target_version)
|
|
212
|
+
return @resolved_versions[requirement_string] if @resolved_versions.key?(requirement_string)
|
|
213
|
+
|
|
214
|
+
@resolved_versions[requirement_string] = run_resolution(requirement_string, target_version)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
sig do
|
|
218
|
+
params(
|
|
219
|
+
requirement_string: String,
|
|
220
|
+
target_version: T.nilable(Dependabot::Uv::Version)
|
|
221
|
+
)
|
|
222
|
+
.returns(T.nilable(Dependabot::Uv::Version))
|
|
223
|
+
end
|
|
224
|
+
def run_resolution(requirement_string, target_version)
|
|
225
|
+
updated_dependency = Dependabot::Dependency.new(
|
|
226
|
+
name: dependency.name,
|
|
227
|
+
version: nil,
|
|
228
|
+
previous_version: dependency.version,
|
|
229
|
+
requirements: [],
|
|
230
|
+
previous_requirements: [],
|
|
231
|
+
package_manager: dependency.package_manager
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
updated_files = FileUpdater::LockFileUpdater.new(
|
|
235
|
+
dependencies: [updated_dependency],
|
|
236
|
+
dependency_files: dependency_files,
|
|
237
|
+
credentials: credentials,
|
|
238
|
+
repo_contents_path: repo_contents_path,
|
|
239
|
+
target_requirement: requirement_string
|
|
240
|
+
).updated_dependency_files
|
|
241
|
+
|
|
242
|
+
lockfile = updated_files.find { |file| file.name == "uv.lock" } || original_lockfile
|
|
243
|
+
resolved_locked_version(T.must(lockfile), target_version)
|
|
244
|
+
rescue Dependabot::DependencyFileContentNotChanged
|
|
245
|
+
resolved_locked_version(T.must(original_lockfile), target_version)
|
|
246
|
+
rescue Dependabot::UpdateNotPossible
|
|
247
|
+
nil
|
|
248
|
+
rescue Dependabot::DependencyFileNotResolvable => e
|
|
249
|
+
conflict = e.message.match?(FileUpdater::LockFileErrorHandler::UV_UNRESOLVABLE_REGEX) ||
|
|
250
|
+
e.message.include?(FileUpdater::LockFileErrorHandler::RESOLUTION_IMPOSSIBLE_ERROR)
|
|
251
|
+
raise unless conflict
|
|
252
|
+
|
|
253
|
+
nil
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
sig do
|
|
257
|
+
params(
|
|
258
|
+
lockfile: Dependabot::DependencyFile,
|
|
259
|
+
target_version: T.nilable(Dependabot::Uv::Version)
|
|
260
|
+
).returns(T.nilable(Dependabot::Uv::Version))
|
|
261
|
+
end
|
|
262
|
+
def resolved_locked_version(lockfile, target_version)
|
|
263
|
+
original_versions = locked_versions(T.must(original_lockfile))
|
|
264
|
+
updated_versions = locked_versions(lockfile)
|
|
265
|
+
current_version = dependency.version && Uv::Version.new(dependency.version)
|
|
266
|
+
return nil unless current_version && original_versions.min == current_version
|
|
267
|
+
return current_version if updated_versions.include?(current_version)
|
|
268
|
+
|
|
269
|
+
updated_version = updated_versions.min
|
|
270
|
+
return target_version if target_version && updated_version == target_version
|
|
271
|
+
return nil if target_version
|
|
272
|
+
|
|
273
|
+
updated_version
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
sig do
|
|
277
|
+
params(lockfile: Dependabot::DependencyFile)
|
|
278
|
+
.returns(T::Array[Dependabot::Uv::Version])
|
|
279
|
+
end
|
|
280
|
+
def locked_versions(lockfile)
|
|
281
|
+
parsed = T.cast(TomlRB.parse(T.must(lockfile.content)), T::Hash[String, Object])
|
|
282
|
+
packages = T.cast(parsed["package"], T.nilable(T::Array[T::Hash[String, Object]])) || []
|
|
283
|
+
dependency_name = NameNormaliser.normalise(dependency.name)
|
|
284
|
+
versions = T.let([], T::Array[Dependabot::Uv::Version])
|
|
285
|
+
packages.each do |package|
|
|
286
|
+
package_name = T.cast(package["name"], T.nilable(String))
|
|
287
|
+
package_version = T.cast(package["version"], T.nilable(String))
|
|
288
|
+
next unless package_name && NameNormaliser.normalise(package_name) == dependency_name
|
|
289
|
+
next unless Uv::Version.correct?(package_version)
|
|
290
|
+
|
|
291
|
+
versions << Uv::Version.new(package_version)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
versions
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
298
|
+
def original_lockfile
|
|
299
|
+
dependency_files.find { |file| file.name == "uv.lock" }
|
|
300
|
+
end
|
|
301
|
+
|
|
100
302
|
sig { returns(LatestVersionFinder) }
|
|
101
303
|
def latest_version_finder
|
|
102
304
|
@latest_version_finder ||= T.let(
|
|
@@ -112,6 +314,18 @@ module Dependabot
|
|
|
112
314
|
T.nilable(LatestVersionFinder)
|
|
113
315
|
)
|
|
114
316
|
end
|
|
317
|
+
|
|
318
|
+
sig { returns(String) }
|
|
319
|
+
def python_version
|
|
320
|
+
@python_version ||= T.let(
|
|
321
|
+
LanguageVersionManager.new(
|
|
322
|
+
python_requirement_parser: FileParser::PythonRequirementParser.new(
|
|
323
|
+
dependency_files: dependency_files
|
|
324
|
+
)
|
|
325
|
+
).python_version,
|
|
326
|
+
T.nilable(String)
|
|
327
|
+
)
|
|
328
|
+
end
|
|
115
329
|
end
|
|
116
330
|
end
|
|
117
331
|
end
|
|
@@ -24,7 +24,7 @@ module Dependabot
|
|
|
24
24
|
# This class does version resolution for pip-compile. Its approach is:
|
|
25
25
|
# - Unlock the dependency we're checking in the requirements.in file
|
|
26
26
|
# - Run `pip-compile` and see what the result is
|
|
27
|
-
# rubocop:disable Metrics/ClassLength
|
|
27
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
28
28
|
class PipCompileVersionResolver
|
|
29
29
|
extend T::Sig
|
|
30
30
|
|
|
@@ -595,7 +595,6 @@ module Dependabot
|
|
|
595
595
|
dependency_files.select { |f| f.name.end_with?("setup.cfg") }
|
|
596
596
|
end
|
|
597
597
|
end
|
|
598
|
-
# rubocop:enable Metrics/ClassLength
|
|
599
598
|
end
|
|
600
599
|
|
|
601
600
|
class PipCompileErrorHandler
|
|
@@ -228,11 +228,11 @@ module Dependabot
|
|
|
228
228
|
requirement_files.any? { |f| f.end_with?("requirements.txt") }
|
|
229
229
|
end
|
|
230
230
|
|
|
231
|
-
sig { override.returns(T.nilable(
|
|
231
|
+
sig { override.returns(T.nilable(PyprojectDocument::ProjectMetadata)) }
|
|
232
232
|
def library_details
|
|
233
233
|
@library_details ||= T.let(
|
|
234
|
-
|
|
235
|
-
T.nilable(
|
|
234
|
+
pyproject_document.project_metadata || pyproject_document.build_system_metadata,
|
|
235
|
+
T.nilable(PyprojectDocument::ProjectMetadata)
|
|
236
236
|
)
|
|
237
237
|
end
|
|
238
238
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-uv
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.395.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,28 +15,28 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.395.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.395.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: dependabot-python
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - '='
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.
|
|
32
|
+
version: 0.395.0
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - '='
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.
|
|
39
|
+
version: 0.395.0
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: debug
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -183,28 +183,28 @@ dependencies:
|
|
|
183
183
|
requirements:
|
|
184
184
|
- - "~>"
|
|
185
185
|
- !ruby/object:Gem::Version
|
|
186
|
-
version: '
|
|
186
|
+
version: '1.1'
|
|
187
187
|
type: :development
|
|
188
188
|
prerelease: false
|
|
189
189
|
version_requirements: !ruby/object:Gem::Requirement
|
|
190
190
|
requirements:
|
|
191
191
|
- - "~>"
|
|
192
192
|
- !ruby/object:Gem::Version
|
|
193
|
-
version: '
|
|
193
|
+
version: '1.1'
|
|
194
194
|
- !ruby/object:Gem::Dependency
|
|
195
|
-
name:
|
|
195
|
+
name: turbo_tests2
|
|
196
196
|
requirement: !ruby/object:Gem::Requirement
|
|
197
197
|
requirements:
|
|
198
198
|
- - "~>"
|
|
199
199
|
- !ruby/object:Gem::Version
|
|
200
|
-
version:
|
|
200
|
+
version: 3.2.7
|
|
201
201
|
type: :development
|
|
202
202
|
prerelease: false
|
|
203
203
|
version_requirements: !ruby/object:Gem::Requirement
|
|
204
204
|
requirements:
|
|
205
205
|
- - "~>"
|
|
206
206
|
- !ruby/object:Gem::Version
|
|
207
|
-
version:
|
|
207
|
+
version: 3.2.7
|
|
208
208
|
- !ruby/object:Gem::Dependency
|
|
209
209
|
name: vcr
|
|
210
210
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -301,7 +301,7 @@ licenses:
|
|
|
301
301
|
- MIT
|
|
302
302
|
metadata:
|
|
303
303
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
304
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
304
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.395.0
|
|
305
305
|
rdoc_options: []
|
|
306
306
|
require_paths:
|
|
307
307
|
- lib
|