dependabot-python 0.226.0 → 0.228.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/helpers/requirements.txt +4 -3
- data/lib/dependabot/python/file_fetcher.rb +3 -7
- data/lib/dependabot/python/file_parser/pyproject_files_parser.rb +40 -19
- data/lib/dependabot/python/file_parser.rb +0 -4
- data/lib/dependabot/python/file_updater/pip_compile_file_updater.rb +0 -1
- data/lib/dependabot/python/file_updater/poetry_file_updater.rb +15 -41
- data/lib/dependabot/python/file_updater.rb +1 -5
- data/lib/dependabot/python/helpers.rb +34 -0
- data/lib/dependabot/python/language_version_manager.rb +24 -44
- data/lib/dependabot/python/update_checker/index_finder.rb +3 -0
- data/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb +2 -8
- data/lib/dependabot/python/update_checker/pipenv_version_resolver.rb +6 -9
- data/lib/dependabot/python/update_checker/poetry_version_resolver.rb +22 -68
- data/lib/dependabot/python/update_checker.rb +3 -7
- metadata +10 -10
- data/lib/dependabot/python/python_versions.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67fcdac9ca728ef251cf259a11a3d1efec3f037715f9587bc30896baf3abcad9
|
4
|
+
data.tar.gz: 00cf4ecfceeba160a6ccb95c84853f782df01f571ea17b320609205a6138e76e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e320bfeef5f545705df3daf17edf15cf9633b3ed2a6438bc1cd12ec3fc66d8abd1248d20898b0a8aca1d3aaa86f1b512f951179c4708706af36d64a93b0a5933
|
7
|
+
data.tar.gz: 9bc806e1d363784ed23ed71d694154e8d37f967bb1d559348852fffdde381889b2f235658b5dc424c9400589483d76c08b5f1f608eb15e43e59e70bc773a266a
|
data/helpers/requirements.txt
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
pip
|
2
|
-
pip-tools
|
1
|
+
pip==23.2.1
|
2
|
+
pip-tools==7.3.0
|
3
|
+
flake8==6.1.0
|
3
4
|
hashin==0.17.0
|
4
5
|
pipenv==2022.4.8
|
5
6
|
pipfile==0.0.2
|
6
|
-
poetry
|
7
|
+
poetry==1.6.1
|
7
8
|
|
8
9
|
# Some dependencies will only install if Cython is present
|
9
10
|
Cython==3.0.0
|
@@ -4,8 +4,10 @@ require "toml-rb"
|
|
4
4
|
|
5
5
|
require "dependabot/file_fetchers"
|
6
6
|
require "dependabot/file_fetchers/base"
|
7
|
+
require "dependabot/python/language_version_manager"
|
7
8
|
require "dependabot/python/requirement_parser"
|
8
9
|
require "dependabot/python/file_parser/pyproject_files_parser"
|
10
|
+
require "dependabot/python/file_parser/python_requirement_parser"
|
9
11
|
require "dependabot/errors"
|
10
12
|
|
11
13
|
module Dependabot
|
@@ -91,7 +93,7 @@ module Dependabot
|
|
91
93
|
end
|
92
94
|
|
93
95
|
def pyproject_files
|
94
|
-
[pyproject,
|
96
|
+
[pyproject, poetry_lock, pdm_lock].compact
|
95
97
|
end
|
96
98
|
|
97
99
|
def requirement_files
|
@@ -166,12 +168,6 @@ module Dependabot
|
|
166
168
|
@pyproject = fetch_file_if_present("pyproject.toml")
|
167
169
|
end
|
168
170
|
|
169
|
-
def pyproject_lock
|
170
|
-
return @pyproject_lock if defined?(@pyproject_lock)
|
171
|
-
|
172
|
-
@pyproject_lock = fetch_file_if_present("pyproject.lock")
|
173
|
-
end
|
174
|
-
|
175
171
|
def poetry_lock
|
176
172
|
return @poetry_lock if defined?(@poetry_lock)
|
177
173
|
|
@@ -7,6 +7,7 @@ require "dependabot/file_parsers/base/dependency_set"
|
|
7
7
|
require "dependabot/python/file_parser"
|
8
8
|
require "dependabot/python/requirement"
|
9
9
|
require "dependabot/errors"
|
10
|
+
require "dependabot/python/helpers"
|
10
11
|
require "dependabot/python/name_normaliser"
|
11
12
|
|
12
13
|
module Dependabot
|
@@ -44,16 +45,20 @@ module Dependabot
|
|
44
45
|
end
|
45
46
|
|
46
47
|
def poetry_dependencies
|
48
|
+
@poetry_dependencies ||= parse_poetry_dependencies
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse_poetry_dependencies
|
47
52
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
48
53
|
|
49
54
|
POETRY_DEPENDENCY_TYPES.each do |type|
|
50
55
|
deps_hash = parsed_pyproject.dig("tool", "poetry", type) || {}
|
51
|
-
dependencies +=
|
56
|
+
dependencies += parse_poetry_dependency_group(type, deps_hash)
|
52
57
|
end
|
53
58
|
|
54
59
|
groups = parsed_pyproject.dig("tool", "poetry", "group") || {}
|
55
60
|
groups.each do |group, group_spec|
|
56
|
-
dependencies +=
|
61
|
+
dependencies += parse_poetry_dependency_group(group, group_spec["dependencies"])
|
57
62
|
end
|
58
63
|
dependencies
|
59
64
|
end
|
@@ -92,7 +97,7 @@ module Dependabot
|
|
92
97
|
dependencies
|
93
98
|
end
|
94
99
|
|
95
|
-
def
|
100
|
+
def parse_poetry_dependency_group(type, deps_hash)
|
96
101
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
97
102
|
|
98
103
|
deps_hash.each do |name, req|
|
@@ -154,14 +159,16 @@ module Dependabot
|
|
154
159
|
parsed_lockfile.fetch("package", []).each do |details|
|
155
160
|
next if source_types.include?(details.dig("source", "type"))
|
156
161
|
|
162
|
+
name = normalise(details.fetch("name"))
|
163
|
+
|
157
164
|
dependencies <<
|
158
165
|
Dependency.new(
|
159
|
-
name:
|
166
|
+
name: name,
|
160
167
|
version: details.fetch("version"),
|
161
168
|
requirements: [],
|
162
169
|
package_manager: "pip",
|
163
170
|
subdependency_metadata: [{
|
164
|
-
production:
|
171
|
+
production: production_dependency_names.include?(name)
|
165
172
|
}]
|
166
173
|
)
|
167
174
|
end
|
@@ -169,6 +176,32 @@ module Dependabot
|
|
169
176
|
dependencies
|
170
177
|
end
|
171
178
|
|
179
|
+
def production_dependency_names
|
180
|
+
@production_dependency_names ||= parse_production_dependency_names
|
181
|
+
end
|
182
|
+
|
183
|
+
def parse_production_dependency_names
|
184
|
+
SharedHelpers.in_a_temporary_directory do
|
185
|
+
File.write(pyproject.name, pyproject.content)
|
186
|
+
File.write(lockfile.name, lockfile.content)
|
187
|
+
|
188
|
+
begin
|
189
|
+
output = Helpers.run_poetry_command("pyenv exec poetry show --only main")
|
190
|
+
|
191
|
+
output.split("\n").map { |line| line.split.first }
|
192
|
+
rescue SharedHelpers::HelperSubprocessFailed
|
193
|
+
# Sometimes, we may be dealing with an old lockfile that our
|
194
|
+
# poetry version can't show dependency information for. Other
|
195
|
+
# commands we use like `poetry update` are more resilient and
|
196
|
+
# automatically heal the lockfile. So we rescue the error and make
|
197
|
+
# a best effort approach to this.
|
198
|
+
poetry_dependencies.dependencies.filter_map do |dep|
|
199
|
+
dep.name if dep.production?
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
172
205
|
def version_from_lockfile(dep_name)
|
173
206
|
return unless parsed_lockfile
|
174
207
|
|
@@ -194,12 +227,6 @@ module Dependabot
|
|
194
227
|
raise Dependabot::DependencyFileNotParseable, pyproject.path
|
195
228
|
end
|
196
229
|
|
197
|
-
def parsed_pyproject_lock
|
198
|
-
@parsed_pyproject_lock ||= TomlRB.parse(pyproject_lock.content)
|
199
|
-
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
200
|
-
raise Dependabot::DependencyFileNotParseable, pyproject_lock.path
|
201
|
-
end
|
202
|
-
|
203
230
|
def parsed_poetry_lock
|
204
231
|
@parsed_poetry_lock ||= TomlRB.parse(poetry_lock.content)
|
205
232
|
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
@@ -212,7 +239,7 @@ module Dependabot
|
|
212
239
|
end
|
213
240
|
|
214
241
|
def lockfile
|
215
|
-
poetry_lock
|
242
|
+
poetry_lock
|
216
243
|
end
|
217
244
|
|
218
245
|
def parsed_pep621_dependencies
|
@@ -234,13 +261,7 @@ module Dependabot
|
|
234
261
|
end
|
235
262
|
|
236
263
|
def parsed_lockfile
|
237
|
-
|
238
|
-
return parsed_pyproject_lock if pyproject_lock
|
239
|
-
end
|
240
|
-
|
241
|
-
def pyproject_lock
|
242
|
-
@pyproject_lock ||=
|
243
|
-
dependency_files.find { |f| f.name == "pyproject.lock" }
|
264
|
+
parsed_poetry_lock if poetry_lock
|
244
265
|
end
|
245
266
|
|
246
267
|
def poetry_lock
|
@@ -208,10 +208,6 @@ module Dependabot
|
|
208
208
|
@pyproject ||= get_original_file("pyproject.toml")
|
209
209
|
end
|
210
210
|
|
211
|
-
def pyproject_lock
|
212
|
-
@pyproject_lock ||= get_original_file("pyproject.lock")
|
213
|
-
end
|
214
|
-
|
215
211
|
def poetry_lock
|
216
212
|
@poetry_lock ||= get_original_file("poetry.lock")
|
217
213
|
end
|
@@ -9,7 +9,6 @@ require "dependabot/python/file_updater"
|
|
9
9
|
require "dependabot/shared_helpers"
|
10
10
|
require "dependabot/python/language_version_manager"
|
11
11
|
require "dependabot/python/native_helpers"
|
12
|
-
require "dependabot/python/python_versions"
|
13
12
|
require "dependabot/python/name_normaliser"
|
14
13
|
require "dependabot/python/authed_url_builder"
|
15
14
|
|
@@ -7,9 +7,9 @@ require "dependabot/shared_helpers"
|
|
7
7
|
require "dependabot/python/language_version_manager"
|
8
8
|
require "dependabot/python/version"
|
9
9
|
require "dependabot/python/requirement"
|
10
|
-
require "dependabot/python/python_versions"
|
11
10
|
require "dependabot/python/file_parser/python_requirement_parser"
|
12
11
|
require "dependabot/python/file_updater"
|
12
|
+
require "dependabot/python/helpers"
|
13
13
|
require "dependabot/python/native_helpers"
|
14
14
|
require "dependabot/python/name_normaliser"
|
15
15
|
|
@@ -95,6 +95,12 @@ module Dependabot
|
|
95
95
|
begin
|
96
96
|
new_lockfile = updated_lockfile_content_for(prepared_pyproject)
|
97
97
|
|
98
|
+
original_locked_python = TomlRB.parse(lockfile.content)["metadata"]["python-versions"]
|
99
|
+
|
100
|
+
new_lockfile.gsub!(/\[metadata\]\n.*python-versions[^\n]+\n/m) do |match|
|
101
|
+
match.gsub(/(["']).*(['"])\n\Z/, '\1' + original_locked_python + '\1' + "\n")
|
102
|
+
end
|
103
|
+
|
98
104
|
tmp_hash =
|
99
105
|
TomlRB.parse(new_lockfile)["metadata"]["content-hash"]
|
100
106
|
correct_hash = pyproject_hash_for(updated_pyproject_content)
|
@@ -139,7 +145,7 @@ module Dependabot
|
|
139
145
|
def update_python_requirement(pyproject_content)
|
140
146
|
PyprojectPreparer.
|
141
147
|
new(pyproject_content: pyproject_content).
|
142
|
-
update_python_requirement(language_version_manager.
|
148
|
+
update_python_requirement(language_version_manager.python_version)
|
143
149
|
end
|
144
150
|
|
145
151
|
def lock_declaration_to_new_version!(poetry_object, dep)
|
@@ -157,17 +163,10 @@ module Dependabot
|
|
157
163
|
end
|
158
164
|
|
159
165
|
def create_declaration_at_new_version!(poetry_object, dep)
|
160
|
-
|
161
|
-
poetry_object[subdep_type][dependency.name] = dep.version
|
162
|
-
end
|
163
|
-
|
164
|
-
def subdep_type
|
165
|
-
category =
|
166
|
-
TomlRB.parse(lockfile.content).fetch("package", []).
|
167
|
-
find { |dets| normalise(dets.fetch("name")) == dependency.name }.
|
168
|
-
fetch("category")
|
166
|
+
subdep_type = dep.production? ? "dependencies" : "dev-dependencies"
|
169
167
|
|
170
|
-
|
168
|
+
poetry_object[subdep_type] ||= {}
|
169
|
+
poetry_object[subdep_type][dep.name] = dep.version
|
171
170
|
end
|
172
171
|
|
173
172
|
def sanitize(pyproject_content)
|
@@ -185,15 +184,11 @@ module Dependabot
|
|
185
184
|
language_version_manager.install_required_python
|
186
185
|
|
187
186
|
# use system git instead of the pure Python dulwich
|
188
|
-
|
189
|
-
run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
|
190
|
-
end
|
187
|
+
run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
|
191
188
|
|
192
189
|
run_poetry_update_command
|
193
190
|
|
194
|
-
|
195
|
-
|
196
|
-
File.read("pyproject.lock")
|
191
|
+
File.read("poetry.lock")
|
197
192
|
end
|
198
193
|
end
|
199
194
|
end
|
@@ -208,24 +203,7 @@ module Dependabot
|
|
208
203
|
end
|
209
204
|
|
210
205
|
def run_poetry_command(command, fingerprint: nil)
|
211
|
-
|
212
|
-
command = SharedHelpers.escape_command(command)
|
213
|
-
stdout, process = Open3.capture2e(command)
|
214
|
-
time_taken = Time.now - start
|
215
|
-
|
216
|
-
# Raise an error with the output from the shell session if Pipenv
|
217
|
-
# returns a non-zero status
|
218
|
-
return if process.success?
|
219
|
-
|
220
|
-
raise SharedHelpers::HelperSubprocessFailed.new(
|
221
|
-
message: stdout,
|
222
|
-
error_context: {
|
223
|
-
command: command,
|
224
|
-
fingerprint: fingerprint,
|
225
|
-
time_taken: time_taken,
|
226
|
-
process_exit_value: process.to_s
|
227
|
-
}
|
228
|
-
)
|
206
|
+
Helpers.run_poetry_command(command, fingerprint: fingerprint)
|
229
207
|
end
|
230
208
|
|
231
209
|
def write_temporary_dependency_files(pyproject_content)
|
@@ -315,17 +293,13 @@ module Dependabot
|
|
315
293
|
end
|
316
294
|
|
317
295
|
def lockfile
|
318
|
-
@lockfile ||=
|
296
|
+
@lockfile ||= poetry_lock
|
319
297
|
end
|
320
298
|
|
321
299
|
def python_helper_path
|
322
300
|
NativeHelpers.python_helper_path
|
323
301
|
end
|
324
302
|
|
325
|
-
def pyproject_lock
|
326
|
-
dependency_files.find { |f| f.name == "pyproject.lock" }
|
327
|
-
end
|
328
|
-
|
329
303
|
def poetry_lock
|
330
304
|
dependency_files.find { |f| f.name == "poetry.lock" }
|
331
305
|
end
|
@@ -77,7 +77,7 @@ module Dependabot
|
|
77
77
|
|
78
78
|
def subdependency_resolver
|
79
79
|
return :pipfile if pipfile_lock
|
80
|
-
return :poetry if poetry_lock
|
80
|
+
return :poetry if poetry_lock
|
81
81
|
return :pip_compile if pip_compile_files.any?
|
82
82
|
|
83
83
|
raise "Claimed to be a sub-dependency, but no lockfile exists!"
|
@@ -144,10 +144,6 @@ module Dependabot
|
|
144
144
|
@pyproject ||= get_original_file("pyproject.toml")
|
145
145
|
end
|
146
146
|
|
147
|
-
def pyproject_lock
|
148
|
-
@pyproject_lock ||= get_original_file("pyproject.lock")
|
149
|
-
end
|
150
|
-
|
151
147
|
def poetry_lock
|
152
148
|
@poetry_lock ||= get_original_file("poetry.lock")
|
153
149
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "time"
|
4
|
+
require "open3"
|
5
|
+
|
6
|
+
require "dependabot/errors"
|
7
|
+
require "dependabot/shared_helpers"
|
8
|
+
|
9
|
+
module Dependabot
|
10
|
+
module Python
|
11
|
+
module Helpers
|
12
|
+
def self.run_poetry_command(command, fingerprint: nil)
|
13
|
+
start = Time.now
|
14
|
+
command = SharedHelpers.escape_command(command)
|
15
|
+
stdout, stderr, process = Open3.capture3(command)
|
16
|
+
time_taken = Time.now - start
|
17
|
+
|
18
|
+
# Raise an error with the output from the shell session if Poetry
|
19
|
+
# returns a non-zero status
|
20
|
+
return stdout if process.success?
|
21
|
+
|
22
|
+
raise SharedHelpers::HelperSubprocessFailed.new(
|
23
|
+
message: stderr,
|
24
|
+
error_context: {
|
25
|
+
command: command,
|
26
|
+
fingerprint: fingerprint,
|
27
|
+
time_taken: time_taken,
|
28
|
+
process_exit_value: process.to_s
|
29
|
+
}
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -6,6 +6,14 @@ require "dependabot/python/version"
|
|
6
6
|
module Dependabot
|
7
7
|
module Python
|
8
8
|
class LanguageVersionManager
|
9
|
+
# This list must match the versions specified at the top of `python/Dockerfile`
|
10
|
+
PRE_INSTALLED_PYTHON_VERSIONS = %w(
|
11
|
+
3.11.4
|
12
|
+
3.10.12
|
13
|
+
3.9.17
|
14
|
+
3.8.17
|
15
|
+
).freeze
|
16
|
+
|
9
17
|
def initialize(python_requirement_parser:)
|
10
18
|
@python_requirement_parser = python_requirement_parser
|
11
19
|
end
|
@@ -14,22 +22,9 @@ module Dependabot
|
|
14
22
|
# The leading space is important in the version check
|
15
23
|
return if SharedHelpers.run_shell_command("pyenv versions").include?(" #{python_major_minor}.")
|
16
24
|
|
17
|
-
|
18
|
-
|
19
|
-
|
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.")
|
25
|
+
SharedHelpers.run_shell_command(
|
26
|
+
"tar xzf /usr/local/.pyenv/#{python_major_minor}.tar.gz -C /usr/local/.pyenv/"
|
27
|
+
)
|
33
28
|
end
|
34
29
|
|
35
30
|
def python_major_minor
|
@@ -48,42 +43,27 @@ module Dependabot
|
|
48
43
|
else
|
49
44
|
user_specified_python_version
|
50
45
|
end
|
51
|
-
elsif python_version_matching_imputed_requirements
|
52
|
-
python_version_matching_imputed_requirements
|
53
46
|
else
|
54
|
-
|
47
|
+
python_version_matching_imputed_requirements || PRE_INSTALLED_PYTHON_VERSIONS.first
|
55
48
|
end
|
56
49
|
end
|
57
50
|
|
58
51
|
def python_version_from_supported_versions
|
59
52
|
requirement_string = python_requirement_string
|
60
53
|
|
61
|
-
#
|
62
|
-
|
63
|
-
|
64
|
-
version =
|
65
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
|
66
|
-
find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
67
|
-
return version if version
|
54
|
+
# If the requirement string isn't already a range (eg ">3.10"), coerce it to "major.minor.*".
|
55
|
+
# The patch version is ignored because a non-matching patch version is unlikely to affect resolution.
|
56
|
+
requirement_string = requirement_string.gsub(/\.\d+$/, ".*") if requirement_string.start_with?(/\d/)
|
68
57
|
|
69
|
-
#
|
70
|
-
|
71
|
-
|
72
|
-
if
|
73
|
-
requirement =
|
74
|
-
Python::Requirement.new(requirement_string.gsub(/\.\d+$/, ".*"))
|
75
|
-
version =
|
76
|
-
PythonVersions::SUPPORTED_VERSIONS_TO_ITERATE.
|
77
|
-
find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
78
|
-
return version if version
|
79
|
-
end
|
58
|
+
# Try to match one of our pre-installed Python versions
|
59
|
+
requirement = Python::Requirement.requirements_array(requirement_string).first
|
60
|
+
version = PRE_INSTALLED_PYTHON_VERSIONS.find { |v| requirement.satisfied_by?(Python::Version.new(v)) }
|
61
|
+
return version if version
|
80
62
|
|
81
|
-
# Otherwise we have to raise
|
82
|
-
|
83
|
-
|
84
|
-
"
|
85
|
-
"following Python versions are supported in Dependabot: " \
|
86
|
-
"#{PythonVersions::SUPPORTED_VERSIONS.join(', ')}."
|
63
|
+
# Otherwise we have to raise
|
64
|
+
msg = "Dependabot detected the following Python requirement for your project: '#{python_requirement_string}'." \
|
65
|
+
"\n\nCurrently, the following Python versions are supported in Dependabot: " \
|
66
|
+
"#{PRE_INSTALLED_PYTHON_VERSIONS.map { |x| x.gsub(/\.\d+$/, '.*') }.join(', ')}."
|
87
67
|
raise DependencyFileNotResolvable, msg
|
88
68
|
end
|
89
69
|
|
@@ -100,7 +80,7 @@ module Dependabot
|
|
100
80
|
end
|
101
81
|
|
102
82
|
def python_version_matching(requirements)
|
103
|
-
|
83
|
+
PRE_INSTALLED_PYTHON_VERSIONS.find do |version_string|
|
104
84
|
version = Python::Version.new(version_string)
|
105
85
|
requirements.all? do |req|
|
106
86
|
next req.any? { |r| r.satisfied_by?(version) } if req.is_a?(Array)
|
@@ -13,7 +13,6 @@ require "dependabot/python/version"
|
|
13
13
|
require "dependabot/shared_helpers"
|
14
14
|
require "dependabot/python/language_version_manager"
|
15
15
|
require "dependabot/python/native_helpers"
|
16
|
-
require "dependabot/python/python_versions"
|
17
16
|
require "dependabot/python/name_normaliser"
|
18
17
|
require "dependabot/python/authed_url_builder"
|
19
18
|
|
@@ -23,7 +22,6 @@ module Dependabot
|
|
23
22
|
# This class does version resolution for pip-compile. Its approach is:
|
24
23
|
# - Unlock the dependency we're checking in the requirements.in file
|
25
24
|
# - Run `pip-compile` and see what the result is
|
26
|
-
# rubocop:disable Metrics/ClassLength
|
27
25
|
class PipCompileVersionResolver
|
28
26
|
GIT_DEPENDENCY_UNREACHABLE_REGEX = /git clone --filter=blob:none --quiet (?<url>[^\s]+).* /
|
29
27
|
GIT_REFERENCE_NOT_FOUND_REGEX = /Did not find branch or tag '(?<tag>[^\n"]+)'/m
|
@@ -236,10 +234,6 @@ module Dependabot
|
|
236
234
|
)
|
237
235
|
end
|
238
236
|
|
239
|
-
def new_resolver_supported?
|
240
|
-
language_version_manager.python_version >= Python::Version.new("3.7")
|
241
|
-
end
|
242
|
-
|
243
237
|
def pip_compile_options_fingerprint(options)
|
244
238
|
options.sub(
|
245
239
|
/--output-file=\S+/, "--output-file=<output_file>"
|
@@ -253,8 +247,9 @@ module Dependabot
|
|
253
247
|
def pip_compile_options(filename)
|
254
248
|
options = @build_isolation ? ["--build-isolation"] : ["--no-build-isolation"]
|
255
249
|
options += pip_compile_index_options
|
250
|
+
# TODO: Stop explicitly specifying `allow-unsafe` once it becomes the default:
|
251
|
+
# https://github.com/jazzband/pip-tools/issues/989#issuecomment-1661254701
|
256
252
|
options += ["--allow-unsafe"]
|
257
|
-
options += ["--resolver backtracking"] if new_resolver_supported?
|
258
253
|
|
259
254
|
if (requirements_file = compiled_file_for_filename(filename))
|
260
255
|
options << "--output-file=#{requirements_file.name}"
|
@@ -502,7 +497,6 @@ module Dependabot
|
|
502
497
|
dependency_files.select { |f| f.name.end_with?("setup.cfg") }
|
503
498
|
end
|
504
499
|
end
|
505
|
-
# rubocop:enable Metrics/ClassLength
|
506
500
|
end
|
507
501
|
end
|
508
502
|
end
|
@@ -11,7 +11,6 @@ require "dependabot/python/file_parser/python_requirement_parser"
|
|
11
11
|
require "dependabot/python/file_updater/pipfile_preparer"
|
12
12
|
require "dependabot/python/file_updater/setup_file_sanitizer"
|
13
13
|
require "dependabot/python/update_checker"
|
14
|
-
require "dependabot/python/python_versions"
|
15
14
|
require "dependabot/python/native_helpers"
|
16
15
|
require "dependabot/python/name_normaliser"
|
17
16
|
require "dependabot/python/version"
|
@@ -40,7 +39,7 @@ module Dependabot
|
|
40
39
|
|
41
40
|
UNSUPPORTED_DEPS = %w(pyobjc).freeze
|
42
41
|
UNSUPPORTED_DEP_REGEX =
|
43
|
-
/Could not find a version that satisfies the requirement.*(?:#{UNSUPPORTED_DEPS.join(
|
42
|
+
/Could not find a version that satisfies the requirement.*(?:#{UNSUPPORTED_DEPS.join('|')})/
|
44
43
|
PIPENV_RANGE_WARNING = /Warning:\sPython\s[<>].* was not found/
|
45
44
|
# rubocop:enable Layout/LineLength
|
46
45
|
|
@@ -208,15 +207,13 @@ module Dependabot
|
|
208
207
|
# errors when failing to update
|
209
208
|
def check_original_requirements_resolvable
|
210
209
|
SharedHelpers.in_a_temporary_directory do
|
211
|
-
|
212
|
-
write_temporary_dependency_files(update_pipfile: false)
|
210
|
+
write_temporary_dependency_files(update_pipfile: false)
|
213
211
|
|
214
|
-
|
212
|
+
run_pipenv_command("pyenv exec pipenv lock")
|
215
213
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
end
|
214
|
+
true
|
215
|
+
rescue SharedHelpers::HelperSubprocessFailed => e
|
216
|
+
handle_pipenv_errors_resolving_original_reqs(e)
|
220
217
|
end
|
221
218
|
end
|
222
219
|
|
@@ -13,8 +13,8 @@ require "dependabot/python/file_updater/pyproject_preparer"
|
|
13
13
|
require "dependabot/python/update_checker"
|
14
14
|
require "dependabot/python/version"
|
15
15
|
require "dependabot/python/requirement"
|
16
|
+
require "dependabot/python/helpers"
|
16
17
|
require "dependabot/python/native_helpers"
|
17
|
-
require "dependabot/python/python_versions"
|
18
18
|
require "dependabot/python/authed_url_builder"
|
19
19
|
require "dependabot/python/name_normaliser"
|
20
20
|
|
@@ -24,30 +24,19 @@ module Dependabot
|
|
24
24
|
# This class does version resolution for pyproject.toml files.
|
25
25
|
class PoetryVersionResolver
|
26
26
|
GIT_REFERENCE_NOT_FOUND_REGEX = /
|
27
|
-
(
|
28
|
-
'checkout',
|
29
|
-
'(?<tag>.+?)'
|
30
|
-
|
|
31
|
-
Failed to checkout
|
27
|
+
(Failed to checkout
|
32
28
|
(?<tag>.+?)
|
33
29
|
(?<url>.+?).git at '(?<tag>.+?)'
|
34
30
|
|
|
35
31
|
...Failedtoclone
|
36
32
|
(?<url>.+?).gitat'(?<tag>.+?)',
|
37
33
|
verifyrefexistsonremote)
|
38
|
-
/x
|
34
|
+
/x
|
39
35
|
GIT_DEPENDENCY_UNREACHABLE_REGEX = /
|
40
|
-
(?:'\['git',
|
41
|
-
\s+'clone',
|
42
|
-
\s+'--recurse-submodules',
|
43
|
-
\s+'(--)?',
|
44
|
-
\s+'(?<url>.+?)'.*
|
45
|
-
\s+exit\s+status\s+128
|
46
|
-
|
|
47
36
|
\s+Failed\sto\sclone
|
48
37
|
\s+(?<url>.+?),
|
49
|
-
\s+check\syour\sgit\sconfiguration
|
50
|
-
/mx
|
38
|
+
\s+check\syour\sgit\sconfiguration
|
39
|
+
/mx
|
51
40
|
|
52
41
|
attr_reader :dependency, :dependency_files, :credentials
|
53
42
|
|
@@ -74,8 +63,7 @@ module Dependabot
|
|
74
63
|
false
|
75
64
|
end
|
76
65
|
rescue SharedHelpers::HelperSubprocessFailed => e
|
77
|
-
raise unless e.message.include?("
|
78
|
-
e.message.include?("version solving failed.")
|
66
|
+
raise unless e.message.include?("version solving failed.")
|
79
67
|
|
80
68
|
@resolvable[version] = false
|
81
69
|
end
|
@@ -95,18 +83,12 @@ module Dependabot
|
|
95
83
|
language_version_manager.install_required_python
|
96
84
|
|
97
85
|
# use system git instead of the pure Python dulwich
|
98
|
-
|
99
|
-
run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
|
100
|
-
end
|
86
|
+
run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
|
101
87
|
|
102
88
|
# Shell out to Poetry, which handles everything for us.
|
103
89
|
run_poetry_update_command
|
104
90
|
|
105
|
-
updated_lockfile =
|
106
|
-
if File.exist?("poetry.lock") then File.read("poetry.lock")
|
107
|
-
else
|
108
|
-
File.read("pyproject.lock")
|
109
|
-
end
|
91
|
+
updated_lockfile = File.read("poetry.lock")
|
110
92
|
updated_lockfile = TomlRB.parse(updated_lockfile)
|
111
93
|
|
112
94
|
fetch_version_from_parsed_lockfile(updated_lockfile)
|
@@ -147,7 +129,7 @@ module Dependabot
|
|
147
129
|
end
|
148
130
|
|
149
131
|
raise unless error.message.include?("SolverProblemError") ||
|
150
|
-
error.message.include?("
|
132
|
+
error.message.include?("not found") ||
|
151
133
|
error.message.include?("version solving failed.")
|
152
134
|
|
153
135
|
check_original_requirements_resolvable
|
@@ -174,20 +156,18 @@ module Dependabot
|
|
174
156
|
return @original_reqs_resolvable if @original_reqs_resolvable
|
175
157
|
|
176
158
|
SharedHelpers.in_a_temporary_directory do
|
177
|
-
|
178
|
-
write_temporary_dependency_files(update_pyproject: false)
|
159
|
+
write_temporary_dependency_files(update_pyproject: false)
|
179
160
|
|
180
|
-
|
161
|
+
run_poetry_update_command
|
181
162
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
163
|
+
@original_reqs_resolvable = true
|
164
|
+
rescue SharedHelpers::HelperSubprocessFailed => e
|
165
|
+
raise unless e.message.include?("SolverProblemError") ||
|
166
|
+
e.message.include?("not found") ||
|
167
|
+
e.message.include?("version solving failed.")
|
187
168
|
|
188
|
-
|
189
|
-
|
190
|
-
end
|
169
|
+
msg = clean_error_message(e.message)
|
170
|
+
raise DependencyFileNotResolvable, msg
|
191
171
|
end
|
192
172
|
end
|
193
173
|
|
@@ -249,7 +229,7 @@ module Dependabot
|
|
249
229
|
def update_python_requirement(pyproject_content)
|
250
230
|
Python::FileUpdater::PyprojectPreparer.
|
251
231
|
new(pyproject_content: pyproject_content).
|
252
|
-
update_python_requirement(language_version_manager.
|
232
|
+
update_python_requirement(language_version_manager.python_version)
|
253
233
|
end
|
254
234
|
|
255
235
|
def freeze_other_dependencies(pyproject_content)
|
@@ -298,12 +278,7 @@ module Dependabot
|
|
298
278
|
end
|
299
279
|
|
300
280
|
def subdep_type
|
301
|
-
|
302
|
-
TomlRB.parse(lockfile.content).fetch("package", []).
|
303
|
-
find { |dets| normalise(dets.fetch("name")) == dependency.name }.
|
304
|
-
fetch("category")
|
305
|
-
|
306
|
-
category == "dev" ? "dev-dependencies" : "dependencies"
|
281
|
+
dependency.production? ? "dependencies" : "dev-dependencies"
|
307
282
|
end
|
308
283
|
|
309
284
|
def python_requirement_parser
|
@@ -324,37 +299,16 @@ module Dependabot
|
|
324
299
|
dependency_files.find { |f| f.name == "pyproject.toml" }
|
325
300
|
end
|
326
301
|
|
327
|
-
def pyproject_lock
|
328
|
-
dependency_files.find { |f| f.name == "pyproject.lock" }
|
329
|
-
end
|
330
|
-
|
331
302
|
def poetry_lock
|
332
303
|
dependency_files.find { |f| f.name == "poetry.lock" }
|
333
304
|
end
|
334
305
|
|
335
306
|
def lockfile
|
336
|
-
poetry_lock
|
307
|
+
poetry_lock
|
337
308
|
end
|
338
309
|
|
339
310
|
def run_poetry_command(command, fingerprint: nil)
|
340
|
-
|
341
|
-
command = SharedHelpers.escape_command(command)
|
342
|
-
stdout, process = Open3.capture2e(command)
|
343
|
-
time_taken = Time.now - start
|
344
|
-
|
345
|
-
# Raise an error with the output from the shell session if poetry
|
346
|
-
# returns a non-zero status
|
347
|
-
return if process.success?
|
348
|
-
|
349
|
-
raise SharedHelpers::HelperSubprocessFailed.new(
|
350
|
-
message: stdout,
|
351
|
-
error_context: {
|
352
|
-
command: command,
|
353
|
-
fingerprint: fingerprint,
|
354
|
-
time_taken: time_taken,
|
355
|
-
process_exit_value: process.to_s
|
356
|
-
}
|
357
|
-
)
|
311
|
+
Helpers.run_poetry_command(command, fingerprint: fingerprint)
|
358
312
|
end
|
359
313
|
|
360
314
|
def normalise(name)
|
@@ -74,7 +74,7 @@ module Dependabot
|
|
74
74
|
requirements: requirements,
|
75
75
|
latest_resolvable_version: preferred_resolvable_version&.to_s,
|
76
76
|
update_strategy: requirements_update_strategy,
|
77
|
-
has_lockfile: !(pipfile_lock || poetry_lock
|
77
|
+
has_lockfile: !(pipfile_lock || poetry_lock).nil?
|
78
78
|
).updated_requirements
|
79
79
|
end
|
80
80
|
|
@@ -143,7 +143,7 @@ module Dependabot
|
|
143
143
|
|
144
144
|
def subdependency_resolver
|
145
145
|
return :pipenv if pipfile_lock
|
146
|
-
return :poetry if poetry_lock
|
146
|
+
return :poetry if poetry_lock
|
147
147
|
return :pip_compile if pip_compile_files.any?
|
148
148
|
|
149
149
|
raise "Claimed to be a sub-dependency, but no lockfile exists!"
|
@@ -257,7 +257,7 @@ module Dependabot
|
|
257
257
|
end
|
258
258
|
|
259
259
|
def library?
|
260
|
-
return unless updating_pyproject?
|
260
|
+
return false unless updating_pyproject?
|
261
261
|
|
262
262
|
# Hit PyPi and check whether there are details for a library with a
|
263
263
|
# matching name and description
|
@@ -315,10 +315,6 @@ module Dependabot
|
|
315
315
|
dependency_files.find { |f| f.name == "pyproject.toml" }
|
316
316
|
end
|
317
317
|
|
318
|
-
def pyproject_lock
|
319
|
-
dependency_files.find { |f| f.name == "pyproject.lock" }
|
320
|
-
end
|
321
|
-
|
322
318
|
def poetry_lock
|
323
319
|
dependency_files.find { |f| f.name == "poetry.lock" }
|
324
320
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-python
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.228.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-08-
|
11
|
+
date: 2023-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dependabot-common
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.228.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.228.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: debug
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,28 +114,28 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 1.
|
117
|
+
version: 1.56.0
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 1.
|
124
|
+
version: 1.56.0
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: rubocop-performance
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 1.
|
131
|
+
version: 1.19.0
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 1.
|
138
|
+
version: 1.19.0
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: stackprof
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -210,11 +210,11 @@ files:
|
|
210
210
|
- lib/dependabot/python/file_updater/requirement_file_updater.rb
|
211
211
|
- lib/dependabot/python/file_updater/requirement_replacer.rb
|
212
212
|
- lib/dependabot/python/file_updater/setup_file_sanitizer.rb
|
213
|
+
- lib/dependabot/python/helpers.rb
|
213
214
|
- lib/dependabot/python/language_version_manager.rb
|
214
215
|
- lib/dependabot/python/metadata_finder.rb
|
215
216
|
- lib/dependabot/python/name_normaliser.rb
|
216
217
|
- lib/dependabot/python/native_helpers.rb
|
217
|
-
- lib/dependabot/python/python_versions.rb
|
218
218
|
- lib/dependabot/python/requirement.rb
|
219
219
|
- lib/dependabot/python/requirement_parser.rb
|
220
220
|
- lib/dependabot/python/update_checker.rb
|
@@ -231,7 +231,7 @@ licenses:
|
|
231
231
|
- Nonstandard
|
232
232
|
metadata:
|
233
233
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
234
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
234
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.228.0
|
235
235
|
post_install_message:
|
236
236
|
rdoc_options: []
|
237
237
|
require_paths:
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dependabot
|
4
|
-
module Python
|
5
|
-
module PythonVersions
|
6
|
-
PRE_INSTALLED_PYTHON_VERSIONS = %w(
|
7
|
-
3.11.4
|
8
|
-
).freeze
|
9
|
-
|
10
|
-
# Due to an OpenSSL issue we can only install the following versions in
|
11
|
-
# the Dependabot container.
|
12
|
-
# NOTE: When adding one version, always doublecheck for additional releases: https://www.python.org/downloads/
|
13
|
-
#
|
14
|
-
# WARNING: 3.9.3 is purposefully omitted as it was recalled: https://www.python.org/downloads/release/python-393/
|
15
|
-
SUPPORTED_VERSIONS = %w(
|
16
|
-
3.11.4 3.11.3 3.11.2 3.11.1 3.11.0
|
17
|
-
3.10.12 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.17 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.17 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.17 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
|
-
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
|
-
3.5.10 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3
|
23
|
-
).freeze
|
24
|
-
|
25
|
-
# This list gets iterated through to find a valid version, so we have
|
26
|
-
# the pre-installed versions listed first.
|
27
|
-
SUPPORTED_VERSIONS_TO_ITERATE =
|
28
|
-
[
|
29
|
-
*PRE_INSTALLED_PYTHON_VERSIONS,
|
30
|
-
*SUPPORTED_VERSIONS
|
31
|
-
].freeze
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|