dependabot-python 0.390.0 → 0.392.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/lib/dependabot/python/authed_url_builder.rb +2 -1
- data/lib/dependabot/python/dependency_grapher/requirements_layers.rb +4 -4
- data/lib/dependabot/python/file_fetcher.rb +1 -1
- data/lib/dependabot/python/file_parser/python_requirement_parser.rb +2 -2
- data/lib/dependabot/python/file_updater/pip_compile_file_updater.rb +27 -32
- data/lib/dependabot/python/file_updater/pipfile_file_updater.rb +1 -1
- data/lib/dependabot/python/file_updater/pipfile_manifest_updater.rb +7 -7
- data/lib/dependabot/python/file_updater/poetry_file_updater/pep621_updater.rb +14 -10
- data/lib/dependabot/python/file_updater/poetry_file_updater.rb +23 -23
- data/lib/dependabot/python/file_updater/pyproject_preparer.rb +2 -5
- data/lib/dependabot/python/file_updater/requirement_file_updater.rb +19 -15
- data/lib/dependabot/python/file_updater/requirement_replacer.rb +5 -5
- data/lib/dependabot/python/file_updater/setup_file_sanitizer.rb +11 -12
- data/lib/dependabot/python/file_updater.rb +1 -1
- data/lib/dependabot/python/package/package_registry_finder.rb +3 -3
- data/lib/dependabot/python/pipenv_runner.rb +1 -1
- data/lib/dependabot/python/poetry_plugin_installer.rb +1 -1
- data/lib/dependabot/python/requirement.rb +9 -6
- data/lib/dependabot/python/shared_file_fetcher.rb +5 -5
- data/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb +19 -21
- data/lib/dependabot/python/update_checker/pip_version_resolver.rb +3 -1
- data/lib/dependabot/python/update_checker/pipenv_version_resolver.rb +4 -4
- data/lib/dependabot/python/update_checker/poetry_version_resolver.rb +7 -7
- data/lib/dependabot/python/update_checker/requirements_updater.rb +48 -40
- data/lib/dependabot/python/update_checker.rb +13 -13
- data/lib/dependabot/python/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 70504f97ff35fbf437e2895455b6371d858c38921b3f4839a11aaddc31d04911
|
|
4
|
+
data.tar.gz: 131699694996cabca8daec6c5a96f5a4dba34ec11601a22d7a8f54e6a855852f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 56501fd6454a91206147b03fa795570e6a494e5d5c9733c8945656b174893352cd4adaa3bd2b4ee6c87565c3cc59dc861f62500d4c86fdfa3ea82c50afadda3f
|
|
7
|
+
data.tar.gz: 8e1983671535f8886b5f7b920893a747d80b16535b74159c07da2ae82c1226dd66276fea515f28503217565955827ab03d51d5ac78dee42dce46d6bcd0cbe869
|
|
@@ -17,7 +17,8 @@ module Dependabot
|
|
|
17
17
|
return url unless token
|
|
18
18
|
|
|
19
19
|
basic_auth_details =
|
|
20
|
-
if token.ascii_only? && token.include?(":")
|
|
20
|
+
if token.ascii_only? && token.include?(":")
|
|
21
|
+
token
|
|
21
22
|
elsif Base64.decode64(token).ascii_only? &&
|
|
22
23
|
Base64.decode64(token).include?(":")
|
|
23
24
|
Base64.decode64(token)
|
|
@@ -29,24 +29,24 @@ module Dependabot
|
|
|
29
29
|
# Matches "requirements" preceded by a hyphen, period, underscore, start-of-string, or slash,
|
|
30
30
|
# followed by non-whitespace chars and ".txt".
|
|
31
31
|
# Examples: requirements.txt, requirements.prod.txt, requirements/production.txt
|
|
32
|
-
REQUIREMENTS_TXT_REGEX =
|
|
32
|
+
REQUIREMENTS_TXT_REGEX = %r{(?:[-._]|^|/)requirements[^\s]*\.txt$}i
|
|
33
33
|
|
|
34
34
|
# More lenient: matches "require" at the start of the filename or after a hyphen/period/underscore/
|
|
35
35
|
# slash delimiter, with an optional hyphen/underscore/slash suffix. The leading delimiter prevents
|
|
36
36
|
# matching "require" as a substring of another word (e.g. "prequire.txt", "acquire.txt").
|
|
37
37
|
# Examples: require.txt, require-test.txt, py3-require.txt, pyenv_require_e2e.txt
|
|
38
|
-
REQUIRE_TXT_REGEX =
|
|
38
|
+
REQUIRE_TXT_REGEX = %r{(?:[-._]|^|/)require(?:[-_/][^\s.]*)?\.txt$}i
|
|
39
39
|
|
|
40
40
|
# Matches "dependencies" / "dependency" preceded by a hyphen, period, underscore,
|
|
41
41
|
# start-of-string, or slash, followed by non-whitespace chars and ".txt".
|
|
42
42
|
# Examples: dependencies.txt, my-dependencies.txt, dependencies/python/ansible-lint.txt
|
|
43
|
-
DEPENDENCIES_TXT_REGEX =
|
|
43
|
+
DEPENDENCIES_TXT_REGEX = %r{(?:[-._]|^|/)dependenc(?:y|ies)[^\s]*\.txt$}i
|
|
44
44
|
|
|
45
45
|
# More lenient: matches "depend" / "depends" at the start of the filename or after a hyphen/period/
|
|
46
46
|
# underscore/slash delimiter, with an optional hyphen/underscore/slash suffix. The leading delimiter
|
|
47
47
|
# prevents matching "depend" as a substring of another word (e.g. "codependent.txt").
|
|
48
48
|
# Examples: depend.txt, depends.txt, depend-test.txt, py3-depends.txt
|
|
49
|
-
DEPEND_TXT_REGEX =
|
|
49
|
+
DEPEND_TXT_REGEX = %r{(?:[-._]|^|/)depend(?:s)?(?:[-_/][^\s.]*)?\.txt$}i
|
|
50
50
|
|
|
51
51
|
# Whether a .txt filename looks like a real pip manifest rather than an unrelated .txt file.
|
|
52
52
|
sig { params(path: String).returns(T::Boolean) }
|
|
@@ -15,7 +15,7 @@ module Dependabot
|
|
|
15
15
|
class FileFetcher < Dependabot::Python::SharedFileFetcher
|
|
16
16
|
extend T::Sig
|
|
17
17
|
|
|
18
|
-
ECOSYSTEM_SPECIFIC_FILES =
|
|
18
|
+
ECOSYSTEM_SPECIFIC_FILES = %w(Pipfile setup.py setup.cfg).freeze
|
|
19
19
|
|
|
20
20
|
sig { override.returns(T::Array[String]) }
|
|
21
21
|
def self.ecosystem_specific_required_files
|
|
@@ -114,7 +114,7 @@ module Dependabot
|
|
|
114
114
|
end.reject(&:empty?)
|
|
115
115
|
|
|
116
116
|
file_version = content_lines.first
|
|
117
|
-
return if file_version
|
|
117
|
+
return if file_version && file_version.empty?
|
|
118
118
|
return unless T.must(pyenv_versions).include?("#{file_version}\n")
|
|
119
119
|
|
|
120
120
|
file_version
|
|
@@ -126,7 +126,7 @@ module Dependabot
|
|
|
126
126
|
|
|
127
127
|
file_version = T.must(T.must(runtime_file).content)
|
|
128
128
|
.match(/(?<=python-).*/)&.to_s&.strip
|
|
129
|
-
return if file_version
|
|
129
|
+
return if file_version && file_version.empty?
|
|
130
130
|
return unless T.must(pyenv_versions).include?("#{file_version}\n")
|
|
131
131
|
|
|
132
132
|
file_version
|
|
@@ -25,23 +25,18 @@ module Dependabot
|
|
|
25
25
|
require_relative "requirement_file_updater"
|
|
26
26
|
require_relative "setup_file_sanitizer"
|
|
27
27
|
|
|
28
|
-
UNSAFE_PACKAGES =
|
|
29
|
-
INCOMPATIBLE_VERSIONS_REGEX =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Regexp::MULTILINE
|
|
34
|
-
),
|
|
35
|
-
Regexp
|
|
36
|
-
)
|
|
37
|
-
WARNINGS = T.let(/\s*# WARNING:.*\Z/m, Regexp)
|
|
38
|
-
UNSAFE_NOTE = T.let(/\s*# The following packages are considered to be unsafe.*\Z/m, Regexp)
|
|
39
|
-
RESOLVER_REGEX = T.let(/(?<=--resolver=)(\w+)/, Regexp)
|
|
40
|
-
UNSAFE_PACKAGE_OPTION_REGEX = T.let(/--unsafe-package(?:=|\s+)(?<name>[^\s\\]+)/, Regexp)
|
|
41
|
-
NATIVE_COMPILATION_ERROR = T.let(
|
|
42
|
-
"pip._internal.exceptions.InstallationSubprocessError: Getting requirements to build wheel exited with 1",
|
|
43
|
-
String
|
|
28
|
+
UNSAFE_PACKAGES = %w(setuptools distribute pip).freeze
|
|
29
|
+
INCOMPATIBLE_VERSIONS_REGEX = Regexp.new(
|
|
30
|
+
"(?:not supported between instances of 'InstallationCandidate'" \
|
|
31
|
+
"|There are incompatible versions in the resolved dependencies).*\\z",
|
|
32
|
+
Regexp::MULTILINE
|
|
44
33
|
)
|
|
34
|
+
WARNINGS = /\s*# WARNING:.*\Z/m
|
|
35
|
+
UNSAFE_NOTE = /\s*# The following packages are considered to be unsafe.*\Z/m
|
|
36
|
+
RESOLVER_REGEX = /(?<=--resolver=)(\w+)/
|
|
37
|
+
UNSAFE_PACKAGE_OPTION_REGEX = /--unsafe-package(?:=|\s+)(?<name>[^\s\\]+)/
|
|
38
|
+
NATIVE_COMPILATION_ERROR =
|
|
39
|
+
"pip._internal.exceptions.InstallationSubprocessError: Getting requirements to build wheel exited with 1"
|
|
45
40
|
|
|
46
41
|
sig { returns(T::Array[Dependabot::Dependency]) }
|
|
47
42
|
attr_reader :dependencies
|
|
@@ -60,10 +55,10 @@ module Dependabot
|
|
|
60
55
|
index_urls: T.nilable(T::Array[T.nilable(String)])
|
|
61
56
|
).void
|
|
62
57
|
end
|
|
63
|
-
def initialize(dependencies:, dependency_files:, credentials:, index_urls: nil)
|
|
64
|
-
@dependencies =
|
|
65
|
-
@dependency_files =
|
|
66
|
-
@index_urls =
|
|
58
|
+
def initialize(dependencies:, dependency_files:, credentials:, index_urls: nil)
|
|
59
|
+
@dependencies = dependencies
|
|
60
|
+
@dependency_files = dependency_files
|
|
61
|
+
@index_urls = index_urls
|
|
67
62
|
@build_isolation = T.let(true, T::Boolean)
|
|
68
63
|
@sanitized_setup_file_content = T.let({}, T::Hash[String, String])
|
|
69
64
|
@requirement_map = T.let(nil, T.nilable(T::Hash[String, T::Array[String]]))
|
|
@@ -73,7 +68,7 @@ module Dependabot
|
|
|
73
68
|
@setup_cfg_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
|
|
74
69
|
@pip_compile_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
|
|
75
70
|
@compiled_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
|
|
76
|
-
@credentials =
|
|
71
|
+
@credentials = credentials
|
|
77
72
|
end
|
|
78
73
|
|
|
79
74
|
sig { returns(T.nilable(T::Array[Dependabot::DependencyFile])) }
|
|
@@ -199,9 +194,9 @@ module Dependabot
|
|
|
199
194
|
def update_uncompiled_files(updated_files)
|
|
200
195
|
updated_filenames = updated_files.map(&:name)
|
|
201
196
|
old_reqs = T.must(T.must(dependency).previous_requirements)
|
|
202
|
-
.reject { |r| updated_filenames.include?(r
|
|
197
|
+
.reject { |r| updated_filenames.include?(r.file) }
|
|
203
198
|
new_reqs = T.must(dependency).requirements
|
|
204
|
-
.reject { |r| updated_filenames.include?(r
|
|
199
|
+
.reject { |r| updated_filenames.include?(r.file) }
|
|
205
200
|
|
|
206
201
|
return [] if new_reqs.none?
|
|
207
202
|
|
|
@@ -329,15 +324,15 @@ module Dependabot
|
|
|
329
324
|
return file.content unless file.name.end_with?(".in")
|
|
330
325
|
|
|
331
326
|
old_req = T.must(T.must(dependency).previous_requirements)
|
|
332
|
-
.find { |r| r
|
|
327
|
+
.find { |r| r.file == file.name }
|
|
333
328
|
|
|
334
329
|
return file.content unless old_req
|
|
335
|
-
return file.content if old_req == "==#{T.must(dependency).version}"
|
|
330
|
+
return file.content if old_req.requirement_string == "==#{T.must(dependency).version}"
|
|
336
331
|
|
|
337
332
|
RequirementReplacer.new(
|
|
338
333
|
content: T.must(file.content),
|
|
339
334
|
dependency_name: T.must(dependency).name,
|
|
340
|
-
old_requirement: old_req
|
|
335
|
+
old_requirement: old_req.requirement_string,
|
|
341
336
|
new_requirement: "==#{T.must(dependency).version}",
|
|
342
337
|
index_urls: @index_urls
|
|
343
338
|
).updated_content
|
|
@@ -348,17 +343,17 @@ module Dependabot
|
|
|
348
343
|
return file.content unless file.name.end_with?(".in")
|
|
349
344
|
|
|
350
345
|
old_req = T.must(T.must(dependency).previous_requirements)
|
|
351
|
-
.find { |r| r
|
|
346
|
+
.find { |r| r.file == file.name }
|
|
352
347
|
new_req = T.must(dependency).requirements
|
|
353
|
-
.find { |r| r
|
|
354
|
-
return file.content unless old_req&.
|
|
348
|
+
.find { |r| r.file == file.name }
|
|
349
|
+
return file.content unless old_req&.requirement_string
|
|
355
350
|
return file.content if old_req == new_req
|
|
356
351
|
|
|
357
352
|
RequirementReplacer.new(
|
|
358
353
|
content: T.must(file.content),
|
|
359
354
|
dependency_name: T.must(dependency).name,
|
|
360
|
-
old_requirement: old_req
|
|
361
|
-
new_requirement: T.must(new_req)
|
|
355
|
+
old_requirement: old_req.requirement_string,
|
|
356
|
+
new_requirement: T.must(T.must(new_req).requirement_string),
|
|
362
357
|
index_urls: @index_urls
|
|
363
358
|
).updated_content
|
|
364
359
|
end
|
|
@@ -679,7 +674,7 @@ module Dependabot
|
|
|
679
674
|
def filenames_to_compile
|
|
680
675
|
files_from_reqs =
|
|
681
676
|
T.must(dependency).requirements
|
|
682
|
-
.
|
|
677
|
+
.filter_map(&:file)
|
|
683
678
|
.select { |fn| fn.end_with?(".in") }
|
|
684
679
|
|
|
685
680
|
files_from_compiled_files =
|
|
@@ -22,7 +22,7 @@ module Dependabot
|
|
|
22
22
|
require_relative "pipfile_manifest_updater"
|
|
23
23
|
require_relative "setup_file_sanitizer"
|
|
24
24
|
|
|
25
|
-
DEPENDENCY_TYPES =
|
|
25
|
+
DEPENDENCY_TYPES = %w(packages dev-packages).freeze
|
|
26
26
|
|
|
27
27
|
sig { returns(T::Array[Dependabot::Dependency]) }
|
|
28
28
|
attr_reader :dependencies
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "dependabot/python/file_updater"
|
|
@@ -53,15 +53,15 @@ module Dependabot
|
|
|
53
53
|
|
|
54
54
|
# Loop through each changed requirement
|
|
55
55
|
reqs.each do |new_req, old_req|
|
|
56
|
-
raise "Bad req match" unless new_req
|
|
57
|
-
next if new_req
|
|
58
|
-
next unless new_req
|
|
56
|
+
raise "Bad req match" unless new_req.file == T.must(old_req).file
|
|
57
|
+
next if new_req.requirement == T.must(old_req).requirement
|
|
58
|
+
next unless new_req.file == manifest.name
|
|
59
59
|
|
|
60
60
|
updated_content = update_manifest_req(
|
|
61
61
|
content: updated_content,
|
|
62
62
|
dep: dependency,
|
|
63
|
-
old_req: T.must(old_req).
|
|
64
|
-
new_req: new_req.
|
|
63
|
+
old_req: T.must(T.must(old_req).requirement_string),
|
|
64
|
+
new_req: T.must(new_req.requirement_string)
|
|
65
65
|
)
|
|
66
66
|
end
|
|
67
67
|
|
|
@@ -118,7 +118,7 @@ module Dependabot
|
|
|
118
118
|
changed_requirements =
|
|
119
119
|
dependency.requirements - T.must(dependency.previous_requirements)
|
|
120
120
|
|
|
121
|
-
changed_requirements.any? { |f| f
|
|
121
|
+
changed_requirements.any? { |f| f.file == manifest.name }
|
|
122
122
|
end
|
|
123
123
|
end
|
|
124
124
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "sorbet-runtime"
|
|
@@ -19,8 +19,8 @@ module Dependabot
|
|
|
19
19
|
sig do
|
|
20
20
|
params(
|
|
21
21
|
content: String,
|
|
22
|
-
new_r:
|
|
23
|
-
old_r:
|
|
22
|
+
new_r: Dependabot::DependencyRequirement,
|
|
23
|
+
old_r: Dependabot::DependencyRequirement
|
|
24
24
|
).returns(T.nilable(String))
|
|
25
25
|
end
|
|
26
26
|
def replace(content, new_r, old_r)
|
|
@@ -96,8 +96,8 @@ module Dependabot
|
|
|
96
96
|
params(
|
|
97
97
|
content: String,
|
|
98
98
|
source_req: String,
|
|
99
|
-
new_r:
|
|
100
|
-
old_r:
|
|
99
|
+
new_r: Dependabot::DependencyRequirement,
|
|
100
|
+
old_r: Dependabot::DependencyRequirement
|
|
101
101
|
).returns(T.nilable(String))
|
|
102
102
|
end
|
|
103
103
|
def replace_with_source_requirement(content, source_req, new_r, old_r)
|
|
@@ -105,7 +105,11 @@ module Dependabot
|
|
|
105
105
|
return unless match
|
|
106
106
|
|
|
107
107
|
declaration = T.must(match[:declaration])
|
|
108
|
-
new_req_str = rewrite_pep508_requirement(
|
|
108
|
+
new_req_str = rewrite_pep508_requirement(
|
|
109
|
+
source_req,
|
|
110
|
+
T.must(old_r.requirement_string),
|
|
111
|
+
T.must(new_r.requirement_string)
|
|
112
|
+
)
|
|
109
113
|
content.sub(declaration, declaration.sub(source_req, new_req_str))
|
|
110
114
|
end
|
|
111
115
|
|
|
@@ -116,13 +120,13 @@ module Dependabot
|
|
|
116
120
|
sig do
|
|
117
121
|
params(
|
|
118
122
|
content: String,
|
|
119
|
-
new_r:
|
|
120
|
-
old_r:
|
|
123
|
+
new_r: Dependabot::DependencyRequirement,
|
|
124
|
+
old_r: Dependabot::DependencyRequirement
|
|
121
125
|
).returns(T.nilable(String))
|
|
122
126
|
end
|
|
123
127
|
def replace_with_normalized_requirement(content, new_r, old_r)
|
|
124
|
-
old_req = old_r
|
|
125
|
-
new_req = new_r
|
|
128
|
+
old_req = T.must(old_r.requirement_string)
|
|
129
|
+
new_req = T.must(new_r.requirement_string)
|
|
126
130
|
|
|
127
131
|
match = content.match(normalized_declaration_regex(old_req))
|
|
128
132
|
return unless match
|
|
@@ -45,7 +45,7 @@ module Dependabot
|
|
|
45
45
|
@dependencies = dependencies
|
|
46
46
|
@dependency_files = dependency_files
|
|
47
47
|
@credentials = credentials
|
|
48
|
-
@cooldown =
|
|
48
|
+
@cooldown = cooldown
|
|
49
49
|
@updated_dependency_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
|
|
50
50
|
@prepared_pyproject = T.let(nil, T.nilable(String))
|
|
51
51
|
@pyproject = T.let(nil, T.nilable(Dependabot::DependencyFile))
|
|
@@ -99,7 +99,7 @@ module Dependabot
|
|
|
99
99
|
updated_content = content.dup
|
|
100
100
|
|
|
101
101
|
dependency.requirements.zip(T.must(dependency.previous_requirements)).each do |new_r, old_r|
|
|
102
|
-
next unless new_r
|
|
102
|
+
next unless new_r.file == pyproject&.name && T.must(old_r).file == pyproject&.name
|
|
103
103
|
|
|
104
104
|
updated_content = replace_dep(dependency, T.must(updated_content), new_r, T.must(old_r))
|
|
105
105
|
end
|
|
@@ -109,7 +109,7 @@ module Dependabot
|
|
|
109
109
|
updated_content
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
-
sig { params(dep: Dependabot::Dependency, content: String, new_r:
|
|
112
|
+
sig { params(dep: Dependabot::Dependency, content: String, new_r: Dependabot::DependencyRequirement, old_r: Dependabot::DependencyRequirement).returns(String) }
|
|
113
113
|
def replace_dep(dep, content, new_r, old_r)
|
|
114
114
|
return update_git_tag(dep, content, new_r, old_r) if git_dependency?(new_r) && git_dependency?(old_r)
|
|
115
115
|
|
|
@@ -119,10 +119,10 @@ module Dependabot
|
|
|
119
119
|
content
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
-
sig { params(dep: Dependabot::Dependency, content: String, new_r:
|
|
122
|
+
sig { params(dep: Dependabot::Dependency, content: String, new_r: Dependabot::DependencyRequirement, old_r: Dependabot::DependencyRequirement).returns(T.nilable(String)) }
|
|
123
123
|
def replace_poetry_dep(dep, content, new_r, old_r)
|
|
124
|
-
new_req = new_r
|
|
125
|
-
old_req = old_r
|
|
124
|
+
new_req = T.must(new_r.requirement_string)
|
|
125
|
+
old_req = T.must(old_r.requirement_string)
|
|
126
126
|
|
|
127
127
|
declaration_regex = declaration_regex(dep, old_r)
|
|
128
128
|
declaration_match = content.match(declaration_regex)
|
|
@@ -135,10 +135,10 @@ module Dependabot
|
|
|
135
135
|
content.sub(T.must(declaration), new_declaration)
|
|
136
136
|
end
|
|
137
137
|
|
|
138
|
-
sig { params(dep: Dependabot::Dependency, content: String, new_r:
|
|
138
|
+
sig { params(dep: Dependabot::Dependency, content: String, new_r: Dependabot::DependencyRequirement, old_r: Dependabot::DependencyRequirement).returns(T.nilable(String)) }
|
|
139
139
|
def replace_poetry_table_dep(dep, content, new_r, old_r)
|
|
140
|
-
old_req = old_r
|
|
141
|
-
new_req = new_r
|
|
140
|
+
old_req = T.must(old_r.requirement_string)
|
|
141
|
+
new_req = T.must(new_r.requirement_string)
|
|
142
142
|
regex = table_declaration_regex(dep, new_r)
|
|
143
143
|
|
|
144
144
|
return unless content.match(regex)
|
|
@@ -151,20 +151,20 @@ module Dependabot
|
|
|
151
151
|
end
|
|
152
152
|
end
|
|
153
153
|
|
|
154
|
-
sig { params(dep: Dependabot::Dependency, content: String, new_r:
|
|
154
|
+
sig { params(dep: Dependabot::Dependency, content: String, new_r: Dependabot::DependencyRequirement, old_r: Dependabot::DependencyRequirement).returns(T.nilable(String)) }
|
|
155
155
|
def replace_pep621_dep(dep, content, new_r, old_r)
|
|
156
156
|
Pep621Updater.new(dep: dep).replace(content, new_r, old_r)
|
|
157
157
|
end
|
|
158
158
|
|
|
159
|
-
sig { params(req:
|
|
159
|
+
sig { params(req: Dependabot::DependencyRequirement).returns(T::Boolean) }
|
|
160
160
|
def git_dependency?(req)
|
|
161
|
-
req.
|
|
161
|
+
req.source_string("type") == "git"
|
|
162
162
|
end
|
|
163
163
|
|
|
164
|
-
sig { params(dep: Dependabot::Dependency, content: String, new_r:
|
|
164
|
+
sig { params(dep: Dependabot::Dependency, content: String, new_r: Dependabot::DependencyRequirement, old_r: Dependabot::DependencyRequirement).returns(String) }
|
|
165
165
|
def update_git_tag(dep, content, new_r, old_r)
|
|
166
|
-
old_tag = old_r.
|
|
167
|
-
new_tag = new_r.
|
|
166
|
+
old_tag = old_r.source_string("ref")
|
|
167
|
+
new_tag = new_r.source_string("ref")
|
|
168
168
|
|
|
169
169
|
return content if old_tag == new_tag
|
|
170
170
|
|
|
@@ -172,7 +172,7 @@ module Dependabot
|
|
|
172
172
|
# Example: fastapi = { git = "...", extras = ["all"], tag = "0.110.0" }
|
|
173
173
|
git_dep_regex = /
|
|
174
174
|
^(\s*)#{Regexp.escape(dep.name)}(\s*=\s*\{[^}]*tag\s*=\s*)
|
|
175
|
-
["']#{Regexp.escape(old_tag)}["']([^}]*\})
|
|
175
|
+
["']#{Regexp.escape(T.must(old_tag))}["']([^}]*\})
|
|
176
176
|
/mx
|
|
177
177
|
|
|
178
178
|
content.gsub(git_dep_regex) do
|
|
@@ -233,7 +233,7 @@ module Dependabot
|
|
|
233
233
|
# Skip Git dependencies - they use tags/refs, not versions
|
|
234
234
|
next if git_dependency_being_updated?(dep)
|
|
235
235
|
|
|
236
|
-
if dep.requirements.find { |r| r
|
|
236
|
+
if dep.requirements.find { |r| r.file == pyproject&.name }
|
|
237
237
|
lock_declaration_to_new_version!(poetry_object, dep)
|
|
238
238
|
else
|
|
239
239
|
create_declaration_at_new_version!(poetry_object, dep)
|
|
@@ -302,7 +302,7 @@ module Dependabot
|
|
|
302
302
|
|
|
303
303
|
sig { params(dep: Dependabot::Dependency).returns(T::Boolean) }
|
|
304
304
|
def git_dependency_being_updated?(dep)
|
|
305
|
-
dep.requirements.any? { |r| r.
|
|
305
|
+
dep.requirements.any? { |r| r.source_string("type") == "git" }
|
|
306
306
|
end
|
|
307
307
|
|
|
308
308
|
sig { params(pyproject_content: String).returns(String) }
|
|
@@ -382,17 +382,17 @@ module Dependabot
|
|
|
382
382
|
end
|
|
383
383
|
end
|
|
384
384
|
|
|
385
|
-
sig { params(dep: Dependabot::Dependency, old_req:
|
|
385
|
+
sig { params(dep: Dependabot::Dependency, old_req: Dependabot::DependencyRequirement).returns(Regexp) }
|
|
386
386
|
def declaration_regex(dep, old_req)
|
|
387
|
-
group = old_req
|
|
387
|
+
group = T.must(old_req.groups).first
|
|
388
388
|
|
|
389
389
|
header_regex = "#{group}(?:\\.dependencies)?\\]\s*(?:\s*#.*?)*?"
|
|
390
390
|
/#{header_regex}(?:\r?\n).*?(?<declaration>(?:^\s*|["'])#{escape(dep)}["']?\s*=[^\r\n]*)(?=\r?\n|$)/mi
|
|
391
391
|
end
|
|
392
392
|
|
|
393
|
-
sig { params(dep: Dependabot::Dependency, old_req:
|
|
393
|
+
sig { params(dep: Dependabot::Dependency, old_req: Dependabot::DependencyRequirement).returns(Regexp) }
|
|
394
394
|
def table_declaration_regex(dep, old_req)
|
|
395
|
-
/tool\.poetry\.#{old_req
|
|
395
|
+
/tool\.poetry\.#{T.must(old_req.groups).first}\.#{escape(dep)}\](?:\r?\n).*?\s*version\s* =.*?(?:\r?\n)/m
|
|
396
396
|
end
|
|
397
397
|
|
|
398
398
|
sig { params(dep: Dependency).returns(String) }
|
|
@@ -410,7 +410,7 @@ module Dependabot
|
|
|
410
410
|
changed_requirements =
|
|
411
411
|
dependency.requirements - T.must(dependency.previous_requirements)
|
|
412
412
|
|
|
413
|
-
changed_requirements.any? { |f| f
|
|
413
|
+
changed_requirements.any? { |f| f.file == file.name }
|
|
414
414
|
end
|
|
415
415
|
|
|
416
416
|
sig { params(file: Dependabot::DependencyFile, content: String).returns(Dependabot::DependencyFile) }
|
|
@@ -18,10 +18,7 @@ module Dependabot
|
|
|
18
18
|
|
|
19
19
|
# Fixed regex for extracting the name+extras prefix from a PEP 508 entry.
|
|
20
20
|
# Does not interpolate library input, avoiding polynomial backtracking.
|
|
21
|
-
PEP508_PREFIX =
|
|
22
|
-
/\A(?<prefix>(?<name>[a-zA-Z0-9](?:[a-zA-Z0-9._-]*[a-zA-Z0-9])?)(?:\[[^\]]*\])?)/i,
|
|
23
|
-
Regexp
|
|
24
|
-
)
|
|
21
|
+
PEP508_PREFIX = /\A(?<prefix>(?<name>[a-zA-Z0-9](?:[a-zA-Z0-9._-]*[a-zA-Z0-9])?)(?:\[[^\]]*\])?)/i
|
|
25
22
|
|
|
26
23
|
# Pins a single PEP 508 dependency entry string to a specific version,
|
|
27
24
|
# preserving extras and environment markers.
|
|
@@ -142,7 +139,7 @@ module Dependabot
|
|
|
142
139
|
.gsub('#{', "{")
|
|
143
140
|
end
|
|
144
141
|
|
|
145
|
-
UNSUPPORTED_SOURCE_TYPES =
|
|
142
|
+
UNSUPPORTED_SOURCE_TYPES = %w(directory file url).freeze
|
|
146
143
|
|
|
147
144
|
sig { params(dependencies: T::Array[Dependabot::Dependency]).returns(String) }
|
|
148
145
|
def freeze_top_level_dependencies_except(dependencies)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "sorbet-runtime"
|
|
@@ -13,6 +13,10 @@ module Dependabot
|
|
|
13
13
|
class RequirementFileUpdater
|
|
14
14
|
extend T::Sig
|
|
15
15
|
|
|
16
|
+
RequirementChange = T.type_alias do
|
|
17
|
+
[Dependabot::DependencyRequirement, T.nilable(Dependabot::DependencyRequirement)]
|
|
18
|
+
end
|
|
19
|
+
|
|
16
20
|
require_relative "requirement_replacer"
|
|
17
21
|
|
|
18
22
|
sig { returns(T::Array[Dependabot::Dependency]) }
|
|
@@ -33,10 +37,10 @@ module Dependabot
|
|
|
33
37
|
).void
|
|
34
38
|
end
|
|
35
39
|
def initialize(dependencies:, dependency_files:, credentials:, index_urls: nil)
|
|
36
|
-
@dependencies =
|
|
37
|
-
@dependency_files =
|
|
38
|
-
@credentials =
|
|
39
|
-
@index_urls =
|
|
40
|
+
@dependencies = dependencies
|
|
41
|
+
@dependency_files = dependency_files
|
|
42
|
+
@credentials = credentials
|
|
43
|
+
@index_urls = index_urls
|
|
40
44
|
@updated_dependency_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
|
|
41
45
|
end
|
|
42
46
|
|
|
@@ -58,9 +62,9 @@ module Dependabot
|
|
|
58
62
|
updated_contents = T.let({}, T::Hash[String, String])
|
|
59
63
|
|
|
60
64
|
unique_requirement_changes.each do |pair|
|
|
61
|
-
new_req =
|
|
65
|
+
new_req = pair[0]
|
|
62
66
|
old_req = pair[1]
|
|
63
|
-
filename = new_req.
|
|
67
|
+
filename = T.must(new_req.file)
|
|
64
68
|
content = updated_contents[filename] || T.must(T.must(get_original_file(filename)).content)
|
|
65
69
|
updated_contents[filename] = updated_requirement_or_setup_file_content(content, new_req, old_req)
|
|
66
70
|
end
|
|
@@ -77,37 +81,37 @@ module Dependabot
|
|
|
77
81
|
# Deduplicates requirements that share the same file and requirement strings.
|
|
78
82
|
# The replacer's regex matches all extras variants at once, so one call per
|
|
79
83
|
# unique (file, old_requirement, new_requirement) is sufficient.
|
|
80
|
-
sig { returns(T::Array[
|
|
84
|
+
sig { returns(T::Array[RequirementChange]) }
|
|
81
85
|
def unique_requirement_changes
|
|
82
86
|
previous_reqs = dependency.previous_requirements || []
|
|
83
87
|
|
|
84
88
|
changes = dependency.requirements.filter_map do |new_req|
|
|
85
|
-
old_req = previous_reqs.find { |r| r
|
|
89
|
+
old_req = previous_reqs.find { |r| r.file == new_req.file && r.groups == new_req.groups }
|
|
86
90
|
next if new_req == old_req
|
|
87
91
|
|
|
88
|
-
[new_req, old_req]
|
|
92
|
+
T.let([new_req, old_req], RequirementChange)
|
|
89
93
|
end
|
|
90
94
|
|
|
91
95
|
changes.uniq do |pair|
|
|
92
96
|
new_req = pair[0]
|
|
93
97
|
old_req = pair[1]
|
|
94
|
-
[new_req
|
|
98
|
+
[new_req.file, old_req&.requirement, new_req.requirement]
|
|
95
99
|
end
|
|
96
100
|
end
|
|
97
101
|
|
|
98
102
|
sig do
|
|
99
103
|
params(
|
|
100
104
|
content: String,
|
|
101
|
-
new_req:
|
|
102
|
-
old_req: T.nilable(
|
|
105
|
+
new_req: Dependabot::DependencyRequirement,
|
|
106
|
+
old_req: T.nilable(Dependabot::DependencyRequirement)
|
|
103
107
|
).returns(String)
|
|
104
108
|
end
|
|
105
109
|
def updated_requirement_or_setup_file_content(content, new_req, old_req)
|
|
106
110
|
RequirementReplacer.new(
|
|
107
111
|
content: content,
|
|
108
112
|
dependency_name: dependency.name,
|
|
109
|
-
old_requirement: old_req&.
|
|
110
|
-
new_requirement: new_req.
|
|
113
|
+
old_requirement: old_req&.requirement_string,
|
|
114
|
+
new_requirement: T.must(new_req.requirement_string),
|
|
111
115
|
new_hash_version: dependency.version,
|
|
112
116
|
index_urls: @index_urls
|
|
113
117
|
).updated_content
|
|
@@ -37,12 +37,12 @@ module Dependabot
|
|
|
37
37
|
new_hash_version: nil,
|
|
38
38
|
index_urls: nil
|
|
39
39
|
)
|
|
40
|
-
@content =
|
|
40
|
+
@content = content
|
|
41
41
|
@dependency_name = T.let(normalise(dependency_name), String)
|
|
42
|
-
@old_requirement =
|
|
43
|
-
@new_requirement =
|
|
44
|
-
@new_hash_version =
|
|
45
|
-
@index_urls =
|
|
42
|
+
@old_requirement = old_requirement
|
|
43
|
+
@new_requirement = new_requirement
|
|
44
|
+
@new_hash_version = new_hash_version
|
|
45
|
+
@index_urls = index_urls
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
sig { returns(String) }
|
|
@@ -20,8 +20,8 @@ module Dependabot
|
|
|
20
20
|
).void
|
|
21
21
|
end
|
|
22
22
|
def initialize(setup_file:, setup_cfg:)
|
|
23
|
-
@setup_file =
|
|
24
|
-
@setup_cfg =
|
|
23
|
+
@setup_file = setup_file
|
|
24
|
+
@setup_cfg = setup_cfg
|
|
25
25
|
@install_requires_array = T.let(nil, T.nilable(T::Array[String]))
|
|
26
26
|
@setup_requires_array = T.let(nil, T.nilable(T::Array[String]))
|
|
27
27
|
@extras_require_hash = T.let(nil, T.nilable(T::Hash[String, T::Array[String]]))
|
|
@@ -61,10 +61,9 @@ module Dependabot
|
|
|
61
61
|
@install_requires_array ||=
|
|
62
62
|
parsed_setup_file.dependencies.filter_map do |dep|
|
|
63
63
|
first = T.must(dep.requirements.first)
|
|
64
|
-
next unless first
|
|
65
|
-
.include?("install_requires")
|
|
64
|
+
next unless first.groups&.include?("install_requires")
|
|
66
65
|
|
|
67
|
-
name_with_extras(dep) + first
|
|
66
|
+
name_with_extras(dep) + first.requirement.to_s
|
|
68
67
|
end
|
|
69
68
|
end
|
|
70
69
|
|
|
@@ -73,10 +72,9 @@ module Dependabot
|
|
|
73
72
|
@setup_requires_array ||=
|
|
74
73
|
parsed_setup_file.dependencies.filter_map do |dep|
|
|
75
74
|
first = T.must(dep.requirements.first)
|
|
76
|
-
next unless first
|
|
77
|
-
.include?("setup_requires")
|
|
75
|
+
next unless first.groups&.include?("setup_requires")
|
|
78
76
|
|
|
79
|
-
name_with_extras(dep) + first
|
|
77
|
+
name_with_extras(dep) + first.requirement.to_s
|
|
80
78
|
end
|
|
81
79
|
end
|
|
82
80
|
|
|
@@ -87,12 +85,13 @@ module Dependabot
|
|
|
87
85
|
hash = {}
|
|
88
86
|
parsed_setup_file.dependencies.each do |dep|
|
|
89
87
|
first = T.must(dep.requirements.first)
|
|
90
|
-
first
|
|
88
|
+
T.must(first.groups).each do |group|
|
|
91
89
|
next unless group.start_with?("extras_require:")
|
|
92
90
|
|
|
93
|
-
|
|
94
|
-
hash[
|
|
95
|
-
|
|
91
|
+
group_name = group.to_s
|
|
92
|
+
hash[group_name.split(":").last] ||= []
|
|
93
|
+
hash[group_name.split(":").last] <<
|
|
94
|
+
(name_with_extras(dep) + first.requirement.to_s)
|
|
96
95
|
end
|
|
97
96
|
end
|
|
98
97
|
|
|
@@ -46,7 +46,7 @@ module Dependabot
|
|
|
46
46
|
changed_reqs = reqs.zip(dependencies.flat_map(&:previous_requirements))
|
|
47
47
|
.reject { |(new_req, old_req)| new_req == old_req }
|
|
48
48
|
.map(&:first)
|
|
49
|
-
changed_req_files = changed_reqs.
|
|
49
|
+
changed_req_files = changed_reqs.filter_map(&:file)
|
|
50
50
|
|
|
51
51
|
# If there are no requirements then this is a sub-dependency. It
|
|
52
52
|
# must come from one of Pipenv, Poetry or pip-tools, and can't come
|
|
@@ -25,9 +25,9 @@ module Dependabot
|
|
|
25
25
|
).void
|
|
26
26
|
end
|
|
27
27
|
def initialize(dependency_files:, credentials:, dependency:)
|
|
28
|
-
@dependency_files =
|
|
29
|
-
@credentials =
|
|
30
|
-
@dependency =
|
|
28
|
+
@dependency_files = dependency_files
|
|
29
|
+
@credentials = credentials
|
|
30
|
+
@dependency = dependency
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
sig { returns(T::Array[String]) }
|
|
@@ -143,7 +143,7 @@ module Dependabot
|
|
|
143
143
|
sig { returns(T.nilable(String)) }
|
|
144
144
|
def lockfile_section
|
|
145
145
|
if current_dependency.requirements.any?
|
|
146
|
-
T.must(current_dependency.requirements.first)
|
|
146
|
+
T.must(T.must(current_dependency.requirements.first).groups).first&.to_s
|
|
147
147
|
else
|
|
148
148
|
parsed_lockfile = JSON.parse(T.must(T.must(lockfile).content))
|
|
149
149
|
Python::FileParser::DEPENDENCY_GROUP_KEYS.each do |keys|
|
|
@@ -27,7 +27,7 @@ module Dependabot
|
|
|
27
27
|
|
|
28
28
|
sig { params(pyproject_content: T.nilable(String)).void }
|
|
29
29
|
def initialize(pyproject_content:)
|
|
30
|
-
@pyproject_content =
|
|
30
|
+
@pyproject_content = pyproject_content
|
|
31
31
|
@plugins_installed = T.let(false, T::Boolean)
|
|
32
32
|
end
|
|
33
33
|
|
|
@@ -12,7 +12,7 @@ module Dependabot
|
|
|
12
12
|
class Requirement < Dependabot::Requirement
|
|
13
13
|
extend T::Sig
|
|
14
14
|
|
|
15
|
-
OR_SEPARATOR =
|
|
15
|
+
OR_SEPARATOR = /(?<=[a-zA-Z0-9)*])\s*\|+/
|
|
16
16
|
|
|
17
17
|
# Add equality and arbitrary-equality matchers
|
|
18
18
|
OPS = T.let(
|
|
@@ -28,8 +28,8 @@ module Dependabot
|
|
|
28
28
|
version_pattern = Python::Version::VERSION_PATTERN
|
|
29
29
|
|
|
30
30
|
PATTERN_RAW = T.let("\\s*(?<op>#{quoted})?\\s*(?<version>#{version_pattern})\\s*".freeze, String)
|
|
31
|
-
PATTERN =
|
|
32
|
-
PARENS_PATTERN =
|
|
31
|
+
PATTERN = /\A#{PATTERN_RAW}\z/
|
|
32
|
+
PARENS_PATTERN = /\A\(([^)]+)\)\z/
|
|
33
33
|
|
|
34
34
|
sig { params(obj: T.any(Gem::Version, String)).returns([String, Gem::Version]) }
|
|
35
35
|
def self.parse(obj)
|
|
@@ -107,11 +107,14 @@ module Dependabot
|
|
|
107
107
|
req_string = req_string.gsub("~=", "~>")
|
|
108
108
|
req_string = req_string.gsub(/(?<=\d)[<=>].*\Z/, "")
|
|
109
109
|
|
|
110
|
-
if req_string.match?(/~[^>]/)
|
|
111
|
-
|
|
110
|
+
if req_string.match?(/~[^>]/)
|
|
111
|
+
convert_tilde_req(req_string)
|
|
112
|
+
elsif req_string.start_with?("^")
|
|
113
|
+
convert_caret_req(req_string)
|
|
112
114
|
elsif req_string.match?(/^=?={0,2}\s*\d+\.\d+(\.\d+)?(-[a-z0-9.-]+)?(\.\*)?$/i)
|
|
113
115
|
convert_exact(req_string)
|
|
114
|
-
elsif req_string.include?(".*")
|
|
116
|
+
elsif req_string.include?(".*")
|
|
117
|
+
convert_wildcard(req_string)
|
|
115
118
|
else
|
|
116
119
|
req_string
|
|
117
120
|
end
|
|
@@ -21,10 +21,10 @@ module Dependabot
|
|
|
21
21
|
|
|
22
22
|
abstract!
|
|
23
23
|
|
|
24
|
-
CHILD_REQUIREMENT_REGEX =
|
|
25
|
-
CONSTRAINT_REGEX =
|
|
26
|
-
DEPENDENCY_TYPES =
|
|
27
|
-
MAX_FILE_SIZE =
|
|
24
|
+
CHILD_REQUIREMENT_REGEX = /^-r\s?(?<path>.*\.(?:txt|in))/
|
|
25
|
+
CONSTRAINT_REGEX = /^-c\s?(?<path>.*\.(?:txt|in))/
|
|
26
|
+
DEPENDENCY_TYPES = %w(packages dev-packages).freeze
|
|
27
|
+
MAX_FILE_SIZE = 500_000
|
|
28
28
|
|
|
29
29
|
sig { abstract.returns(T::Array[String]) }
|
|
30
30
|
def self.ecosystem_specific_required_files; end
|
|
@@ -34,7 +34,7 @@ module Dependabot
|
|
|
34
34
|
return true if filenames.any? { |name| name.end_with?(".txt", ".in") }
|
|
35
35
|
return true if filenames.include?("requirements")
|
|
36
36
|
return true if filenames.include?("pyproject.toml")
|
|
37
|
-
return true if filenames.
|
|
37
|
+
return true if filenames.intersect?(ecosystem_specific_required_files)
|
|
38
38
|
|
|
39
39
|
false
|
|
40
40
|
end
|
|
@@ -27,16 +27,14 @@ module Dependabot
|
|
|
27
27
|
class PipCompileVersionResolver # rubocop:disable Metrics/ClassLength
|
|
28
28
|
extend T::Sig
|
|
29
29
|
|
|
30
|
-
GIT_DEPENDENCY_UNREACHABLE_REGEX =
|
|
31
|
-
GIT_REFERENCE_NOT_FOUND_REGEX =
|
|
32
|
-
NATIVE_COMPILATION_ERROR =
|
|
33
|
-
"pip._internal.exceptions.InstallationSubprocessError: Getting requirements to build wheel exited with 1"
|
|
34
|
-
String
|
|
35
|
-
)
|
|
30
|
+
GIT_DEPENDENCY_UNREACHABLE_REGEX = /git clone --filter=blob:none --quiet (?<url>[^\s]+).* /
|
|
31
|
+
GIT_REFERENCE_NOT_FOUND_REGEX = /Did not find branch or tag '(?<tag>[^\n"]+)'/m
|
|
32
|
+
NATIVE_COMPILATION_ERROR =
|
|
33
|
+
"pip._internal.exceptions.InstallationSubprocessError: Getting requirements to build wheel exited with 1"
|
|
36
34
|
# See https://packaging.python.org/en/latest/tutorials/packaging-projects/#configuring-metadata
|
|
37
|
-
PYTHON_PACKAGE_NAME_REGEX =
|
|
38
|
-
RESOLUTION_IMPOSSIBLE_ERROR =
|
|
39
|
-
ERROR_REGEX =
|
|
35
|
+
PYTHON_PACKAGE_NAME_REGEX = /[A-Za-z0-9_\-]+/
|
|
36
|
+
RESOLUTION_IMPOSSIBLE_ERROR = "ResolutionImpossible"
|
|
37
|
+
ERROR_REGEX = /(?<=ERROR\:\W).*$/
|
|
40
38
|
|
|
41
39
|
sig { returns(Dependabot::Dependency) }
|
|
42
40
|
attr_reader :dependency
|
|
@@ -62,10 +60,10 @@ module Dependabot
|
|
|
62
60
|
).void
|
|
63
61
|
end
|
|
64
62
|
def initialize(dependency:, dependency_files:, credentials:, repo_contents_path:)
|
|
65
|
-
@dependency =
|
|
66
|
-
@dependency_files =
|
|
67
|
-
@credentials =
|
|
68
|
-
@repo_contents_path =
|
|
63
|
+
@dependency = dependency
|
|
64
|
+
@dependency_files = dependency_files
|
|
65
|
+
@credentials = credentials
|
|
66
|
+
@repo_contents_path = repo_contents_path
|
|
69
67
|
@build_isolation = T.let(true, T::Boolean)
|
|
70
68
|
@error_handler = T.let(PipCompileErrorHandler.new, PipCompileErrorHandler)
|
|
71
69
|
end
|
|
@@ -402,14 +400,14 @@ module Dependabot
|
|
|
402
400
|
def update_req_file(file, updated_req)
|
|
403
401
|
return T.must(file.content) unless file.name.end_with?(".in")
|
|
404
402
|
|
|
405
|
-
req = dependency.requirements.find { |r| r
|
|
403
|
+
req = dependency.requirements.find { |r| r.file == file.name }
|
|
406
404
|
|
|
407
|
-
return T.must(file.content) + "\n#{dependency.name} #{updated_req}" unless req&.
|
|
405
|
+
return T.must(file.content) + "\n#{dependency.name} #{updated_req}" unless req&.requirement_string
|
|
408
406
|
|
|
409
407
|
Python::FileUpdater::RequirementReplacer.new(
|
|
410
408
|
content: T.must(file.content),
|
|
411
409
|
dependency_name: dependency.name,
|
|
412
|
-
old_requirement: req
|
|
410
|
+
old_requirement: req.requirement_string,
|
|
413
411
|
new_requirement: updated_req
|
|
414
412
|
).updated_content
|
|
415
413
|
end
|
|
@@ -428,7 +426,7 @@ module Dependabot
|
|
|
428
426
|
def filenames_to_compile
|
|
429
427
|
files_from_reqs =
|
|
430
428
|
dependency.requirements
|
|
431
|
-
.
|
|
429
|
+
.filter_map(&:file)
|
|
432
430
|
.select { |fn| fn.end_with?(".in") }
|
|
433
431
|
|
|
434
432
|
files_from_compiled_files =
|
|
@@ -585,13 +583,13 @@ module Dependabot
|
|
|
585
583
|
class PipCompileErrorHandler
|
|
586
584
|
extend T::Sig
|
|
587
585
|
|
|
588
|
-
SUBPROCESS_ERROR =
|
|
586
|
+
SUBPROCESS_ERROR = /subprocess-exited-with-error/
|
|
589
587
|
|
|
590
|
-
INSTALLATION_ERROR =
|
|
588
|
+
INSTALLATION_ERROR = /InstallationError/
|
|
591
589
|
|
|
592
|
-
INSTALLATION_SUBPROCESS_ERROR =
|
|
590
|
+
INSTALLATION_SUBPROCESS_ERROR = /InstallationSubprocessError/
|
|
593
591
|
|
|
594
|
-
HASH_MISMATCH =
|
|
592
|
+
HASH_MISMATCH = /HashMismatch/
|
|
595
593
|
|
|
596
594
|
sig { params(error: String).void }
|
|
597
595
|
def handle_pipcompile_error(error)
|
|
@@ -182,7 +182,9 @@ module Dependabot
|
|
|
182
182
|
sig { returns(T::Array[[String, String]]) }
|
|
183
183
|
def normalized_requirement_files
|
|
184
184
|
dependency.requirements.filter_map do |req|
|
|
185
|
-
raw_file =
|
|
185
|
+
raw_file = req.file
|
|
186
|
+
next unless raw_file
|
|
187
|
+
|
|
186
188
|
[raw_file, normalize_path(raw_file)]
|
|
187
189
|
end
|
|
188
190
|
end
|
|
@@ -56,10 +56,10 @@ module Dependabot
|
|
|
56
56
|
).void
|
|
57
57
|
end
|
|
58
58
|
def initialize(dependency:, dependency_files:, credentials:, repo_contents_path:)
|
|
59
|
-
@dependency =
|
|
60
|
-
@dependency_files =
|
|
61
|
-
@credentials =
|
|
62
|
-
@repo_contents_path =
|
|
59
|
+
@dependency = dependency
|
|
60
|
+
@dependency_files = dependency_files
|
|
61
|
+
@credentials = credentials
|
|
62
|
+
@repo_contents_path = repo_contents_path
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
sig { params(requirement: T.nilable(String)).returns(T.nilable(Dependabot::Python::Version)) }
|
|
@@ -78,10 +78,10 @@ module Dependabot
|
|
|
78
78
|
).void
|
|
79
79
|
end
|
|
80
80
|
def initialize(dependency:, dependency_files:, credentials:, repo_contents_path:)
|
|
81
|
-
@dependency =
|
|
82
|
-
@dependency_files =
|
|
83
|
-
@credentials =
|
|
84
|
-
@repo_contents_path =
|
|
81
|
+
@dependency = dependency
|
|
82
|
+
@dependency_files = dependency_files
|
|
83
|
+
@credentials = credentials
|
|
84
|
+
@repo_contents_path = repo_contents_path
|
|
85
85
|
@error_handler = T.let(
|
|
86
86
|
PoetryErrorHandler.new(dependencies: dependency, dependency_files: dependency_files),
|
|
87
87
|
Dependabot::Python::PoetryErrorHandler
|
|
@@ -333,7 +333,7 @@ module Dependabot
|
|
|
333
333
|
end
|
|
334
334
|
|
|
335
335
|
# If this is a sub-dependency, add the new requirement
|
|
336
|
-
unless dependency.requirements.find { |r| r
|
|
336
|
+
unless dependency.requirements.find { |r| r.file == T.must(pyproject).name }
|
|
337
337
|
poetry_object[subdep_type] ||= {}
|
|
338
338
|
poetry_object[subdep_type][dependency.name] = updated_requirement
|
|
339
339
|
end
|
|
@@ -490,8 +490,8 @@ module Dependabot
|
|
|
490
490
|
).void
|
|
491
491
|
end
|
|
492
492
|
def initialize(dependencies:, dependency_files:)
|
|
493
|
-
@dependencies =
|
|
494
|
-
@dependency_files =
|
|
493
|
+
@dependencies = dependencies
|
|
494
|
+
@dependency_files = dependency_files
|
|
495
495
|
end
|
|
496
496
|
|
|
497
497
|
private
|
|
@@ -16,9 +16,9 @@ module Dependabot
|
|
|
16
16
|
class RequirementsUpdater
|
|
17
17
|
extend T::Sig
|
|
18
18
|
|
|
19
|
-
PYPROJECT_OR_SEPARATOR =
|
|
20
|
-
PYPROJECT_SEPARATOR =
|
|
21
|
-
LOWER_BOUND_OPS =
|
|
19
|
+
PYPROJECT_OR_SEPARATOR = /(?<=[a-zA-Z0-9*])\s*\|+/
|
|
20
|
+
PYPROJECT_SEPARATOR = /#{PYPROJECT_OR_SEPARATOR}|,/
|
|
21
|
+
LOWER_BOUND_OPS = %w(> >=).freeze
|
|
22
22
|
|
|
23
23
|
class UnfixableRequirement < StandardError; end
|
|
24
24
|
|
|
@@ -52,8 +52,8 @@ module Dependabot
|
|
|
52
52
|
requirements.map { |req| Dependabot::DependencyRequirement.create(req) },
|
|
53
53
|
T::Array[Dependabot::DependencyRequirement]
|
|
54
54
|
)
|
|
55
|
-
@update_strategy =
|
|
56
|
-
@has_lockfile =
|
|
55
|
+
@update_strategy = update_strategy
|
|
56
|
+
@has_lockfile = has_lockfile
|
|
57
57
|
@latest_resolvable_version = T.let(nil, T.nilable(Dependabot::Python::Version))
|
|
58
58
|
|
|
59
59
|
return unless latest_resolvable_version
|
|
@@ -66,45 +66,49 @@ module Dependabot
|
|
|
66
66
|
return requirements if update_strategy.lockfile_only?
|
|
67
67
|
|
|
68
68
|
requirements.map do |req|
|
|
69
|
-
case req
|
|
69
|
+
case req.file
|
|
70
70
|
when /setup\.(?:py|cfg)$/ then updated_setup_requirement(req)
|
|
71
71
|
when ->(file) { file.end_with?("pyproject.toml") } then updated_pyproject_requirement(req)
|
|
72
72
|
when "Pipfile" then updated_pipfile_requirement(req)
|
|
73
73
|
when /\.txt$|\.in$/ then updated_requirement(req)
|
|
74
|
-
else raise "Unexpected filename: #{req
|
|
74
|
+
else raise "Unexpected filename: #{req.file}"
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
private
|
|
80
80
|
|
|
81
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
|
82
81
|
sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
|
|
83
82
|
def updated_setup_requirement(req)
|
|
84
83
|
return req unless latest_resolvable_version
|
|
85
|
-
return req unless req.fetch(:requirement)
|
|
86
|
-
return req if new_version_satisfies?(req)
|
|
87
84
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if req_strings.any? { |r| requirement_class.new(r).exact? }
|
|
92
|
-
find_and_update_equality_match(req_strings)
|
|
93
|
-
elsif req_strings.any? { |r| r.start_with?("~=") }
|
|
94
|
-
tw_req = req_strings.find { |r| r.start_with?("~=") }
|
|
95
|
-
bump_version(tw_req, latest_resolvable_version.to_s)
|
|
96
|
-
elsif req_strings.any? { |r| r.start_with?("==") }
|
|
97
|
-
tw_req = req_strings.find { |r| r.start_with?("==") }
|
|
98
|
-
convert_to_range(tw_req, T.must(latest_resolvable_version))
|
|
99
|
-
else
|
|
100
|
-
update_requirements_range(req_strings)
|
|
101
|
-
end
|
|
85
|
+
requirement = req.requirement_string
|
|
86
|
+
return req unless requirement
|
|
87
|
+
return req if new_version_satisfies?(req)
|
|
102
88
|
|
|
89
|
+
new_requirement = updated_setup_requirement_string(requirement)
|
|
103
90
|
Dependabot::DependencyRequirement.create(req.merge(requirement: new_requirement))
|
|
104
91
|
rescue UnfixableRequirement
|
|
105
92
|
Dependabot::DependencyRequirement.create(req.merge(requirement: :unfixable))
|
|
106
93
|
end
|
|
107
|
-
|
|
94
|
+
|
|
95
|
+
sig { params(requirement: String).returns(String) }
|
|
96
|
+
def updated_setup_requirement_string(requirement)
|
|
97
|
+
req_strings = requirement.split(",").map(&:strip)
|
|
98
|
+
return find_and_update_equality_match(req_strings) if req_strings.any? { |r| requirement_class.new(r).exact? }
|
|
99
|
+
|
|
100
|
+
if req_strings.any? { |r| r.start_with?("~=") }
|
|
101
|
+
tw_req = req_strings.find { |r| r.start_with?("~=") }
|
|
102
|
+
return bump_version(T.must(tw_req), latest_resolvable_version.to_s)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
if req_strings.any? { |r| r.start_with?("==") }
|
|
106
|
+
tw_req = req_strings.find { |r| r.start_with?("==") }
|
|
107
|
+
return convert_to_range(T.must(tw_req), T.must(latest_resolvable_version))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
update_requirements_range(req_strings)
|
|
111
|
+
end
|
|
108
112
|
|
|
109
113
|
sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
|
|
110
114
|
def updated_pipfile_requirement(req)
|
|
@@ -116,7 +120,7 @@ module Dependabot
|
|
|
116
120
|
sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
|
|
117
121
|
def updated_pyproject_requirement(req)
|
|
118
122
|
return req unless latest_resolvable_version
|
|
119
|
-
return req unless req.
|
|
123
|
+
return req unless req.requirement_string
|
|
120
124
|
return req if skip_pyproject_update?(req)
|
|
121
125
|
|
|
122
126
|
pyproject_update_for_strategy(req)
|
|
@@ -132,11 +136,13 @@ module Dependabot
|
|
|
132
136
|
|
|
133
137
|
sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
|
|
134
138
|
def pyproject_update_for_strategy(req)
|
|
139
|
+
requirement = T.must(req.requirement_string)
|
|
140
|
+
|
|
135
141
|
# If the requirement uses || syntax then we always want to widen it
|
|
136
|
-
return widen_pyproject_requirement(req) if
|
|
142
|
+
return widen_pyproject_requirement(req) if requirement.match?(PYPROJECT_OR_SEPARATOR)
|
|
137
143
|
|
|
138
144
|
# If the requirement is a development dependency we always want to bump it
|
|
139
|
-
return update_pyproject_version(req) if req.
|
|
145
|
+
return update_pyproject_version(req) if req.groups&.include?("dev-dependencies")
|
|
140
146
|
|
|
141
147
|
case update_strategy
|
|
142
148
|
when RequirementsUpdateStrategy::WidenRanges then widen_pyproject_requirement(req)
|
|
@@ -155,7 +161,7 @@ module Dependabot
|
|
|
155
161
|
|
|
156
162
|
sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
|
|
157
163
|
def update_pyproject_version(req)
|
|
158
|
-
return req if req
|
|
164
|
+
return req if req.requirement == "*"
|
|
159
165
|
|
|
160
166
|
update_pyproject_version_core(req, bump_lower_bound: true)
|
|
161
167
|
end
|
|
@@ -167,14 +173,14 @@ module Dependabot
|
|
|
167
173
|
).returns(Dependabot::DependencyRequirement)
|
|
168
174
|
end
|
|
169
175
|
def update_pyproject_version_core(req, bump_lower_bound:)
|
|
170
|
-
requirement_strings = req
|
|
176
|
+
requirement_strings = T.must(req.requirement_string).split(",").map(&:strip)
|
|
171
177
|
|
|
172
178
|
new_requirement =
|
|
173
179
|
if requirement_strings.any? { |r| r.match?(/^=|^\d/) }
|
|
174
180
|
find_and_update_equality_match(requirement_strings)
|
|
175
181
|
elsif requirement_strings.any? { |r| r.start_with?("~", "^") }
|
|
176
182
|
v_req = requirement_strings.find { |r| r.start_with?("~", "^") }
|
|
177
|
-
bump_version(v_req, latest_resolvable_version.to_s)
|
|
183
|
+
bump_version(T.must(v_req), latest_resolvable_version.to_s)
|
|
178
184
|
elsif bump_lower_bound
|
|
179
185
|
bump_requirements_range(requirement_strings)
|
|
180
186
|
else
|
|
@@ -188,11 +194,12 @@ module Dependabot
|
|
|
188
194
|
def widen_pyproject_requirement(req)
|
|
189
195
|
return req if new_version_satisfies?(req)
|
|
190
196
|
|
|
197
|
+
requirement = T.must(req.requirement_string)
|
|
191
198
|
new_requirement =
|
|
192
|
-
if
|
|
193
|
-
add_new_requirement_option(
|
|
199
|
+
if requirement.match?(PYPROJECT_OR_SEPARATOR)
|
|
200
|
+
add_new_requirement_option(requirement)
|
|
194
201
|
else
|
|
195
|
-
widen_requirement_range(
|
|
202
|
+
widen_requirement_range(requirement)
|
|
196
203
|
end
|
|
197
204
|
|
|
198
205
|
Dependabot::DependencyRequirement.create(req.merge(requirement: new_requirement))
|
|
@@ -248,7 +255,7 @@ module Dependabot
|
|
|
248
255
|
sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
|
|
249
256
|
def updated_requirement(req)
|
|
250
257
|
return req unless latest_resolvable_version
|
|
251
|
-
return req unless req.
|
|
258
|
+
return req unless req.requirement_string
|
|
252
259
|
|
|
253
260
|
case update_strategy
|
|
254
261
|
when RequirementsUpdateStrategy::WidenRanges
|
|
@@ -279,17 +286,18 @@ module Dependabot
|
|
|
279
286
|
|
|
280
287
|
sig { params(req: Dependabot::DependencyRequirement).returns(T.any(String, Symbol)) }
|
|
281
288
|
def updated_requirement_string(req)
|
|
282
|
-
|
|
289
|
+
requirement = T.must(req.requirement_string)
|
|
290
|
+
requirement_strings = requirement.split(",").map(&:strip)
|
|
283
291
|
|
|
284
292
|
if requirement_strings.any? { |r| r.match?(/^[=\d]/) }
|
|
285
293
|
find_and_update_equality_match(requirement_strings)
|
|
286
294
|
elsif requirement_strings.any? { |r| r.start_with?("~=") }
|
|
287
295
|
tw_req = requirement_strings.find { |r| r.start_with?("~=") }
|
|
288
|
-
bump_version(tw_req, latest_resolvable_version.to_s)
|
|
296
|
+
bump_version(T.must(tw_req), latest_resolvable_version.to_s)
|
|
289
297
|
elsif bump_lower_bound?(requirement_strings)
|
|
290
298
|
bump_requirements_range(requirement_strings)
|
|
291
299
|
elsif new_version_satisfies?(req)
|
|
292
|
-
|
|
300
|
+
requirement
|
|
293
301
|
else
|
|
294
302
|
update_requirements_range(requirement_strings)
|
|
295
303
|
end
|
|
@@ -305,7 +313,7 @@ module Dependabot
|
|
|
305
313
|
def widen_requirement(req)
|
|
306
314
|
return req if new_version_satisfies?(req)
|
|
307
315
|
|
|
308
|
-
new_requirement = widen_requirement_range(req
|
|
316
|
+
new_requirement = widen_requirement_range(T.must(req.requirement_string))
|
|
309
317
|
|
|
310
318
|
Dependabot::DependencyRequirement.create(req.merge(requirement: new_requirement))
|
|
311
319
|
end
|
|
@@ -313,7 +321,7 @@ module Dependabot
|
|
|
313
321
|
sig { params(req: Dependabot::DependencyRequirement).returns(T::Boolean) }
|
|
314
322
|
def new_version_satisfies?(req)
|
|
315
323
|
requirement_class
|
|
316
|
-
.requirements_array(req.
|
|
324
|
+
.requirements_array(req.requirement_string)
|
|
317
325
|
.any? { |r| r.satisfied_by?(T.must(latest_resolvable_version)) }
|
|
318
326
|
end
|
|
319
327
|
|
|
@@ -253,10 +253,9 @@ module Dependabot
|
|
|
253
253
|
:requirements
|
|
254
254
|
end
|
|
255
255
|
|
|
256
|
-
sig { params(reqs: T::Array[
|
|
256
|
+
sig { params(reqs: T::Array[Dependabot::DependencyRequirement]).returns(T::Boolean) }
|
|
257
257
|
def exact_requirement?(reqs)
|
|
258
|
-
reqs = reqs.
|
|
259
|
-
reqs = reqs.compact
|
|
258
|
+
reqs = reqs.filter_map(&:requirement_string)
|
|
260
259
|
reqs = reqs.flat_map { |r| r.split(",").map(&:strip) }
|
|
261
260
|
reqs.any? { |r| Python::Requirement.new(r).exact? }
|
|
262
261
|
end
|
|
@@ -332,12 +331,13 @@ module Dependabot
|
|
|
332
331
|
return if reqs.none?
|
|
333
332
|
|
|
334
333
|
requirement = reqs.find do |r|
|
|
335
|
-
file = r
|
|
334
|
+
file = r.file
|
|
335
|
+
next false unless file
|
|
336
336
|
|
|
337
337
|
file == "Pipfile" || file == "pyproject.toml" || file.end_with?(".in") || file.end_with?(".txt")
|
|
338
338
|
end
|
|
339
339
|
|
|
340
|
-
requirement&.
|
|
340
|
+
requirement&.requirement_string
|
|
341
341
|
end
|
|
342
342
|
|
|
343
343
|
sig { returns(String) }
|
|
@@ -361,13 +361,13 @@ module Dependabot
|
|
|
361
361
|
def updated_version_req_lower_bound
|
|
362
362
|
return ">=#{dependency.version}" if dependency.version
|
|
363
363
|
|
|
364
|
-
version_for_requirement =
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
364
|
+
version_for_requirement = requirements
|
|
365
|
+
.filter_map(&:requirement_string)
|
|
366
|
+
.reject { |req_string| req_string.start_with?("<") }
|
|
367
|
+
.select { |req_string| req_string.match?(VERSION_REGEX) }
|
|
368
|
+
.map { |req_string| req_string.match(VERSION_REGEX).to_s }
|
|
369
|
+
.select { |version| Python::Version.correct?(version) }
|
|
370
|
+
.max_by { |version| Python::Version.new(version) }
|
|
371
371
|
|
|
372
372
|
">=#{version_for_requirement || 0}"
|
|
373
373
|
end
|
|
@@ -450,7 +450,7 @@ module Dependabot
|
|
|
450
450
|
|
|
451
451
|
sig { returns(T::Array[String]) }
|
|
452
452
|
def requirement_files
|
|
453
|
-
requirements.
|
|
453
|
+
requirements.filter_map(&:file)
|
|
454
454
|
end
|
|
455
455
|
|
|
456
456
|
sig { returns(T::Array[Dependabot::DependencyRequirement]) }
|
|
@@ -30,7 +30,7 @@ module Dependabot
|
|
|
30
30
|
sig { returns(T.nilable(T::Array[T.any(String, Integer)])) }
|
|
31
31
|
attr_reader :local
|
|
32
32
|
|
|
33
|
-
INFINITY =
|
|
33
|
+
INFINITY = 1000
|
|
34
34
|
NEGATIVE_INFINITY = T.let(-INFINITY, Integer)
|
|
35
35
|
|
|
36
36
|
# See https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-python
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.392.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.392.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.392.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: debug
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -323,7 +323,7 @@ licenses:
|
|
|
323
323
|
- MIT
|
|
324
324
|
metadata:
|
|
325
325
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
326
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
326
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.392.0
|
|
327
327
|
rdoc_options: []
|
|
328
328
|
require_paths:
|
|
329
329
|
- lib
|