dependabot-python 0.214.0 → 0.216.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/build +5 -5
- data/helpers/build_for_version +21 -0
- data/helpers/requirements.txt +4 -5
- data/lib/dependabot/python/file_parser/pyproject_files_parser.rb +25 -15
- data/lib/dependabot/python/file_updater/pip_compile_file_updater.rb +48 -53
- data/lib/dependabot/python/file_updater/pipfile_file_updater.rb +19 -59
- data/lib/dependabot/python/file_updater/pipfile_preparer.rb +17 -1
- data/lib/dependabot/python/file_updater/poetry_file_updater.rb +47 -38
- data/lib/dependabot/python/language_version_manager.rb +115 -0
- data/lib/dependabot/python/python_versions.rb +6 -6
- data/lib/dependabot/python/requirement_parser.rb +1 -1
- data/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb +46 -50
- data/lib/dependabot/python/update_checker/pip_version_resolver.rb +14 -40
- data/lib/dependabot/python/update_checker/pipenv_version_resolver.rb +23 -58
- data/lib/dependabot/python/update_checker/poetry_version_resolver.rb +55 -49
- data/lib/dependabot/python/update_checker/requirements_updater.rb +25 -6
- data/lib/dependabot/python/update_checker.rb +22 -49
- data/lib/dependabot/python/version.rb +2 -2
- metadata +37 -33
- data/lib/dependabot/python/helpers.rb +0 -37
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/logger"
|
4
|
+
require "dependabot/python/version"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Python
|
8
|
+
class LanguageVersionManager
|
9
|
+
def initialize(python_requirement_parser:)
|
10
|
+
@python_requirement_parser = python_requirement_parser
|
11
|
+
end
|
12
|
+
|
13
|
+
def install_required_python
|
14
|
+
# The leading space is important in the version check
|
15
|
+
return if SharedHelpers.run_shell_command("pyenv versions").include?(" #{python_major_minor}.")
|
16
|
+
|
17
|
+
if File.exist?("/usr/local/.pyenv/#{python_major_minor}.tar.gz")
|
18
|
+
SharedHelpers.run_shell_command(
|
19
|
+
"tar xzf /usr/local/.pyenv/#{python_major_minor}.tar.gz -C /usr/local/.pyenv/"
|
20
|
+
)
|
21
|
+
return if SharedHelpers.run_shell_command("pyenv versions").
|
22
|
+
include?(" #{python_major_minor}.")
|
23
|
+
end
|
24
|
+
|
25
|
+
Dependabot.logger.info("Installing required Python #{python_version}.")
|
26
|
+
start = Time.now
|
27
|
+
SharedHelpers.run_shell_command("pyenv install -s #{python_version}")
|
28
|
+
SharedHelpers.run_shell_command("pyenv exec pip install --upgrade pip")
|
29
|
+
SharedHelpers.run_shell_command("pyenv exec pip install -r" \
|
30
|
+
"#{NativeHelpers.python_requirements_path}")
|
31
|
+
time_taken = Time.now - start
|
32
|
+
Dependabot.logger.info("Installing Python #{python_version} took #{time_taken}s.")
|
33
|
+
end
|
34
|
+
|
35
|
+
def python_major_minor
|
36
|
+
@python ||= Python::Version.new(python_version)
|
37
|
+
"#{@python.segments[0]}.#{@python.segments[1]}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def python_version
|
41
|
+
@python_version ||= python_version_from_supported_versions
|
42
|
+
end
|
43
|
+
|
44
|
+
def python_requirement_string
|
45
|
+
if user_specified_python_version
|
46
|
+
if user_specified_python_version.start_with?(/\d/)
|
47
|
+
parts = user_specified_python_version.split(".")
|
48
|
+
parts.fill("*", (parts.length)..2).join(".")
|
49
|
+
else
|
50
|
+
user_specified_python_version
|
51
|
+
end
|
52
|
+
elsif python_version_matching_imputed_requirements
|
53
|
+
python_version_matching_imputed_requirements
|
54
|
+
else
|
55
|
+
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.first
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def python_version_from_supported_versions
|
60
|
+
requirement_string = python_requirement_string
|
61
|
+
|
62
|
+
# Ideally, the requirement is satisfied by a Python version we support
|
63
|
+
requirement =
|
64
|
+
Python::Requirement.requirements_array(requirement_string).first
|
65
|
+
version =
|
66
|
+
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
|
67
|
+
find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
68
|
+
return version if version
|
69
|
+
|
70
|
+
# If not, and we're dealing with a simple version string
|
71
|
+
# and changing the patch version would fix things, we do that
|
72
|
+
# as the patch version is unlikely to affect resolution
|
73
|
+
if requirement_string.start_with?(/\d/)
|
74
|
+
requirement =
|
75
|
+
Python::Requirement.new(requirement_string.gsub(/\.\d+$/, ".*"))
|
76
|
+
version =
|
77
|
+
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
|
78
|
+
find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
79
|
+
return version if version
|
80
|
+
end
|
81
|
+
|
82
|
+
# Otherwise we have to raise, giving details of the Python versions
|
83
|
+
# that Dependabot supports
|
84
|
+
msg = "Dependabot detected the following Python requirement " \
|
85
|
+
"for your project: '#{requirement_string}'.\n\nCurrently, the " \
|
86
|
+
"following Python versions are supported in Dependabot: " \
|
87
|
+
"#{PythonVersions::SUPPORTED_VERSIONS.join(', ')}."
|
88
|
+
raise DependencyFileNotResolvable, msg
|
89
|
+
end
|
90
|
+
|
91
|
+
def user_specified_python_version
|
92
|
+
@python_requirement_parser.user_specified_requirements.first
|
93
|
+
end
|
94
|
+
|
95
|
+
def python_version_matching_imputed_requirements
|
96
|
+
compiled_file_python_requirement_markers =
|
97
|
+
@python_requirement_parser.imputed_requirements.map do |r|
|
98
|
+
Dependabot::Python::Requirement.new(r)
|
99
|
+
end
|
100
|
+
python_version_matching(compiled_file_python_requirement_markers)
|
101
|
+
end
|
102
|
+
|
103
|
+
def python_version_matching(requirements)
|
104
|
+
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.find do |version_string|
|
105
|
+
version = Python::Version.new(version_string)
|
106
|
+
requirements.all? do |req|
|
107
|
+
next req.any? { |r| r.satisfied_by?(version) } if req.is_a?(Array)
|
108
|
+
|
109
|
+
req.satisfied_by?(version)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -4,7 +4,7 @@ module Dependabot
|
|
4
4
|
module Python
|
5
5
|
module PythonVersions
|
6
6
|
PRE_INSTALLED_PYTHON_VERSIONS = %w(
|
7
|
-
3.11.
|
7
|
+
3.11.3
|
8
8
|
).freeze
|
9
9
|
|
10
10
|
# Due to an OpenSSL issue we can only install the following versions in
|
@@ -13,11 +13,11 @@ module Dependabot
|
|
13
13
|
#
|
14
14
|
# WARNING: 3.9.3 is purposefully omitted as it was recalled: https://www.python.org/downloads/release/python-393/
|
15
15
|
SUPPORTED_VERSIONS = %w(
|
16
|
-
3.11.0
|
17
|
-
3.10.8 3.10.7 3.10.6 3.10.5 3.10.4 3.10.3 3.10.2 3.10.1 3.10.0
|
18
|
-
3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 3.9.10 3.9.9 3.9.8 3.9.7 3.9.6 3.9.5 3.9.4 3.9.2 3.9.1 3.9.0
|
19
|
-
3.8.15 3.8.14 3.8.13 3.8.12 3.8.11 3.8.10 3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 3.8.2 3.8.1 3.8.0
|
20
|
-
3.7.15 3.7.14 3.7.13 3.7.12 3.7.11 3.7.10 3.7.9 3.7.8 3.7.7 3.7.6 3.7.5 3.7.4 3.7.3 3.7.2 3.7.1 3.7.0
|
16
|
+
3.11.3 3.11.2 3.11.1 3.11.0
|
17
|
+
3.10.11 3.10.10 3.10.9 3.10.8 3.10.7 3.10.6 3.10.5 3.10.4 3.10.3 3.10.2 3.10.1 3.10.0
|
18
|
+
3.9.16 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 3.9.10 3.9.9 3.9.8 3.9.7 3.9.6 3.9.5 3.9.4 3.9.2 3.9.1 3.9.0
|
19
|
+
3.8.16 3.8.15 3.8.14 3.8.13 3.8.12 3.8.11 3.8.10 3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 3.8.2 3.8.1 3.8.0
|
20
|
+
3.7.16 3.7.15 3.7.14 3.7.13 3.7.12 3.7.11 3.7.10 3.7.9 3.7.8 3.7.7 3.7.6 3.7.5 3.7.4 3.7.3 3.7.2 3.7.1 3.7.0
|
21
21
|
3.6.15 3.6.14 3.6.13 3.6.12 3.6.11 3.6.10 3.6.9 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.6.0
|
22
22
|
3.5.10 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3
|
23
23
|
).freeze
|
@@ -9,7 +9,7 @@ module Dependabot
|
|
9
9
|
VERSION = /([1-9][0-9]*!)?[0-9]+[a-zA-Z0-9\-_.*]*(\+[0-9a-zA-Z]+(\.[0-9a-zA-Z]+)*)?/
|
10
10
|
|
11
11
|
REQUIREMENT = /(?<comparison>#{COMPARISON})\s*\\?\s*(?<version>#{VERSION})/
|
12
|
-
HASH = /--hash=(?<algorithm>.*?):(?<hash>.*?)(?=\s
|
12
|
+
HASH = /--hash=(?<algorithm>.*?):(?<hash>.*?)(?=\s|\\|$)/
|
13
13
|
REQUIREMENTS = /#{REQUIREMENT}(\s*,\s*\\?\s*#{REQUIREMENT})*/
|
14
14
|
HASHES = /#{HASH}(\s*\\?\s*#{HASH})*/
|
15
15
|
MARKER_OP = /\s*(#{COMPARISON}|(\s*in)|(\s*not\s*in))/
|
@@ -11,7 +11,7 @@ require "dependabot/python/file_updater/requirement_replacer"
|
|
11
11
|
require "dependabot/python/file_updater/setup_file_sanitizer"
|
12
12
|
require "dependabot/python/version"
|
13
13
|
require "dependabot/shared_helpers"
|
14
|
-
require "dependabot/python/
|
14
|
+
require "dependabot/python/language_version_manager"
|
15
15
|
require "dependabot/python/native_helpers"
|
16
16
|
require "dependabot/python/python_versions"
|
17
17
|
require "dependabot/python/name_normaliser"
|
@@ -71,13 +71,17 @@ module Dependabot
|
|
71
71
|
SharedHelpers.in_a_temporary_directory do
|
72
72
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
73
73
|
write_temporary_dependency_files(updated_req: requirement)
|
74
|
-
|
74
|
+
language_version_manager.install_required_python
|
75
75
|
|
76
76
|
filenames_to_compile.each do |filename|
|
77
77
|
# Shell out to pip-compile.
|
78
78
|
# This is slow, as pip-compile needs to do installs.
|
79
|
+
options = pip_compile_options(filename)
|
80
|
+
options_fingerprint = pip_compile_options_fingerprint(options)
|
81
|
+
|
79
82
|
run_pip_compile_command(
|
80
|
-
"pyenv exec pip-compile -v #{
|
83
|
+
"pyenv exec pip-compile -v #{options} -P #{dependency.name} #{filename}",
|
84
|
+
fingerprint: "pyenv exec pip-compile -v #{options_fingerprint} -P <dependency_name> <filename>"
|
81
85
|
)
|
82
86
|
|
83
87
|
next if dependency.top_level?
|
@@ -91,7 +95,8 @@ module Dependabot
|
|
91
95
|
# update_not_possible.
|
92
96
|
write_original_manifest_files
|
93
97
|
run_pip_compile_command(
|
94
|
-
"pyenv exec pip-compile #{
|
98
|
+
"pyenv exec pip-compile #{options} #{filename}",
|
99
|
+
fingerprint: "pyenv exec pip-compile #{options_fingerprint} <filename>"
|
95
100
|
)
|
96
101
|
end
|
97
102
|
|
@@ -168,6 +173,10 @@ module Dependabot
|
|
168
173
|
raise GitDependenciesNotReachable, url
|
169
174
|
end
|
170
175
|
|
176
|
+
raise Dependabot::OutOfDisk if error.message.end_with?("[Errno 28] No space left on device")
|
177
|
+
|
178
|
+
raise Dependabot::OutOfMemory if error.message.end_with?("MemoryError")
|
179
|
+
|
171
180
|
raise
|
172
181
|
end
|
173
182
|
# rubocop:enable Metrics/AbcSize
|
@@ -183,8 +192,12 @@ module Dependabot
|
|
183
192
|
write_temporary_dependency_files(update_requirement: false)
|
184
193
|
|
185
194
|
filenames_to_compile.each do |filename|
|
195
|
+
options = pip_compile_options(filename)
|
196
|
+
options_fingerprint = pip_compile_options_fingerprint(options)
|
197
|
+
|
186
198
|
run_pip_compile_command(
|
187
|
-
"pyenv exec pip-compile #{
|
199
|
+
"pyenv exec pip-compile #{options} #{filename}",
|
200
|
+
fingerprint: "pyenv exec pip-compile #{options_fingerprint} <filename>"
|
188
201
|
)
|
189
202
|
end
|
190
203
|
|
@@ -204,7 +217,7 @@ module Dependabot
|
|
204
217
|
end
|
205
218
|
end
|
206
219
|
|
207
|
-
def run_command(command, env: python_env)
|
220
|
+
def run_command(command, env: python_env, fingerprint:)
|
208
221
|
start = Time.now
|
209
222
|
command = SharedHelpers.escape_command(command)
|
210
223
|
stdout, process = Open3.capture2e(env, command)
|
@@ -216,6 +229,7 @@ module Dependabot
|
|
216
229
|
message: stdout,
|
217
230
|
error_context: {
|
218
231
|
command: command,
|
232
|
+
fingerprint: fingerprint,
|
219
233
|
time_taken: time_taken,
|
220
234
|
process_exit_value: process.to_s
|
221
235
|
}
|
@@ -223,7 +237,17 @@ module Dependabot
|
|
223
237
|
end
|
224
238
|
|
225
239
|
def new_resolver_supported?
|
226
|
-
python_version >= Python::Version.new("3.7")
|
240
|
+
language_version_manager.python_version >= Python::Version.new("3.7")
|
241
|
+
end
|
242
|
+
|
243
|
+
def pip_compile_options_fingerprint(options)
|
244
|
+
options.sub(
|
245
|
+
/--output-file=\S+/, "--output-file=<output_file>"
|
246
|
+
).sub(
|
247
|
+
/--index-url=\S+/, "--index-url=<index_url>"
|
248
|
+
).sub(
|
249
|
+
/--extra-index-url=\S+/, "--extra-index-url=<extra_index_url>"
|
250
|
+
)
|
227
251
|
end
|
228
252
|
|
229
253
|
def pip_compile_options(filename)
|
@@ -253,9 +277,13 @@ module Dependabot
|
|
253
277
|
end
|
254
278
|
end
|
255
279
|
|
256
|
-
def run_pip_compile_command(command)
|
257
|
-
run_command(
|
258
|
-
|
280
|
+
def run_pip_compile_command(command, fingerprint:)
|
281
|
+
run_command(
|
282
|
+
"pyenv local #{language_version_manager.python_major_minor}",
|
283
|
+
fingerprint: "pyenv local <python_major_minor>"
|
284
|
+
)
|
285
|
+
|
286
|
+
run_command(command, fingerprint: fingerprint)
|
259
287
|
end
|
260
288
|
|
261
289
|
def python_env
|
@@ -298,7 +326,7 @@ module Dependabot
|
|
298
326
|
end
|
299
327
|
|
300
328
|
# Overwrite the .python-version with updated content
|
301
|
-
File.write(".python-version",
|
329
|
+
File.write(".python-version", language_version_manager.python_major_minor)
|
302
330
|
|
303
331
|
setup_files.each do |file|
|
304
332
|
path = file.name
|
@@ -410,9 +438,9 @@ module Dependabot
|
|
410
438
|
while (remaining_filenames = filenames - ordered_filenames).any?
|
411
439
|
ordered_filenames +=
|
412
440
|
remaining_filenames.
|
413
|
-
|
441
|
+
reject do |fn|
|
414
442
|
unupdated_reqs = requirement_map[fn] - ordered_filenames
|
415
|
-
(
|
443
|
+
unupdated_reqs.intersect?(filenames)
|
416
444
|
end
|
417
445
|
end
|
418
446
|
|
@@ -455,41 +483,6 @@ module Dependabot
|
|
455
483
|
).parse.find { |d| d.name == dependency.name }&.version
|
456
484
|
end
|
457
485
|
|
458
|
-
def python_version
|
459
|
-
@python_version ||=
|
460
|
-
user_specified_python_version ||
|
461
|
-
python_version_matching_imputed_requirements ||
|
462
|
-
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.first
|
463
|
-
end
|
464
|
-
|
465
|
-
def user_specified_python_version
|
466
|
-
return unless python_requirement_parser.user_specified_requirements.any?
|
467
|
-
|
468
|
-
user_specified_requirements =
|
469
|
-
python_requirement_parser.user_specified_requirements.
|
470
|
-
map { |r| Python::Requirement.requirements_array(r) }
|
471
|
-
python_version_matching(user_specified_requirements)
|
472
|
-
end
|
473
|
-
|
474
|
-
def python_version_matching_imputed_requirements
|
475
|
-
compiled_file_python_requirement_markers =
|
476
|
-
python_requirement_parser.imputed_requirements.map do |r|
|
477
|
-
Dependabot::Python::Requirement.new(r)
|
478
|
-
end
|
479
|
-
python_version_matching(compiled_file_python_requirement_markers)
|
480
|
-
end
|
481
|
-
|
482
|
-
def python_version_matching(requirements)
|
483
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.find do |version_string|
|
484
|
-
version = Python::Version.new(version_string)
|
485
|
-
requirements.all? do |req|
|
486
|
-
next req.any? { |r| r.satisfied_by?(version) } if req.is_a?(Array)
|
487
|
-
|
488
|
-
req.satisfied_by?(version)
|
489
|
-
end
|
490
|
-
end
|
491
|
-
end
|
492
|
-
|
493
486
|
def python_requirement_parser
|
494
487
|
@python_requirement_parser ||=
|
495
488
|
FileParser::PythonRequirementParser.new(
|
@@ -497,8 +490,11 @@ module Dependabot
|
|
497
490
|
)
|
498
491
|
end
|
499
492
|
|
500
|
-
def
|
501
|
-
|
493
|
+
def language_version_manager
|
494
|
+
@language_version_manager ||=
|
495
|
+
LanguageVersionManager.new(
|
496
|
+
python_requirement_parser: python_requirement_parser
|
497
|
+
)
|
502
498
|
end
|
503
499
|
|
504
500
|
def setup_files
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "dependabot/python/language_version_manager"
|
3
4
|
require "dependabot/python/update_checker"
|
4
5
|
require "dependabot/python/update_checker/latest_version_finder"
|
5
6
|
require "dependabot/python/file_parser/python_requirement_parser"
|
@@ -20,17 +21,17 @@ module Dependabot
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def latest_resolvable_version
|
23
|
-
latest_version_finder.latest_version(python_version: python_version)
|
24
|
+
latest_version_finder.latest_version(python_version: language_version_manager.python_version)
|
24
25
|
end
|
25
26
|
|
26
27
|
def latest_resolvable_version_with_no_unlock
|
27
28
|
latest_version_finder.
|
28
|
-
latest_version_with_no_unlock(python_version: python_version)
|
29
|
+
latest_version_with_no_unlock(python_version: language_version_manager.python_version)
|
29
30
|
end
|
30
31
|
|
31
32
|
def lowest_resolvable_security_fix_version
|
32
33
|
latest_version_finder.
|
33
|
-
lowest_security_fix_version(python_version: python_version)
|
34
|
+
lowest_security_fix_version(python_version: language_version_manager.python_version)
|
34
35
|
end
|
35
36
|
|
36
37
|
private
|
@@ -49,45 +50,18 @@ module Dependabot
|
|
49
50
|
)
|
50
51
|
end
|
51
52
|
|
52
|
-
def python_version
|
53
|
-
@python_version ||=
|
54
|
-
user_specified_python_version ||
|
55
|
-
python_version_matching_imputed_requirements ||
|
56
|
-
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.first
|
57
|
-
end
|
58
|
-
|
59
|
-
def user_specified_python_version
|
60
|
-
return unless python_requirement_parser.user_specified_requirements.any?
|
61
|
-
|
62
|
-
user_specified_requirements =
|
63
|
-
python_requirement_parser.user_specified_requirements.
|
64
|
-
map { |r| Python::Requirement.requirements_array(r) }
|
65
|
-
python_version_matching(user_specified_requirements)
|
66
|
-
end
|
67
|
-
|
68
|
-
def python_version_matching_imputed_requirements
|
69
|
-
compiled_file_python_requirement_markers =
|
70
|
-
python_requirement_parser.imputed_requirements.map do |r|
|
71
|
-
Dependabot::Python::Requirement.new(r)
|
72
|
-
end
|
73
|
-
python_version_matching(compiled_file_python_requirement_markers)
|
74
|
-
end
|
75
|
-
|
76
|
-
def python_version_matching(requirements)
|
77
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.find do |version_string|
|
78
|
-
version = Python::Version.new(version_string)
|
79
|
-
requirements.all? do |req|
|
80
|
-
next req.any? { |r| r.satisfied_by?(version) } if req.is_a?(Array)
|
81
|
-
|
82
|
-
req.satisfied_by?(version)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
53
|
def python_requirement_parser
|
88
54
|
@python_requirement_parser ||=
|
89
|
-
FileParser::PythonRequirementParser.
|
90
|
-
|
55
|
+
FileParser::PythonRequirementParser.new(
|
56
|
+
dependency_files: dependency_files
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
def language_version_manager
|
61
|
+
@language_version_manager ||=
|
62
|
+
LanguageVersionManager.new(
|
63
|
+
python_requirement_parser: python_requirement_parser
|
64
|
+
)
|
91
65
|
end
|
92
66
|
end
|
93
67
|
end
|
@@ -175,7 +175,7 @@ module Dependabot
|
|
175
175
|
end
|
176
176
|
|
177
177
|
if error.message.include?("UnsupportedPythonVersion") &&
|
178
|
-
|
178
|
+
language_version_manager.user_specified_python_version
|
179
179
|
check_original_requirements_resolvable
|
180
180
|
|
181
181
|
# The latest version of the dependency we're updating to needs a
|
@@ -231,7 +231,7 @@ module Dependabot
|
|
231
231
|
end
|
232
232
|
|
233
233
|
if error.message.include?("UnsupportedPythonVersion") &&
|
234
|
-
|
234
|
+
language_version_manager.user_specified_python_version
|
235
235
|
msg = clean_error_message(error.message).
|
236
236
|
lines.take_while { |l| !l.start_with?("File") }.join.strip
|
237
237
|
raise if msg.empty?
|
@@ -239,8 +239,10 @@ module Dependabot
|
|
239
239
|
raise DependencyFileNotResolvable, msg
|
240
240
|
end
|
241
241
|
|
242
|
-
# NOTE: Pipenv masks the
|
242
|
+
# NOTE: Pipenv masks the actual error, see this issue for updates:
|
243
243
|
# https://github.com/pypa/pipenv/issues/2791
|
244
|
+
# TODO: This may no longer be reproducible on latest pipenv, see linked issue,
|
245
|
+
# so investigate when we next bump to newer pipenv...
|
244
246
|
handle_pipenv_installation_error(error.message) if error.message.match?(PIPENV_INSTALLATION_ERROR_REGEX)
|
245
247
|
|
246
248
|
# Raise an unhandled error, as this could be a problem with
|
@@ -290,7 +292,7 @@ module Dependabot
|
|
290
292
|
end
|
291
293
|
|
292
294
|
# Overwrite the .python-version with updated content
|
293
|
-
File.write(".python-version",
|
295
|
+
File.write(".python-version", language_version_manager.python_major_minor)
|
294
296
|
|
295
297
|
setup_files.each do |file|
|
296
298
|
path = file.name
|
@@ -320,7 +322,7 @@ module Dependabot
|
|
320
322
|
nil
|
321
323
|
end
|
322
324
|
|
323
|
-
|
325
|
+
language_version_manager.install_required_python
|
324
326
|
end
|
325
327
|
|
326
328
|
def sanitized_setup_file_content(file)
|
@@ -354,7 +356,7 @@ module Dependabot
|
|
354
356
|
def update_python_requirement(pipfile_content)
|
355
357
|
Python::FileUpdater::PipfilePreparer.
|
356
358
|
new(pipfile_content: pipfile_content).
|
357
|
-
update_python_requirement(
|
359
|
+
update_python_requirement(language_version_manager.python_major_minor)
|
358
360
|
end
|
359
361
|
|
360
362
|
# rubocop:disable Metrics/PerceivedComplexity
|
@@ -398,57 +400,6 @@ module Dependabot
|
|
398
400
|
replace_sources(credentials)
|
399
401
|
end
|
400
402
|
|
401
|
-
def python_version
|
402
|
-
@python_version ||= python_version_from_supported_versions
|
403
|
-
end
|
404
|
-
|
405
|
-
def python_version_from_supported_versions
|
406
|
-
requirement_string =
|
407
|
-
if @using_python_two then "2.7.*"
|
408
|
-
elsif user_specified_python_requirement
|
409
|
-
parts = user_specified_python_requirement.split(".")
|
410
|
-
parts.fill("*", (parts.length)..2).join(".")
|
411
|
-
else
|
412
|
-
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.first
|
413
|
-
end
|
414
|
-
|
415
|
-
# Ideally, the requirement is satisfied by a Python version we support
|
416
|
-
requirement =
|
417
|
-
Python::Requirement.requirements_array(requirement_string).first
|
418
|
-
version =
|
419
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
|
420
|
-
find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
421
|
-
return version if version
|
422
|
-
|
423
|
-
# If not, and changing the patch version would fix things, we do that
|
424
|
-
# as the patch version is unlikely to affect resolution
|
425
|
-
requirement =
|
426
|
-
Python::Requirement.new(requirement_string.gsub(/\.\d+$/, ".*"))
|
427
|
-
version =
|
428
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
|
429
|
-
find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
430
|
-
return version if version
|
431
|
-
|
432
|
-
# Otherwise we have to raise, giving details of the Python versions
|
433
|
-
# that Dependabot supports
|
434
|
-
msg = "Dependabot detected the following Python requirement " \
|
435
|
-
"for your project: '#{requirement_string}'.\n\nCurrently, the " \
|
436
|
-
"following Python versions are supported in Dependabot: " \
|
437
|
-
"#{PythonVersions::SUPPORTED_VERSIONS.join(', ')}."
|
438
|
-
raise DependencyFileNotResolvable, msg
|
439
|
-
end
|
440
|
-
|
441
|
-
def user_specified_python_requirement
|
442
|
-
python_requirement_parser.user_specified_requirements.first
|
443
|
-
end
|
444
|
-
|
445
|
-
def python_requirement_parser
|
446
|
-
@python_requirement_parser ||=
|
447
|
-
FileParser::PythonRequirementParser.new(
|
448
|
-
dependency_files: dependency_files
|
449
|
-
)
|
450
|
-
end
|
451
|
-
|
452
403
|
def run_command(command, env: {})
|
453
404
|
start = Time.now
|
454
405
|
command = SharedHelpers.escape_command(command)
|
@@ -468,7 +419,7 @@ module Dependabot
|
|
468
419
|
end
|
469
420
|
|
470
421
|
def run_pipenv_command(command, env: pipenv_env_variables)
|
471
|
-
run_command("pyenv local #{
|
422
|
+
run_command("pyenv local #{language_version_manager.python_major_minor}")
|
472
423
|
run_command(command, env: env)
|
473
424
|
end
|
474
425
|
|
@@ -486,6 +437,20 @@ module Dependabot
|
|
486
437
|
NameNormaliser.normalise(name)
|
487
438
|
end
|
488
439
|
|
440
|
+
def python_requirement_parser
|
441
|
+
@python_requirement_parser ||=
|
442
|
+
FileParser::PythonRequirementParser.new(
|
443
|
+
dependency_files: dependency_files
|
444
|
+
)
|
445
|
+
end
|
446
|
+
|
447
|
+
def language_version_manager
|
448
|
+
@language_version_manager ||=
|
449
|
+
LanguageVersionManager.new(
|
450
|
+
python_requirement_parser: python_requirement_parser
|
451
|
+
)
|
452
|
+
end
|
453
|
+
|
489
454
|
def pipfile
|
490
455
|
dependency_files.find { |f| f.name == "Pipfile" }
|
491
456
|
end
|