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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62df822653f41408461f72892b9886776c124a195af5569c6af9e3bdf044e93d
|
4
|
+
data.tar.gz: 8cba64f792d1be98900fe5136d549230d5156d487d07150e0356a147402c5ca3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8c60892487b523ca5879fd08f188dfabcd4d9c4ca17b3317accb3558a22a7731f53129616494230cf62138503e7aece5e9b304fe53bbd525e484197fe74f110
|
7
|
+
data.tar.gz: d7cfe8feb5f919ec01521377366c3716954f898361cc666a1df6384afc3389b9e6db9a92dd4c91cd25fa2e043cbd1aa5a71745d7c030a9627f7c434fcfee5731
|
data/helpers/build
CHANGED
@@ -18,8 +18,8 @@ cp -r \
|
|
18
18
|
"$install_dir"
|
19
19
|
|
20
20
|
cd "$install_dir"
|
21
|
-
PYENV_VERSION=3.11.
|
22
|
-
PYENV_VERSION=3.10.
|
23
|
-
PYENV_VERSION=3.9.
|
24
|
-
PYENV_VERSION=3.8.
|
25
|
-
PYENV_VERSION=3.7.
|
21
|
+
PYENV_VERSION=3.11.3 pyenv exec pip --disable-pip-version-check install --use-pep517 -r "requirements.txt"
|
22
|
+
PYENV_VERSION=3.10.11 pyenv exec pip --disable-pip-version-check install --use-pep517 -r "requirements.txt"
|
23
|
+
PYENV_VERSION=3.9.16 pyenv exec pip --disable-pip-version-check install --use-pep517 -r "requirements.txt"
|
24
|
+
PYENV_VERSION=3.8.16 pyenv exec pip --disable-pip-version-check install --use-pep517 -r "requirements.txt"
|
25
|
+
PYENV_VERSION=3.7.16 pyenv exec pip --disable-pip-version-check install --use-pep517 -r "requirements.txt"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
if [ -z "$DEPENDABOT_NATIVE_HELPERS_PATH" ]; then
|
6
|
+
echo "Unable to build, DEPENDABOT_NATIVE_HELPERS_PATH is not set"
|
7
|
+
exit 1
|
8
|
+
fi
|
9
|
+
|
10
|
+
install_dir="$DEPENDABOT_NATIVE_HELPERS_PATH/python"
|
11
|
+
mkdir -p "$install_dir"
|
12
|
+
|
13
|
+
helpers_dir="$(dirname "${BASH_SOURCE[0]}")"
|
14
|
+
cp -r \
|
15
|
+
"$helpers_dir/lib" \
|
16
|
+
"$helpers_dir/run.py" \
|
17
|
+
"$helpers_dir/requirements.txt" \
|
18
|
+
"$install_dir"
|
19
|
+
|
20
|
+
cd "$install_dir"
|
21
|
+
PYENV_VERSION=$1 pyenv exec pip --disable-pip-version-check install --use-pep517 -r "requirements.txt"
|
data/helpers/requirements.txt
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
pip>=21.3.1,<
|
2
|
-
pip-tools>=6.4.0
|
3
|
-
flake8==5.0.4
|
1
|
+
pip>=21.3.1,<23.1.0 # Range maintains py36 support TODO: Review python 3.6 support in April 2023 (eol ubuntu 18.04)
|
2
|
+
pip-tools>=6.4.0,<=6.12.3 # Range maintains py36 support TODO: Review python 3.6 support in April 2023 (eol ubuntu 18.04)
|
4
3
|
hashin==0.17.0
|
5
4
|
pipenv==2022.4.8
|
6
5
|
pipfile==0.0.2
|
7
|
-
poetry>=1.1.15,<1.
|
6
|
+
poetry>=1.1.15,<1.4.0
|
8
7
|
wheel==0.37.1
|
9
8
|
|
10
9
|
# Some dependencies will only install if Cython is present
|
11
|
-
Cython==0.29.
|
10
|
+
Cython==0.29.34
|
@@ -48,22 +48,13 @@ module Dependabot
|
|
48
48
|
|
49
49
|
POETRY_DEPENDENCY_TYPES.each do |type|
|
50
50
|
deps_hash = parsed_pyproject.dig("tool", "poetry", type) || {}
|
51
|
-
|
52
|
-
deps_hash.each do |name, req|
|
53
|
-
next if normalise(name) == "python"
|
54
|
-
|
55
|
-
requirements = parse_requirements_from(req, type)
|
56
|
-
next if requirements.empty?
|
57
|
-
|
58
|
-
dependencies << Dependency.new(
|
59
|
-
name: normalise(name),
|
60
|
-
version: version_from_lockfile(name),
|
61
|
-
requirements: requirements,
|
62
|
-
package_manager: "pip"
|
63
|
-
)
|
64
|
-
end
|
51
|
+
dependencies += parse_poetry_dependencies(type, deps_hash)
|
65
52
|
end
|
66
53
|
|
54
|
+
groups = parsed_pyproject.dig("tool", "poetry", "group") || {}
|
55
|
+
groups.each do |group, group_spec|
|
56
|
+
dependencies += parse_poetry_dependencies(group, group_spec["dependencies"])
|
57
|
+
end
|
67
58
|
dependencies
|
68
59
|
end
|
69
60
|
|
@@ -101,6 +92,25 @@ module Dependabot
|
|
101
92
|
dependencies
|
102
93
|
end
|
103
94
|
|
95
|
+
def parse_poetry_dependencies(type, deps_hash)
|
96
|
+
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
97
|
+
|
98
|
+
deps_hash.each do |name, req|
|
99
|
+
next if normalise(name) == "python"
|
100
|
+
|
101
|
+
requirements = parse_requirements_from(req, type)
|
102
|
+
next if requirements.empty?
|
103
|
+
|
104
|
+
dependencies << Dependency.new(
|
105
|
+
name: normalise(name),
|
106
|
+
version: version_from_lockfile(name),
|
107
|
+
requirements: requirements,
|
108
|
+
package_manager: "pip"
|
109
|
+
)
|
110
|
+
end
|
111
|
+
dependencies
|
112
|
+
end
|
113
|
+
|
104
114
|
def normalised_name(name, extras)
|
105
115
|
NameNormaliser.normalise_including_extras(name, extras)
|
106
116
|
end
|
@@ -108,7 +118,7 @@ module Dependabot
|
|
108
118
|
# @param req can be an Array, Hash or String that represents the constraints for a dependency
|
109
119
|
def parse_requirements_from(req, type)
|
110
120
|
[req].flatten.compact.filter_map do |requirement|
|
111
|
-
next if requirement.is_a?(Hash) && (
|
121
|
+
next if requirement.is_a?(Hash) && UNSUPPORTED_DEPENDENCY_TYPES.intersect?(requirement.keys)
|
112
122
|
|
113
123
|
check_requirements(requirement)
|
114
124
|
|
@@ -7,7 +7,7 @@ require "dependabot/python/file_fetcher"
|
|
7
7
|
require "dependabot/python/file_parser/python_requirement_parser"
|
8
8
|
require "dependabot/python/file_updater"
|
9
9
|
require "dependabot/shared_helpers"
|
10
|
-
require "dependabot/python/
|
10
|
+
require "dependabot/python/language_version_manager"
|
11
11
|
require "dependabot/python/native_helpers"
|
12
12
|
require "dependabot/python/python_versions"
|
13
13
|
require "dependabot/python/name_normaliser"
|
@@ -26,6 +26,7 @@ module Dependabot
|
|
26
26
|
INCOMPATIBLE_VERSIONS_REGEX = /There are incompatible versions in the resolved dependencies:.*\z/m
|
27
27
|
WARNINGS = /\s*# WARNING:.*\Z/m
|
28
28
|
UNSAFE_NOTE = /\s*# The following packages are considered to be unsafe.*\Z/m
|
29
|
+
RESOLVER_REGEX = /(?<=--resolver=)(\w+)/
|
29
30
|
|
30
31
|
attr_reader :dependencies, :dependency_files, :credentials
|
31
32
|
|
@@ -66,20 +67,30 @@ module Dependabot
|
|
66
67
|
def compile_new_requirement_files
|
67
68
|
SharedHelpers.in_a_temporary_directory do
|
68
69
|
write_updated_dependency_files
|
69
|
-
|
70
|
+
language_version_manager.install_required_python
|
70
71
|
|
71
72
|
filenames_to_compile.each do |filename|
|
72
73
|
# Shell out to pip-compile, generate a new set of requirements.
|
73
74
|
# This is slow, as pip-compile needs to do installs.
|
75
|
+
options = pip_compile_options(filename)
|
76
|
+
options_fingerprint = pip_compile_options_fingerprint(options)
|
77
|
+
|
74
78
|
name_part = "pyenv exec pip-compile " \
|
75
|
-
"#{
|
79
|
+
"#{options} -P " \
|
76
80
|
"#{dependency.name}"
|
81
|
+
fingerprint_name_part = "pyenv exec pip-compile " \
|
82
|
+
"#{options_fingerprint} -P " \
|
83
|
+
"<dependency_name>"
|
84
|
+
|
77
85
|
version_part = "#{dependency.version} #{filename}"
|
86
|
+
fingerprint_version_part = "<dependency_version> <filename>"
|
87
|
+
|
78
88
|
# Don't escape pyenv `dep-name==version` syntax
|
79
89
|
run_pip_compile_command(
|
80
90
|
"#{SharedHelpers.escape_command(name_part)}==" \
|
81
91
|
"#{SharedHelpers.escape_command(version_part)}",
|
82
|
-
allow_unsafe_shell_command: true
|
92
|
+
allow_unsafe_shell_command: true,
|
93
|
+
fingerprint: "#{fingerprint_name_part}==#{fingerprint_version_part}"
|
83
94
|
)
|
84
95
|
end
|
85
96
|
|
@@ -137,7 +148,7 @@ module Dependabot
|
|
137
148
|
).updated_dependency_files
|
138
149
|
end
|
139
150
|
|
140
|
-
def run_command(cmd, env: python_env, allow_unsafe_shell_command: false)
|
151
|
+
def run_command(cmd, env: python_env, allow_unsafe_shell_command: false, fingerprint:)
|
141
152
|
start = Time.now
|
142
153
|
command = if allow_unsafe_shell_command
|
143
154
|
cmd
|
@@ -149,10 +160,6 @@ module Dependabot
|
|
149
160
|
|
150
161
|
return stdout if process.success?
|
151
162
|
|
152
|
-
handle_pip_errors(stdout, command, time_taken, process.to_s)
|
153
|
-
end
|
154
|
-
|
155
|
-
def handle_pip_errors(stdout, command, time_taken, exit_value)
|
156
163
|
if stdout.match?(INCOMPATIBLE_VERSIONS_REGEX)
|
157
164
|
raise DependencyFileNotResolvable, stdout.match(INCOMPATIBLE_VERSIONS_REGEX)
|
158
165
|
end
|
@@ -161,17 +168,23 @@ module Dependabot
|
|
161
168
|
message: stdout,
|
162
169
|
error_context: {
|
163
170
|
command: command,
|
171
|
+
fingerprint: fingerprint,
|
164
172
|
time_taken: time_taken,
|
165
|
-
process_exit_value:
|
173
|
+
process_exit_value: process.to_s
|
166
174
|
}
|
167
175
|
)
|
168
176
|
end
|
169
177
|
|
170
|
-
def run_pip_compile_command(command, allow_unsafe_shell_command: false)
|
171
|
-
run_command(
|
178
|
+
def run_pip_compile_command(command, allow_unsafe_shell_command: false, fingerprint:)
|
179
|
+
run_command(
|
180
|
+
"pyenv local #{language_version_manager.python_major_minor}",
|
181
|
+
fingerprint: "pyenv local <python_major_minor>"
|
182
|
+
)
|
183
|
+
|
172
184
|
run_command(
|
173
185
|
command,
|
174
|
-
allow_unsafe_shell_command: allow_unsafe_shell_command
|
186
|
+
allow_unsafe_shell_command: allow_unsafe_shell_command,
|
187
|
+
fingerprint: fingerprint
|
175
188
|
)
|
176
189
|
end
|
177
190
|
|
@@ -198,7 +211,7 @@ module Dependabot
|
|
198
211
|
end
|
199
212
|
|
200
213
|
# Overwrite the .python-version with updated content
|
201
|
-
File.write(".python-version",
|
214
|
+
File.write(".python-version", language_version_manager.python_major_minor)
|
202
215
|
|
203
216
|
setup_files.each do |file|
|
204
217
|
path = file.name
|
@@ -391,6 +404,16 @@ module Dependabot
|
|
391
404
|
current_separator || default_separator
|
392
405
|
end
|
393
406
|
|
407
|
+
def pip_compile_options_fingerprint(options)
|
408
|
+
options.sub(
|
409
|
+
/--output-file=\S+/, "--output-file=<output_file>"
|
410
|
+
).sub(
|
411
|
+
/--index-url=\S+/, "--index-url=<index_url>"
|
412
|
+
).sub(
|
413
|
+
/--extra-index-url=\S+/, "--extra-index-url=<extra_index_url>"
|
414
|
+
)
|
415
|
+
end
|
416
|
+
|
394
417
|
def pip_compile_options(filename)
|
395
418
|
options = ["--build-isolation"]
|
396
419
|
options += pip_compile_index_options
|
@@ -419,6 +442,10 @@ module Dependabot
|
|
419
442
|
|
420
443
|
options << "--strip-extras" if requirements_file.content.include?("--strip-extras")
|
421
444
|
|
445
|
+
if (resolver = RESOLVER_REGEX.match(requirements_file.content))
|
446
|
+
options << "--resolver=#{resolver}"
|
447
|
+
end
|
448
|
+
|
422
449
|
options
|
423
450
|
end
|
424
451
|
|
@@ -495,9 +522,9 @@ module Dependabot
|
|
495
522
|
while (remaining_filenames = filenames - ordered_filenames).any?
|
496
523
|
ordered_filenames +=
|
497
524
|
remaining_filenames.
|
498
|
-
|
525
|
+
reject do |fn|
|
499
526
|
unupdated_reqs = requirement_map[fn] - ordered_filenames
|
500
|
-
(
|
527
|
+
unupdated_reqs.intersect?(filenames)
|
501
528
|
end
|
502
529
|
end
|
503
530
|
|
@@ -523,41 +550,6 @@ module Dependabot
|
|
523
550
|
end
|
524
551
|
end
|
525
552
|
|
526
|
-
def python_version
|
527
|
-
@python_version ||=
|
528
|
-
user_specified_python_version ||
|
529
|
-
python_version_matching_imputed_requirements ||
|
530
|
-
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.first
|
531
|
-
end
|
532
|
-
|
533
|
-
def user_specified_python_version
|
534
|
-
return unless python_requirement_parser.user_specified_requirements.any?
|
535
|
-
|
536
|
-
user_specified_requirements =
|
537
|
-
python_requirement_parser.user_specified_requirements.
|
538
|
-
map { |r| Python::Requirement.requirements_array(r) }
|
539
|
-
python_version_matching(user_specified_requirements)
|
540
|
-
end
|
541
|
-
|
542
|
-
def python_version_matching_imputed_requirements
|
543
|
-
compiled_file_python_requirement_markers =
|
544
|
-
python_requirement_parser.imputed_requirements.map do |r|
|
545
|
-
Dependabot::Python::Requirement.new(r)
|
546
|
-
end
|
547
|
-
python_version_matching(compiled_file_python_requirement_markers)
|
548
|
-
end
|
549
|
-
|
550
|
-
def python_version_matching(requirements)
|
551
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.find do |version_string|
|
552
|
-
version = Python::Version.new(version_string)
|
553
|
-
requirements.all? do |req|
|
554
|
-
next req.any? { |r| r.satisfied_by?(version) } if req.is_a?(Array)
|
555
|
-
|
556
|
-
req.satisfied_by?(version)
|
557
|
-
end
|
558
|
-
end
|
559
|
-
end
|
560
|
-
|
561
553
|
def python_requirement_parser
|
562
554
|
@python_requirement_parser ||=
|
563
555
|
FileParser::PythonRequirementParser.new(
|
@@ -565,8 +557,11 @@ module Dependabot
|
|
565
557
|
)
|
566
558
|
end
|
567
559
|
|
568
|
-
def
|
569
|
-
|
560
|
+
def language_version_manager
|
561
|
+
@language_version_manager ||=
|
562
|
+
LanguageVersionManager.new(
|
563
|
+
python_requirement_parser: python_requirement_parser
|
564
|
+
)
|
570
565
|
end
|
571
566
|
|
572
567
|
def setup_files
|
@@ -6,6 +6,7 @@ require "dependabot/dependency"
|
|
6
6
|
require "dependabot/python/requirement_parser"
|
7
7
|
require "dependabot/python/file_parser/python_requirement_parser"
|
8
8
|
require "dependabot/python/file_updater"
|
9
|
+
require "dependabot/python/language_version_manager"
|
9
10
|
require "dependabot/shared_helpers"
|
10
11
|
require "dependabot/python/native_helpers"
|
11
12
|
require "dependabot/python/name_normaliser"
|
@@ -146,7 +147,7 @@ module Dependabot
|
|
146
147
|
def update_python_requirement(pipfile_content)
|
147
148
|
PipfilePreparer.
|
148
149
|
new(pipfile_content: pipfile_content).
|
149
|
-
update_python_requirement(
|
150
|
+
update_python_requirement(language_version_manager.python_major_minor)
|
150
151
|
end
|
151
152
|
|
152
153
|
# rubocop:disable Metrics/PerceivedComplexity
|
@@ -198,10 +199,6 @@ module Dependabot
|
|
198
199
|
write_temporary_dependency_files(prepared_pipfile_content)
|
199
200
|
install_required_python
|
200
201
|
|
201
|
-
# Initialize a git repo to appease pip-tools
|
202
|
-
command = SharedHelpers.escape_command("git init")
|
203
|
-
IO.popen(command, err: %i(child out)) if setup_files.any?
|
204
|
-
|
205
202
|
run_pipenv_command(
|
206
203
|
"pyenv exec pipenv lock"
|
207
204
|
)
|
@@ -271,7 +268,7 @@ module Dependabot
|
|
271
268
|
end
|
272
269
|
|
273
270
|
def run_pipenv_command(command, env: pipenv_env_variables)
|
274
|
-
run_command("pyenv local #{
|
271
|
+
run_command("pyenv local #{language_version_manager.python_major_minor}")
|
275
272
|
run_command(command, env: env)
|
276
273
|
end
|
277
274
|
|
@@ -283,7 +280,7 @@ module Dependabot
|
|
283
280
|
end
|
284
281
|
|
285
282
|
# Overwrite the .python-version with updated content
|
286
|
-
File.write(".python-version",
|
283
|
+
File.write(".python-version", language_version_manager.python_major_minor)
|
287
284
|
|
288
285
|
setup_files.each do |file|
|
289
286
|
path = file.name
|
@@ -309,7 +306,7 @@ module Dependabot
|
|
309
306
|
nil
|
310
307
|
end
|
311
308
|
|
312
|
-
|
309
|
+
language_version_manager.install_required_python
|
313
310
|
end
|
314
311
|
|
315
312
|
def sanitized_setup_file_content(file)
|
@@ -322,57 +319,6 @@ module Dependabot
|
|
322
319
|
sanitized_content
|
323
320
|
end
|
324
321
|
|
325
|
-
def python_version
|
326
|
-
@python_version ||= python_version_from_supported_versions
|
327
|
-
end
|
328
|
-
|
329
|
-
def python_version_from_supported_versions
|
330
|
-
requirement_string =
|
331
|
-
if @using_python_two then "2.7.*"
|
332
|
-
elsif user_specified_python_requirement
|
333
|
-
parts = user_specified_python_requirement.split(".")
|
334
|
-
parts.fill("*", (parts.length)..2).join(".")
|
335
|
-
else
|
336
|
-
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.first
|
337
|
-
end
|
338
|
-
|
339
|
-
# Ideally, the requirement is satisfied by a Python version we support
|
340
|
-
requirement =
|
341
|
-
Python::Requirement.requirements_array(requirement_string).first
|
342
|
-
version =
|
343
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
|
344
|
-
find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
345
|
-
return version if version
|
346
|
-
|
347
|
-
# If not, and changing the patch version would fix things, we do that
|
348
|
-
# as the patch version is unlikely to affect resolution
|
349
|
-
requirement =
|
350
|
-
Python::Requirement.new(requirement_string.gsub(/\.\d+$/, ".*"))
|
351
|
-
version =
|
352
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
|
353
|
-
find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
354
|
-
return version if version
|
355
|
-
|
356
|
-
# Otherwise we have to raise, giving details of the Python versions
|
357
|
-
# that Dependabot supports
|
358
|
-
msg = "Dependabot detected the following Python requirement " \
|
359
|
-
"for your project: '#{requirement_string}'.\n\nCurrently, the " \
|
360
|
-
"following Python versions are supported in Dependabot: " \
|
361
|
-
"#{PythonVersions::SUPPORTED_VERSIONS.join(', ')}."
|
362
|
-
raise DependencyFileNotResolvable, msg
|
363
|
-
end
|
364
|
-
|
365
|
-
def user_specified_python_requirement
|
366
|
-
python_requirement_parser.user_specified_requirements.first
|
367
|
-
end
|
368
|
-
|
369
|
-
def python_requirement_parser
|
370
|
-
@python_requirement_parser ||=
|
371
|
-
FileParser::PythonRequirementParser.new(
|
372
|
-
dependency_files: dependency_files
|
373
|
-
)
|
374
|
-
end
|
375
|
-
|
376
322
|
def setup_cfg(file)
|
377
323
|
dependency_files.find do |f|
|
378
324
|
f.name == file.name.sub(/\.py$/, ".cfg")
|
@@ -400,6 +346,20 @@ module Dependabot
|
|
400
346
|
NameNormaliser.normalise(name)
|
401
347
|
end
|
402
348
|
|
349
|
+
def python_requirement_parser
|
350
|
+
@python_requirement_parser ||=
|
351
|
+
FileParser::PythonRequirementParser.new(
|
352
|
+
dependency_files: dependency_files
|
353
|
+
)
|
354
|
+
end
|
355
|
+
|
356
|
+
def language_version_manager
|
357
|
+
@language_version_manager ||=
|
358
|
+
LanguageVersionManager.new(
|
359
|
+
python_requirement_parser: python_requirement_parser
|
360
|
+
)
|
361
|
+
end
|
362
|
+
|
403
363
|
def parsed_lockfile
|
404
364
|
@parsed_lockfile ||= JSON.parse(lockfile.content)
|
405
365
|
end
|
@@ -21,7 +21,7 @@ module Dependabot
|
|
21
21
|
pipfile_object = TomlRB.parse(pipfile_content)
|
22
22
|
|
23
23
|
pipfile_object["source"] =
|
24
|
-
pipfile_sources.
|
24
|
+
pipfile_sources.filter_map { |h| sub_auth_url(h, credentials) } +
|
25
25
|
config_variable_sources(credentials)
|
26
26
|
|
27
27
|
TomlRB.dump(pipfile_object)
|
@@ -114,6 +114,22 @@ module Dependabot
|
|
114
114
|
map { |h| h.dup.merge("url" => h["url"].gsub(%r{/*$}, "") + "/") }
|
115
115
|
end
|
116
116
|
|
117
|
+
def sub_auth_url(source, credentials)
|
118
|
+
if source["url"].include?("${")
|
119
|
+
base_url = source["url"].sub(/\${.*}@/, "")
|
120
|
+
|
121
|
+
source_cred = credentials.
|
122
|
+
select { |cred| cred["type"] == "python_index" }.
|
123
|
+
find { |c| c["index-url"].sub(/\${.*}@/, "") == base_url }
|
124
|
+
|
125
|
+
return nil if source_cred.nil?
|
126
|
+
|
127
|
+
source["url"] = AuthedUrlBuilder.authed_url(credential: source_cred)
|
128
|
+
end
|
129
|
+
|
130
|
+
source
|
131
|
+
end
|
132
|
+
|
117
133
|
def config_variable_sources(credentials)
|
118
134
|
@config_variable_sources ||=
|
119
135
|
credentials.
|
@@ -4,7 +4,7 @@ require "toml-rb"
|
|
4
4
|
require "open3"
|
5
5
|
require "dependabot/dependency"
|
6
6
|
require "dependabot/shared_helpers"
|
7
|
-
require "dependabot/python/
|
7
|
+
require "dependabot/python/language_version_manager"
|
8
8
|
require "dependabot/python/version"
|
9
9
|
require "dependabot/python/requirement"
|
10
10
|
require "dependabot/python/python_versions"
|
@@ -75,10 +75,17 @@ module Dependabot
|
|
75
75
|
find { |r| r[:file] == pyproject.name }.
|
76
76
|
fetch(:requirement)
|
77
77
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
declaration_regex = declaration_regex(dep)
|
79
|
+
updated_content = if content.match?(declaration_regex)
|
80
|
+
content.gsub(declaration_regex(dep)) do |match|
|
81
|
+
match.gsub(old_req, updated_requirement)
|
82
|
+
end
|
83
|
+
else
|
84
|
+
content.gsub(table_declaration_regex(dep)) do |match|
|
85
|
+
match.gsub(/(\s*version\s*=\s*["'])#{Regexp.escape(old_req)}/,
|
86
|
+
'\1' + updated_requirement)
|
87
|
+
end
|
88
|
+
end
|
82
89
|
|
83
90
|
raise "Content did not change!" if content == updated_content
|
84
91
|
|
@@ -135,7 +142,7 @@ module Dependabot
|
|
135
142
|
def update_python_requirement(pyproject_content)
|
136
143
|
PyprojectPreparer.
|
137
144
|
new(pyproject_content: pyproject_content).
|
138
|
-
update_python_requirement(
|
145
|
+
update_python_requirement(language_version_manager.python_major_minor)
|
139
146
|
end
|
140
147
|
|
141
148
|
def lock_declaration_to_new_version!(poetry_object, dep)
|
@@ -178,14 +185,14 @@ module Dependabot
|
|
178
185
|
write_temporary_dependency_files(pyproject_content)
|
179
186
|
add_auth_env_vars
|
180
187
|
|
181
|
-
|
188
|
+
language_version_manager.install_required_python
|
182
189
|
|
183
190
|
# use system git instead of the pure Python dulwich
|
184
|
-
unless python_version&.start_with?("3.6")
|
191
|
+
unless language_version_manager.python_version&.start_with?("3.6")
|
185
192
|
run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
|
186
193
|
end
|
187
194
|
|
188
|
-
|
195
|
+
run_poetry_update_command
|
189
196
|
|
190
197
|
return File.read("poetry.lock") if File.exist?("poetry.lock")
|
191
198
|
|
@@ -196,11 +203,14 @@ module Dependabot
|
|
196
203
|
|
197
204
|
# Using `--lock` avoids doing an install.
|
198
205
|
# Using `--no-interaction` avoids asking for passwords.
|
199
|
-
def
|
200
|
-
|
206
|
+
def run_poetry_update_command
|
207
|
+
run_poetry_command(
|
208
|
+
"pyenv exec poetry update #{dependency.name} --lock --no-interaction",
|
209
|
+
fingerprint: "pyenv exec poetry update <dependency_name> --lock --no-interaction"
|
210
|
+
)
|
201
211
|
end
|
202
212
|
|
203
|
-
def run_poetry_command(command)
|
213
|
+
def run_poetry_command(command, fingerprint: nil)
|
204
214
|
start = Time.now
|
205
215
|
command = SharedHelpers.escape_command(command)
|
206
216
|
stdout, process = Open3.capture2e(command)
|
@@ -214,6 +224,7 @@ module Dependabot
|
|
214
224
|
message: stdout,
|
215
225
|
error_context: {
|
216
226
|
command: command,
|
227
|
+
fingerprint: fingerprint,
|
217
228
|
time_taken: time_taken,
|
218
229
|
process_exit_value: process.to_s
|
219
230
|
}
|
@@ -228,7 +239,7 @@ module Dependabot
|
|
228
239
|
end
|
229
240
|
|
230
241
|
# Overwrite the .python-version with updated content
|
231
|
-
File.write(".python-version",
|
242
|
+
File.write(".python-version", language_version_manager.python_major_minor)
|
232
243
|
|
233
244
|
# Overwrite the pyproject with updated content
|
234
245
|
File.write("pyproject.toml", pyproject_content)
|
@@ -240,29 +251,6 @@ module Dependabot
|
|
240
251
|
add_auth_env_vars(credentials)
|
241
252
|
end
|
242
253
|
|
243
|
-
def python_version
|
244
|
-
requirements = python_requirement_parser.user_specified_requirements
|
245
|
-
requirements = requirements.
|
246
|
-
map { |r| Python::Requirement.requirements_array(r) }
|
247
|
-
|
248
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.find do |version|
|
249
|
-
requirements.all? do |reqs|
|
250
|
-
reqs.any? { |r| r.satisfied_by?(Python::Version.new(version)) }
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
def python_requirement_parser
|
256
|
-
@python_requirement_parser ||=
|
257
|
-
FileParser::PythonRequirementParser.new(
|
258
|
-
dependency_files: dependency_files
|
259
|
-
)
|
260
|
-
end
|
261
|
-
|
262
|
-
def pre_installed_python?(version)
|
263
|
-
PythonVersions::PRE_INSTALLED_PYTHON_VERSIONS.include?(version)
|
264
|
-
end
|
265
|
-
|
266
254
|
def pyproject_hash_for(pyproject_content)
|
267
255
|
SharedHelpers.in_a_temporary_directory do |dir|
|
268
256
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
@@ -278,8 +266,15 @@ module Dependabot
|
|
278
266
|
end
|
279
267
|
|
280
268
|
def declaration_regex(dep)
|
281
|
-
|
282
|
-
|
269
|
+
/(?:^\s*|["'])#{escape(dep)}["']?\s*=.*$/i
|
270
|
+
end
|
271
|
+
|
272
|
+
def table_declaration_regex(dep)
|
273
|
+
/tool\.poetry\.[^\n]+\.#{escape(dep)}\]\n.*?\s*version\s* =.*?\n/m
|
274
|
+
end
|
275
|
+
|
276
|
+
def escape(dep)
|
277
|
+
Regexp.escape(dep.name).gsub("\\-", "[-_.]")
|
283
278
|
end
|
284
279
|
|
285
280
|
def file_changed?(file)
|
@@ -303,6 +298,20 @@ module Dependabot
|
|
303
298
|
NameNormaliser.normalise(name)
|
304
299
|
end
|
305
300
|
|
301
|
+
def python_requirement_parser
|
302
|
+
@python_requirement_parser ||=
|
303
|
+
FileParser::PythonRequirementParser.new(
|
304
|
+
dependency_files: dependency_files
|
305
|
+
)
|
306
|
+
end
|
307
|
+
|
308
|
+
def language_version_manager
|
309
|
+
@language_version_manager ||=
|
310
|
+
LanguageVersionManager.new(
|
311
|
+
python_requirement_parser: python_requirement_parser
|
312
|
+
)
|
313
|
+
end
|
314
|
+
|
306
315
|
def pyproject
|
307
316
|
@pyproject ||=
|
308
317
|
dependency_files.find { |f| f.name == "pyproject.toml" }
|