dependabot-python 0.320.0 → 0.320.1
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/lib/dependabot/python/authed_url_builder.rb +8 -3
- data/lib/dependabot/python/file_updater/pip_compile_file_updater.rb +5 -5
- data/lib/dependabot/python/file_updater/requirement_file_updater.rb +37 -10
- data/lib/dependabot/python/file_updater/requirement_replacer.rb +59 -25
- data/lib/dependabot/python/file_updater/setup_file_sanitizer.rb +39 -13
- data/lib/dependabot/python/file_updater.rb +1 -1
- data/lib/dependabot/python/package/package_registry_finder.rb +97 -55
- data/lib/dependabot/python/pipenv_runner.rb +2 -2
- data/lib/dependabot/python/requirement.rb +29 -20
- data/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb +121 -50
- data/lib/dependabot/python/update_checker/pip_version_resolver.rb +41 -10
- data/lib/dependabot/python/update_checker/pipenv_version_resolver.rb +80 -23
- data/lib/dependabot/python/update_checker/poetry_version_resolver.rb +80 -25
- data/lib/dependabot/python/update_checker/requirements_updater.rb +80 -34
- data/lib/dependabot/python/version.rb +21 -14
- metadata +4 -4
@@ -1,6 +1,7 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
4
5
|
require "open3"
|
5
6
|
require "dependabot/dependency"
|
6
7
|
require "dependabot/python/requirement_parser"
|
@@ -23,33 +24,58 @@ module Dependabot
|
|
23
24
|
# This class does version resolution for pip-compile. Its approach is:
|
24
25
|
# - Unlock the dependency we're checking in the requirements.in file
|
25
26
|
# - Run `pip-compile` and see what the result is
|
26
|
-
class PipCompileVersionResolver
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
class PipCompileVersionResolver # rubocop:disable Metrics/ClassLength
|
28
|
+
extend T::Sig
|
29
|
+
|
30
|
+
GIT_DEPENDENCY_UNREACHABLE_REGEX = T.let(/git clone --filter=blob:none --quiet (?<url>[^\s]+).* /, Regexp)
|
31
|
+
GIT_REFERENCE_NOT_FOUND_REGEX = T.let(/Did not find branch or tag '(?<tag>[^\n"]+)'/m, Regexp)
|
32
|
+
NATIVE_COMPILATION_ERROR = T.let(
|
33
|
+
"pip._internal.exceptions.InstallationSubprocessError: Getting requirements to build wheel exited with 1",
|
34
|
+
String
|
35
|
+
)
|
31
36
|
# See https://packaging.python.org/en/latest/tutorials/packaging-projects/#configuring-metadata
|
32
|
-
PYTHON_PACKAGE_NAME_REGEX = /[A-Za-z0-9_\-]
|
33
|
-
RESOLUTION_IMPOSSIBLE_ERROR = "ResolutionImpossible"
|
34
|
-
ERROR_REGEX = /(?<=ERROR\:\W)
|
37
|
+
PYTHON_PACKAGE_NAME_REGEX = T.let(/[A-Za-z0-9_\-]+/, Regexp)
|
38
|
+
RESOLUTION_IMPOSSIBLE_ERROR = T.let("ResolutionImpossible", String)
|
39
|
+
ERROR_REGEX = T.let(/(?<=ERROR\:\W).*$/, Regexp)
|
35
40
|
|
41
|
+
sig { returns(Dependabot::Dependency) }
|
36
42
|
attr_reader :dependency
|
43
|
+
|
44
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
37
45
|
attr_reader :dependency_files
|
46
|
+
|
47
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
38
48
|
attr_reader :credentials
|
49
|
+
|
50
|
+
sig { returns(T.nilable(String)) }
|
39
51
|
attr_reader :repo_contents_path
|
52
|
+
|
53
|
+
sig { returns(PipCompileErrorHandler) }
|
40
54
|
attr_reader :error_handler
|
41
55
|
|
56
|
+
sig do
|
57
|
+
params(
|
58
|
+
dependency: Dependabot::Dependency,
|
59
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
60
|
+
credentials: T::Array[Dependabot::Credential],
|
61
|
+
repo_contents_path: T.nilable(String)
|
62
|
+
).void
|
63
|
+
end
|
42
64
|
def initialize(dependency:, dependency_files:, credentials:, repo_contents_path:)
|
43
|
-
@dependency
|
44
|
-
@dependency_files
|
45
|
-
@credentials
|
46
|
-
@repo_contents_path
|
47
|
-
@build_isolation = true
|
48
|
-
@error_handler = PipCompileErrorHandler.new
|
65
|
+
@dependency = T.let(dependency, Dependabot::Dependency)
|
66
|
+
@dependency_files = T.let(dependency_files, T::Array[Dependabot::DependencyFile])
|
67
|
+
@credentials = T.let(credentials, T::Array[Dependabot::Credential])
|
68
|
+
@repo_contents_path = T.let(repo_contents_path, T.nilable(String))
|
69
|
+
@build_isolation = T.let(true, T::Boolean)
|
70
|
+
@error_handler = T.let(PipCompileErrorHandler.new, PipCompileErrorHandler)
|
49
71
|
end
|
50
72
|
|
73
|
+
sig { params(requirement: T.nilable(String)).returns(T.nilable(Dependabot::Python::Version)) }
|
51
74
|
def latest_resolvable_version(requirement: nil)
|
52
|
-
@latest_resolvable_version_string ||=
|
75
|
+
@latest_resolvable_version_string ||= T.let(
|
76
|
+
{},
|
77
|
+
T.nilable(T::Hash[T.nilable(String), T.nilable(Dependabot::Python::Version)])
|
78
|
+
)
|
53
79
|
return @latest_resolvable_version_string[requirement] if @latest_resolvable_version_string.key?(requirement)
|
54
80
|
|
55
81
|
version_string =
|
@@ -59,9 +85,10 @@ module Dependabot
|
|
59
85
|
version_string.nil? ? nil : Python::Version.new(version_string)
|
60
86
|
end
|
61
87
|
|
88
|
+
sig { params(version: Gem::Version).returns(T::Boolean) }
|
62
89
|
def resolvable?(version:)
|
63
|
-
@resolvable ||= {}
|
64
|
-
return @resolvable[version] if @resolvable.key?(version)
|
90
|
+
@resolvable ||= T.let({}, T.nilable(T::Hash[Gem::Version, T::Boolean]))
|
91
|
+
return T.must(@resolvable[version]) if @resolvable.key?(version)
|
65
92
|
|
66
93
|
@resolvable[version] = if latest_resolvable_version(requirement: "==#{version}")
|
67
94
|
true
|
@@ -72,6 +99,7 @@ module Dependabot
|
|
72
99
|
|
73
100
|
private
|
74
101
|
|
102
|
+
sig { params(requirement: T.nilable(String)).returns(T.nilable(String)) }
|
75
103
|
def fetch_latest_resolvable_version_string(requirement:)
|
76
104
|
SharedHelpers.in_a_temporary_directory do
|
77
105
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
@@ -90,6 +118,7 @@ module Dependabot
|
|
90
118
|
end
|
91
119
|
end
|
92
120
|
|
121
|
+
sig { params(filename: String).returns(T::Boolean) }
|
93
122
|
def compile_file(filename)
|
94
123
|
# Shell out to pip-compile.
|
95
124
|
# This is slow, as pip-compile needs to do installs.
|
@@ -126,15 +155,18 @@ module Dependabot
|
|
126
155
|
end
|
127
156
|
|
128
157
|
handle_pip_compile_errors(e.message)
|
158
|
+
false
|
129
159
|
end
|
130
160
|
|
161
|
+
sig { params(error: Dependabot::SharedHelpers::HelperSubprocessFailed).returns(T::Boolean) }
|
131
162
|
def compilation_error?(error)
|
132
163
|
error.message.include?(NATIVE_COMPILATION_ERROR)
|
133
164
|
end
|
134
165
|
|
135
166
|
# rubocop:disable Metrics/AbcSize
|
136
167
|
# rubocop:disable Metrics/PerceivedComplexity
|
137
|
-
|
168
|
+
sig { params(message: String).returns(T.nilable(String)) }
|
169
|
+
def handle_pip_compile_errors(message) # rubocop:disable Metrics/MethodLength
|
138
170
|
if message.include?(RESOLUTION_IMPOSSIBLE_ERROR)
|
139
171
|
check_original_requirements_resolvable
|
140
172
|
# If the original requirements are resolvable but we get an
|
@@ -167,21 +199,24 @@ module Dependabot
|
|
167
199
|
end
|
168
200
|
|
169
201
|
if message.match?(GIT_REFERENCE_NOT_FOUND_REGEX)
|
170
|
-
tag = message.match(GIT_REFERENCE_NOT_FOUND_REGEX).named_captures.fetch("tag")
|
171
|
-
constraints_section = message.split("Finding the best candidates:").first
|
202
|
+
tag = T.must(T.must(message.match(GIT_REFERENCE_NOT_FOUND_REGEX)).named_captures.fetch("tag"))
|
203
|
+
constraints_section = T.must(message.split("Finding the best candidates:").first)
|
172
204
|
egg_regex = /#{Regexp.escape(tag)}#egg=(#{PYTHON_PACKAGE_NAME_REGEX})/
|
173
205
|
name_match = constraints_section.scan(egg_regex)
|
174
206
|
|
175
207
|
# We can determine the name of the package from another part of the logger output if it has a unique tag
|
176
|
-
|
208
|
+
if name_match.length == 1 && name_match.first.is_a?(Array)
|
209
|
+
raise GitDependencyReferenceNotFound,
|
210
|
+
T.must(T.cast(T.must(name_match.first), T::Array[String]).first)
|
211
|
+
end
|
177
212
|
|
178
213
|
raise GitDependencyReferenceNotFound, "(unknown package at #{tag})"
|
179
214
|
end
|
180
215
|
|
181
216
|
if message.match?(GIT_DEPENDENCY_UNREACHABLE_REGEX)
|
182
|
-
url = message.match(GIT_DEPENDENCY_UNREACHABLE_REGEX)
|
183
|
-
|
184
|
-
raise GitDependenciesNotReachable, url
|
217
|
+
url = T.must(message.match(GIT_DEPENDENCY_UNREACHABLE_REGEX))
|
218
|
+
.named_captures.fetch("url")
|
219
|
+
raise GitDependenciesNotReachable, T.must(url)
|
185
220
|
end
|
186
221
|
|
187
222
|
raise Dependabot::OutOfDisk if message.end_with?("[Errno 28] No space left on device")
|
@@ -199,6 +234,7 @@ module Dependabot
|
|
199
234
|
# Note: We raise errors from this method, rather than returning a
|
200
235
|
# boolean, so that all deps for this repo will raise identical
|
201
236
|
# errors when failing to update
|
237
|
+
sig { returns(T::Boolean) }
|
202
238
|
def check_original_requirements_resolvable
|
203
239
|
SharedHelpers.in_a_temporary_directory do
|
204
240
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
@@ -230,10 +266,12 @@ module Dependabot
|
|
230
266
|
end
|
231
267
|
end
|
232
268
|
|
233
|
-
|
269
|
+
sig { params(command: String, fingerprint: String, env: T::Hash[String, String]).void }
|
270
|
+
def run_command(command, fingerprint:, env: python_env)
|
234
271
|
SharedHelpers.run_shell_command(command, env: env, fingerprint: fingerprint, stderr_to_stdout: true)
|
235
272
|
end
|
236
273
|
|
274
|
+
sig { params(options: String).returns(String) }
|
237
275
|
def pip_compile_options_fingerprint(options)
|
238
276
|
options.sub(
|
239
277
|
/--output-file=\S+/, "--output-file=<output_file>"
|
@@ -244,6 +282,7 @@ module Dependabot
|
|
244
282
|
)
|
245
283
|
end
|
246
284
|
|
285
|
+
sig { params(filename: String).returns(String) }
|
247
286
|
def pip_compile_options(filename)
|
248
287
|
options = @build_isolation ? ["--build-isolation"] : ["--no-build-isolation"]
|
249
288
|
options += pip_compile_index_options
|
@@ -258,6 +297,7 @@ module Dependabot
|
|
258
297
|
options.join(" ")
|
259
298
|
end
|
260
299
|
|
300
|
+
sig { returns(T::Array[String]) }
|
261
301
|
def pip_compile_index_options
|
262
302
|
credentials
|
263
303
|
.select { |cred| cred["type"] == "python_index" }
|
@@ -272,6 +312,7 @@ module Dependabot
|
|
272
312
|
end
|
273
313
|
end
|
274
314
|
|
315
|
+
sig { params(command: String, fingerprint: String).void }
|
275
316
|
def run_pip_compile_command(command, fingerprint:)
|
276
317
|
run_command(
|
277
318
|
"pyenv local #{language_version_manager.python_major_minor}",
|
@@ -281,12 +322,13 @@ module Dependabot
|
|
281
322
|
run_command(command, fingerprint: fingerprint)
|
282
323
|
end
|
283
324
|
|
325
|
+
sig { returns(T::Hash[String, String]) }
|
284
326
|
def python_env
|
285
327
|
env = {}
|
286
328
|
|
287
329
|
# Handle Apache Airflow 1.10.x installs
|
288
|
-
if dependency_files.any? { |f| f.content.include?("apache-airflow") }
|
289
|
-
if dependency_files.any? { |f| f.content.include?("unidecode") }
|
330
|
+
if dependency_files.any? { |f| T.must(f.content).include?("apache-airflow") }
|
331
|
+
if dependency_files.any? { |f| T.must(f.content).include?("unidecode") }
|
290
332
|
env["AIRFLOW_GPL_UNIDECODE"] = "yes"
|
291
333
|
else
|
292
334
|
env["SLUGIFY_USES_TEXT_UNIDECODE"] = "yes"
|
@@ -296,8 +338,11 @@ module Dependabot
|
|
296
338
|
env
|
297
339
|
end
|
298
340
|
|
299
|
-
|
300
|
-
|
341
|
+
sig do
|
342
|
+
params(updated_req: T.nilable(String), update_requirement: T::Boolean)
|
343
|
+
.returns(T::Array[Dependabot::DependencyFile])
|
344
|
+
end
|
345
|
+
def write_temporary_dependency_files(updated_req: nil, update_requirement: true)
|
301
346
|
dependency_files.each do |file|
|
302
347
|
path = file.name
|
303
348
|
FileUtils.mkdir_p(Pathname.new(path).dirname)
|
@@ -325,6 +370,7 @@ module Dependabot
|
|
325
370
|
end
|
326
371
|
end
|
327
372
|
|
373
|
+
sig { void }
|
328
374
|
def write_original_manifest_files
|
329
375
|
pip_compile_files.each do |file|
|
330
376
|
FileUtils.mkdir_p(Pathname.new(file.name).dirname)
|
@@ -332,9 +378,10 @@ module Dependabot
|
|
332
378
|
end
|
333
379
|
end
|
334
380
|
|
381
|
+
sig { params(file: Dependabot::DependencyFile).returns(String) }
|
335
382
|
def sanitized_setup_file_content(file)
|
336
|
-
@sanitized_setup_file_content ||= {}
|
337
|
-
return @sanitized_setup_file_content[file.name] if @sanitized_setup_file_content[file.name]
|
383
|
+
@sanitized_setup_file_content ||= T.let({}, T.nilable(T::Hash[String, String]))
|
384
|
+
return T.must(@sanitized_setup_file_content[file.name]) if @sanitized_setup_file_content[file.name]
|
338
385
|
|
339
386
|
@sanitized_setup_file_content[file.name] =
|
340
387
|
Python::FileUpdater::SetupFileSanitizer
|
@@ -342,35 +389,40 @@ module Dependabot
|
|
342
389
|
.sanitized_content
|
343
390
|
end
|
344
391
|
|
392
|
+
sig { params(file: Dependabot::DependencyFile).returns(T.nilable(Dependabot::DependencyFile)) }
|
345
393
|
def setup_cfg(file)
|
346
394
|
dependency_files.find do |f|
|
347
395
|
f.name == file.name.sub(/\.py$/, ".cfg")
|
348
396
|
end
|
349
397
|
end
|
350
398
|
|
399
|
+
sig { params(file: Dependabot::DependencyFile, updated_req: T.nilable(String)).returns(String) }
|
351
400
|
def update_req_file(file, updated_req)
|
352
|
-
return file.content unless file.name.end_with?(".in")
|
401
|
+
return T.must(file.content) unless file.name.end_with?(".in")
|
353
402
|
|
354
403
|
req = dependency.requirements.find { |r| r[:file] == file.name }
|
355
404
|
|
356
|
-
return file.content + "\n#{dependency.name} #{updated_req}" unless req&.fetch(:requirement)
|
405
|
+
return T.must(file.content) + "\n#{dependency.name} #{updated_req}" unless req&.fetch(:requirement)
|
357
406
|
|
358
407
|
Python::FileUpdater::RequirementReplacer.new(
|
359
|
-
content: file.content,
|
408
|
+
content: T.must(file.content),
|
360
409
|
dependency_name: dependency.name,
|
361
410
|
old_requirement: req[:requirement],
|
362
411
|
new_requirement: updated_req
|
363
412
|
).updated_content
|
364
413
|
end
|
365
414
|
|
415
|
+
sig { params(name: String).returns(String) }
|
366
416
|
def normalise(name)
|
367
417
|
NameNormaliser.normalise(name)
|
368
418
|
end
|
369
419
|
|
420
|
+
sig { params(message: String).returns(String) }
|
370
421
|
def clean_error_message(message)
|
371
|
-
message.scan(ERROR_REGEX).last
|
422
|
+
T.must(T.cast(message.scan(ERROR_REGEX), T::Array[String]).last)
|
372
423
|
end
|
373
424
|
|
425
|
+
sig { returns(T::Array[String]) }
|
374
426
|
def filenames_to_compile
|
375
427
|
files_from_reqs =
|
376
428
|
dependency.requirements
|
@@ -388,10 +440,11 @@ module Dependabot
|
|
388
440
|
order_filenames_for_compilation(filenames)
|
389
441
|
end
|
390
442
|
|
443
|
+
sig { params(filename: String).returns(T.nilable(Dependabot::DependencyFile)) }
|
391
444
|
def compiled_file_for_filename(filename)
|
392
445
|
compiled_file =
|
393
446
|
compiled_files
|
394
|
-
.find { |f| f.content.match?(output_file_regex(filename)) }
|
447
|
+
.find { |f| T.must(f.content).match?(output_file_regex(filename)) }
|
395
448
|
|
396
449
|
compiled_file ||=
|
397
450
|
compiled_files
|
@@ -400,22 +453,25 @@ module Dependabot
|
|
400
453
|
compiled_file
|
401
454
|
end
|
402
455
|
|
456
|
+
sig { params(filename: String).returns(String) }
|
403
457
|
def output_file_regex(filename)
|
404
458
|
"--output-file[=\s]+.*\s#{Regexp.escape(filename)}\s*$"
|
405
459
|
end
|
406
460
|
|
461
|
+
sig { params(compiled_file: T.nilable(Dependabot::DependencyFile)).returns(T::Boolean) }
|
407
462
|
def compiled_file_includes_dependency?(compiled_file)
|
408
463
|
return false unless compiled_file
|
409
464
|
|
410
465
|
regex = RequirementParser::INSTALL_REQ_WITH_REQUIREMENT
|
411
466
|
|
412
467
|
matches = []
|
413
|
-
compiled_file.content.scan(regex) { matches << Regexp.last_match }
|
468
|
+
T.must(compiled_file.content).scan(regex) { matches << Regexp.last_match }
|
414
469
|
matches.any? { |m| normalise(m[:name]) == dependency.name }
|
415
470
|
end
|
416
471
|
|
417
472
|
# If the files we need to update require one another then we need to
|
418
473
|
# update them in the right order
|
474
|
+
sig { params(filenames: T::Array[String]).returns(T::Array[String]) }
|
419
475
|
def order_filenames_for_compilation(filenames)
|
420
476
|
ordered_filenames = T.let([], T::Array[String])
|
421
477
|
|
@@ -423,7 +479,7 @@ module Dependabot
|
|
423
479
|
ordered_filenames +=
|
424
480
|
remaining_filenames
|
425
481
|
.reject do |fn|
|
426
|
-
unupdated_reqs = requirement_map[fn] - ordered_filenames
|
482
|
+
unupdated_reqs = T.must(requirement_map[fn]) - ordered_filenames
|
427
483
|
unupdated_reqs.intersect?(filenames)
|
428
484
|
end
|
429
485
|
end
|
@@ -431,11 +487,12 @@ module Dependabot
|
|
431
487
|
ordered_filenames
|
432
488
|
end
|
433
489
|
|
490
|
+
sig { returns(T::Hash[String, T::Array[String]]) }
|
434
491
|
def requirement_map
|
435
492
|
child_req_regex = Python::FileFetcher::CHILD_REQUIREMENT_REGEX
|
436
|
-
@requirement_map ||=
|
493
|
+
@requirement_map ||= T.let(
|
437
494
|
pip_compile_files.each_with_object({}) do |file, req_map|
|
438
|
-
paths = file.content.scan(child_req_regex).flatten
|
495
|
+
paths = T.must(file.content).scan(child_req_regex).flatten
|
439
496
|
current_dir = File.dirname(file.name)
|
440
497
|
|
441
498
|
req_map[file.name] =
|
@@ -447,9 +504,12 @@ module Dependabot
|
|
447
504
|
|
448
505
|
path
|
449
506
|
end.uniq.compact
|
450
|
-
end
|
507
|
+
end,
|
508
|
+
T.nilable(T::Hash[String, T::Array[String]])
|
509
|
+
)
|
451
510
|
end
|
452
511
|
|
512
|
+
sig { returns(T.nilable(String)) }
|
453
513
|
def parse_updated_files
|
454
514
|
updated_files =
|
455
515
|
dependency_files.map do |file|
|
@@ -467,32 +527,40 @@ module Dependabot
|
|
467
527
|
).parse.find { |d| d.name == dependency.name }&.version
|
468
528
|
end
|
469
529
|
|
530
|
+
sig { returns(Dependabot::Python::FileParser::PythonRequirementParser) }
|
470
531
|
def python_requirement_parser
|
471
|
-
@python_requirement_parser ||=
|
532
|
+
@python_requirement_parser ||= T.let(
|
472
533
|
FileParser::PythonRequirementParser.new(
|
473
534
|
dependency_files: dependency_files
|
474
|
-
)
|
535
|
+
), T.nilable(FileParser::PythonRequirementParser)
|
536
|
+
)
|
475
537
|
end
|
476
538
|
|
539
|
+
sig { returns(Dependabot::Python::LanguageVersionManager) }
|
477
540
|
def language_version_manager
|
478
|
-
@language_version_manager ||=
|
541
|
+
@language_version_manager ||= T.let(
|
479
542
|
LanguageVersionManager.new(
|
480
543
|
python_requirement_parser: python_requirement_parser
|
481
|
-
)
|
544
|
+
), T.nilable(LanguageVersionManager)
|
545
|
+
)
|
482
546
|
end
|
483
547
|
|
548
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
484
549
|
def setup_files
|
485
550
|
dependency_files.select { |f| f.name.end_with?("setup.py") }
|
486
551
|
end
|
487
552
|
|
553
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
488
554
|
def pip_compile_files
|
489
555
|
dependency_files.select { |f| f.name.end_with?(".in") }
|
490
556
|
end
|
491
557
|
|
558
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
492
559
|
def compiled_files
|
493
560
|
dependency_files.select { |f| f.name.end_with?(".txt") }
|
494
561
|
end
|
495
562
|
|
563
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
496
564
|
def setup_cfg_files
|
497
565
|
dependency_files.select { |f| f.name.end_with?("setup.cfg") }
|
498
566
|
end
|
@@ -500,14 +568,17 @@ module Dependabot
|
|
500
568
|
end
|
501
569
|
|
502
570
|
class PipCompileErrorHandler
|
503
|
-
|
571
|
+
extend T::Sig
|
572
|
+
|
573
|
+
SUBPROCESS_ERROR = T.let(/subprocess-exited-with-error/, Regexp)
|
504
574
|
|
505
|
-
INSTALLATION_ERROR = /InstallationError
|
575
|
+
INSTALLATION_ERROR = T.let(/InstallationError/, Regexp)
|
506
576
|
|
507
|
-
INSTALLATION_SUBPROCESS_ERROR = /InstallationSubprocessError
|
577
|
+
INSTALLATION_SUBPROCESS_ERROR = T.let(/InstallationSubprocessError/, Regexp)
|
508
578
|
|
509
|
-
HASH_MISMATCH = /HashMismatch
|
579
|
+
HASH_MISMATCH = T.let(/HashMismatch/, Regexp)
|
510
580
|
|
581
|
+
sig { params(error: String).void }
|
511
582
|
def handle_pipcompile_error(error)
|
512
583
|
return unless error.match?(SUBPROCESS_ERROR) || error.match?(INSTALLATION_ERROR) ||
|
513
584
|
error.match?(INSTALLATION_SUBPROCESS_ERROR) || error.match?(HASH_MISMATCH)
|
@@ -1,6 +1,7 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strong
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
4
5
|
require "dependabot/python/language_version_manager"
|
5
6
|
require "dependabot/python/update_checker"
|
6
7
|
require "dependabot/python/update_checker/latest_version_finder"
|
@@ -10,27 +11,45 @@ module Dependabot
|
|
10
11
|
module Python
|
11
12
|
class UpdateChecker
|
12
13
|
class PipVersionResolver
|
14
|
+
extend T::Sig
|
15
|
+
|
16
|
+
sig do
|
17
|
+
params(
|
18
|
+
dependency: Dependabot::Dependency,
|
19
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
20
|
+
credentials: T::Array[Dependabot::Credential],
|
21
|
+
ignored_versions: T::Array[String],
|
22
|
+
security_advisories: T::Array[Dependabot::SecurityAdvisory],
|
23
|
+
update_cooldown: T.nilable(Dependabot::Package::ReleaseCooldownOptions),
|
24
|
+
raise_on_ignored: T::Boolean
|
25
|
+
).void
|
26
|
+
end
|
13
27
|
def initialize(dependency:, dependency_files:, credentials:,
|
14
|
-
ignored_versions:, update_cooldown: nil, raise_on_ignored: false
|
15
|
-
|
16
|
-
@
|
17
|
-
@
|
18
|
-
@
|
19
|
-
@
|
20
|
-
@update_cooldown = update_cooldown
|
21
|
-
@raise_on_ignored
|
22
|
-
@
|
28
|
+
ignored_versions:, security_advisories:, update_cooldown: nil, raise_on_ignored: false)
|
29
|
+
@dependency = T.let(dependency, Dependabot::Dependency)
|
30
|
+
@dependency_files = T.let(dependency_files, T::Array[Dependabot::DependencyFile])
|
31
|
+
@credentials = T.let(credentials, T::Array[Dependabot::Credential])
|
32
|
+
@ignored_versions = T.let(ignored_versions, T::Array[String])
|
33
|
+
@security_advisories = T.let(security_advisories, T::Array[Dependabot::SecurityAdvisory])
|
34
|
+
@update_cooldown = T.let(update_cooldown, T.nilable(Dependabot::Package::ReleaseCooldownOptions))
|
35
|
+
@raise_on_ignored = T.let(raise_on_ignored, T::Boolean)
|
36
|
+
@latest_version_finder = T.let(nil, T.nilable(LatestVersionFinder))
|
37
|
+
@python_requirement_parser = T.let(nil, T.nilable(FileParser::PythonRequirementParser))
|
38
|
+
@language_version_manager = T.let(nil, T.nilable(LanguageVersionManager))
|
23
39
|
end
|
24
40
|
|
41
|
+
sig { returns(T.nilable(Dependabot::Version)) }
|
25
42
|
def latest_resolvable_version
|
26
43
|
latest_version_finder.latest_version(language_version: language_version_manager.python_version)
|
27
44
|
end
|
28
45
|
|
46
|
+
sig { returns(T.nilable(Dependabot::Version)) }
|
29
47
|
def latest_resolvable_version_with_no_unlock
|
30
48
|
latest_version_finder
|
31
49
|
.latest_version_with_no_unlock(language_version: language_version_manager.python_version)
|
32
50
|
end
|
33
51
|
|
52
|
+
sig { returns(T.nilable(Dependabot::Version)) }
|
34
53
|
def lowest_resolvable_security_fix_version
|
35
54
|
latest_version_finder
|
36
55
|
.lowest_security_fix_version(language_version: language_version_manager.python_version)
|
@@ -38,12 +57,22 @@ module Dependabot
|
|
38
57
|
|
39
58
|
private
|
40
59
|
|
60
|
+
sig { returns(Dependabot::Dependency) }
|
41
61
|
attr_reader :dependency
|
62
|
+
|
63
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
42
64
|
attr_reader :dependency_files
|
65
|
+
|
66
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
43
67
|
attr_reader :credentials
|
68
|
+
|
69
|
+
sig { returns(T::Array[String]) }
|
44
70
|
attr_reader :ignored_versions
|
71
|
+
|
72
|
+
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
45
73
|
attr_reader :security_advisories
|
46
74
|
|
75
|
+
sig { returns(LatestVersionFinder) }
|
47
76
|
def latest_version_finder
|
48
77
|
@latest_version_finder ||= LatestVersionFinder.new(
|
49
78
|
dependency: dependency,
|
@@ -57,6 +86,7 @@ module Dependabot
|
|
57
86
|
@latest_version_finder
|
58
87
|
end
|
59
88
|
|
89
|
+
sig { returns(FileParser::PythonRequirementParser) }
|
60
90
|
def python_requirement_parser
|
61
91
|
@python_requirement_parser ||=
|
62
92
|
FileParser::PythonRequirementParser.new(
|
@@ -64,6 +94,7 @@ module Dependabot
|
|
64
94
|
)
|
65
95
|
end
|
66
96
|
|
97
|
+
sig { returns(LanguageVersionManager) }
|
67
98
|
def language_version_manager
|
68
99
|
@language_version_manager ||=
|
69
100
|
LanguageVersionManager.new(
|