dependabot-python 0.212.0 → 0.213.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 +1 -6
- data/helpers/lib/parser.py +52 -0
- data/helpers/requirements.txt +3 -3
- data/helpers/run.py +2 -0
- data/lib/dependabot/python/file_fetcher.rb +21 -12
- data/lib/dependabot/python/file_parser/{poetry_files_parser.rb → pyproject_files_parser.rb} +83 -2
- data/lib/dependabot/python/file_parser/setup_file_parser.rb +4 -4
- data/lib/dependabot/python/file_parser.rb +5 -29
- data/lib/dependabot/python/file_updater/pip_compile_file_updater.rb +5 -20
- data/lib/dependabot/python/file_updater/pipfile_file_updater.rb +1 -5
- data/lib/dependabot/python/file_updater/poetry_file_updater.rb +7 -6
- data/lib/dependabot/python/file_updater/pyproject_preparer.rb +1 -1
- data/lib/dependabot/python/file_updater.rb +14 -1
- data/lib/dependabot/python/helpers.rb +20 -0
- data/lib/dependabot/python/metadata_finder.rb +2 -0
- data/lib/dependabot/python/python_versions.rb +5 -5
- data/lib/dependabot/python/requirement.rb +7 -4
- data/lib/dependabot/python/requirement_parser.rb +20 -23
- data/lib/dependabot/python/update_checker/index_finder.rb +1 -1
- data/lib/dependabot/python/update_checker/pip_compile_version_resolver.rb +17 -19
- data/lib/dependabot/python/update_checker/pipenv_version_resolver.rb +7 -16
- data/lib/dependabot/python/update_checker/poetry_version_resolver.rb +13 -11
- data/lib/dependabot/python/update_checker/requirements_updater.rb +17 -4
- data/lib/dependabot/python/update_checker.rb +82 -25
- data/lib/dependabot/python/version.rb +2 -2
- metadata +15 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6cb23890c79504e40e7e4962485003c76c07179574ac89b210b6529d15d2c216
|
4
|
+
data.tar.gz: b96523f9cf991cbffc38fc2831221c43450c74ef560e8e80ff2d2bbf73c889c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5beeac4ec63193ce095e6a5d7223c11e4e9c2ace55b3ef5c94f0011d8cb0c70fc7b364108b68cd68f656a5ed79d712b64eecbb75998714325a0f3b101169592c
|
7
|
+
data.tar.gz: 17ec5483c750fe4bc35490feebf418a8bd7eaf0eb2d14e2bcfc811e06f94c02f69eca71bafb589cb2d51b8a73155d3d358b97fcc6125a8fb7229b54f06a42fbe
|
data/helpers/build
CHANGED
@@ -18,9 +18,4 @@ cp -r \
|
|
18
18
|
"$install_dir"
|
19
19
|
|
20
20
|
cd "$install_dir"
|
21
|
-
PYENV_VERSION=3.10.
|
22
|
-
|
23
|
-
# Workaround of https://github.com/python-poetry/poetry/issues/3010
|
24
|
-
# By default poetry config file is stored under ~/.config/pypoetry
|
25
|
-
# and is not bound to any specific Python version
|
26
|
-
PYENV_VERSION=3.10.5 pyenv exec poetry config experimental.new-installer false
|
21
|
+
PYENV_VERSION=3.10.7 pyenv exec pip --disable-pip-version-check install --use-pep517 -r "requirements.txt"
|
data/helpers/lib/parser.py
CHANGED
@@ -11,11 +11,63 @@ from pip._internal.req.constructors import (
|
|
11
11
|
install_req_from_line,
|
12
12
|
install_req_from_parsed_requirement,
|
13
13
|
)
|
14
|
+
|
15
|
+
from packaging.requirements import InvalidRequirement, Requirement
|
16
|
+
import toml
|
17
|
+
|
14
18
|
# Inspired by pips internal check:
|
15
19
|
# https://github.com/pypa/pip/blob/0bb3ac87f5bb149bd75cceac000844128b574385/src/pip/_internal/req/req_file.py#L35
|
16
20
|
COMMENT_RE = re.compile(r'(^|\s+)#.*$')
|
17
21
|
|
18
22
|
|
23
|
+
def parse_pep621_dependencies(pyproject_path):
|
24
|
+
project_toml = toml.load(pyproject_path)['project']
|
25
|
+
|
26
|
+
def parse_toml_section_pep621_dependencies(pyproject_path, dependencies):
|
27
|
+
requirement_packages = []
|
28
|
+
|
29
|
+
def version_from_req(specifier_set):
|
30
|
+
if (len(specifier_set) == 1 and
|
31
|
+
next(iter(specifier_set)).operator in {"==", "==="}):
|
32
|
+
return next(iter(specifier_set)).version
|
33
|
+
|
34
|
+
for dependency in dependencies:
|
35
|
+
try:
|
36
|
+
req = Requirement(dependency)
|
37
|
+
except InvalidRequirement as e:
|
38
|
+
print(json.dumps({"error": repr(e)}))
|
39
|
+
exit(1)
|
40
|
+
else:
|
41
|
+
requirement_packages.append({
|
42
|
+
"name": req.name,
|
43
|
+
"version": version_from_req(req.specifier),
|
44
|
+
"markers": str(req.marker) or None,
|
45
|
+
"file": pyproject_path,
|
46
|
+
"requirement": str(req.specifier),
|
47
|
+
"extras": sorted(list(req.extras))
|
48
|
+
})
|
49
|
+
|
50
|
+
return requirement_packages
|
51
|
+
|
52
|
+
dependencies = parse_toml_section_pep621_dependencies(
|
53
|
+
pyproject_path,
|
54
|
+
project_toml['dependencies']
|
55
|
+
)
|
56
|
+
|
57
|
+
if 'optional-dependencies' in project_toml:
|
58
|
+
optional_dependencies_toml = project_toml['optional-dependencies']
|
59
|
+
|
60
|
+
for group in optional_dependencies_toml:
|
61
|
+
group_dependencies = parse_toml_section_pep621_dependencies(
|
62
|
+
pyproject_path,
|
63
|
+
optional_dependencies_toml[group]
|
64
|
+
)
|
65
|
+
|
66
|
+
dependencies.extend(group_dependencies)
|
67
|
+
|
68
|
+
return json.dumps({"result": dependencies})
|
69
|
+
|
70
|
+
|
19
71
|
def parse_requirements(directory):
|
20
72
|
# Parse the requirements.txt
|
21
73
|
requirement_packages = []
|
data/helpers/requirements.txt
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
pip>=21.3.1,<22.
|
2
|
-
pip-tools>=6.4.0,<6.
|
1
|
+
pip>=21.3.1,<22.4.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.9.1 # Range maintains py36 support TODO: Review python 3.6 support in April 2023 (eol ubuntu 18.04)
|
3
3
|
flake8==5.0.4
|
4
4
|
hashin==0.17.0
|
5
5
|
pipenv==2022.4.8
|
6
6
|
pipfile==0.0.2
|
7
|
-
poetry>=1.1.15
|
7
|
+
poetry>=1.1.15,<1.3.0
|
8
8
|
wheel==0.37.1
|
9
9
|
|
10
10
|
# Some dependencies will only install if Cython is present
|
data/helpers/run.py
CHANGED
@@ -10,6 +10,8 @@ if __name__ == "__main__":
|
|
10
10
|
print(parser.parse_requirements(args["args"][0]))
|
11
11
|
elif args["function"] == "parse_setup":
|
12
12
|
print(parser.parse_setup(args["args"][0]))
|
13
|
+
elif args["function"] == "parse_pep621_dependencies":
|
14
|
+
print(parser.parse_pep621_dependencies(args["args"][0]))
|
13
15
|
elif args["function"] == "get_dependency_hash":
|
14
16
|
print(hasher.get_dependency_hash(*args["args"]))
|
15
17
|
elif args["function"] == "get_pipfile_hash":
|
@@ -5,15 +5,15 @@ require "toml-rb"
|
|
5
5
|
require "dependabot/file_fetchers"
|
6
6
|
require "dependabot/file_fetchers/base"
|
7
7
|
require "dependabot/python/requirement_parser"
|
8
|
-
require "dependabot/python/file_parser/
|
8
|
+
require "dependabot/python/file_parser/pyproject_files_parser"
|
9
9
|
require "dependabot/errors"
|
10
10
|
|
11
11
|
module Dependabot
|
12
12
|
module Python
|
13
13
|
class FileFetcher < Dependabot::FileFetchers::Base
|
14
|
-
CHILD_REQUIREMENT_REGEX = /^-r\s?(?<path>.*\.(?:txt|in))
|
15
|
-
CONSTRAINT_REGEX = /^-c\s?(?<path>.*\.(?:txt|in))
|
16
|
-
DEPENDENCY_TYPES = %w(packages dev-packages)
|
14
|
+
CHILD_REQUIREMENT_REGEX = /^-r\s?(?<path>.*\.(?:txt|in))/
|
15
|
+
CONSTRAINT_REGEX = /^-c\s?(?<path>.*\.(?:txt|in))/
|
16
|
+
DEPENDENCY_TYPES = %w(packages dev-packages)
|
17
17
|
|
18
18
|
def self.required_files_in?(filenames)
|
19
19
|
return true if filenames.any? { |name| name.end_with?(".txt", ".in") }
|
@@ -24,7 +24,7 @@ module Dependabot
|
|
24
24
|
# If this repo is using a Pipfile return true
|
25
25
|
return true if filenames.include?("Pipfile")
|
26
26
|
|
27
|
-
# If this repo is using
|
27
|
+
# If this repo is using pyproject.toml return true
|
28
28
|
return true if filenames.include?("pyproject.toml")
|
29
29
|
|
30
30
|
return true if filenames.include?("setup.py")
|
@@ -69,7 +69,7 @@ module Dependabot
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def pyproject_files
|
72
|
-
[pyproject, pyproject_lock, poetry_lock].compact
|
72
|
+
[pyproject, pyproject_lock, poetry_lock, pdm_lock].compact
|
73
73
|
end
|
74
74
|
|
75
75
|
def requirement_files
|
@@ -81,7 +81,12 @@ module Dependabot
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def check_required_files_present
|
84
|
-
return if requirements_txt_files.any? ||
|
84
|
+
return if requirements_txt_files.any? ||
|
85
|
+
requirements_in_files.any? ||
|
86
|
+
setup_file ||
|
87
|
+
setup_cfg_file ||
|
88
|
+
pipfile ||
|
89
|
+
pyproject
|
85
90
|
|
86
91
|
path = Pathname.new(File.join(directory, "requirements.txt")).
|
87
92
|
cleanpath.to_path
|
@@ -136,6 +141,10 @@ module Dependabot
|
|
136
141
|
@poetry_lock ||= fetch_file_if_present("poetry.lock")
|
137
142
|
end
|
138
143
|
|
144
|
+
def pdm_lock
|
145
|
+
@pdm_lock ||= fetch_file_if_present("pdm.lock")
|
146
|
+
end
|
147
|
+
|
139
148
|
def requirements_txt_files
|
140
149
|
req_txt_and_in_files.select { |f| f.name.end_with?(".txt") }
|
141
150
|
end
|
@@ -169,7 +178,7 @@ module Dependabot
|
|
169
178
|
repo_contents.
|
170
179
|
select { |f| f.type == "file" }.
|
171
180
|
select { |f| f.name.end_with?(".txt", ".in") }.
|
172
|
-
reject { |f| f.size >
|
181
|
+
reject { |f| f.size > 500_000 }.
|
173
182
|
map { |f| fetch_file_from_host(f.name) }.
|
174
183
|
select { |f| requirements_file?(f) }.
|
175
184
|
each { |f| @req_txt_and_in_files << f }
|
@@ -189,7 +198,7 @@ module Dependabot
|
|
189
198
|
repo_contents(dir: relative_reqs_dir).
|
190
199
|
select { |f| f.type == "file" }.
|
191
200
|
select { |f| f.name.end_with?(".txt", ".in") }.
|
192
|
-
reject { |f| f.size >
|
201
|
+
reject { |f| f.size > 500_000 }.
|
193
202
|
map { |f| fetch_file_from_host("#{relative_reqs_dir}/#{f.name}") }.
|
194
203
|
select { |f| requirements_file?(f) }
|
195
204
|
end
|
@@ -291,8 +300,8 @@ module Dependabot
|
|
291
300
|
fetch_submodules: true
|
292
301
|
).tap { |f| f.support_file = true }
|
293
302
|
rescue Dependabot::DependencyFileNotFound
|
294
|
-
# For
|
295
|
-
# given path instead of a setup.py. We do not require a
|
303
|
+
# For projects with pyproject.toml attempt to fetch a pyproject.toml
|
304
|
+
# at the given path instead of a setup.py. We do not require a
|
296
305
|
# setup.py to be present, so if none can be found, simply return
|
297
306
|
return [] unless allow_pyproject
|
298
307
|
|
@@ -390,7 +399,7 @@ module Dependabot
|
|
390
399
|
return [] unless pyproject
|
391
400
|
|
392
401
|
paths = []
|
393
|
-
Dependabot::Python::FileParser::
|
402
|
+
Dependabot::Python::FileParser::PyprojectFilesParser::POETRY_DEPENDENCY_TYPES.each do |dep_type|
|
394
403
|
next unless parsed_pyproject.dig("tool", "poetry", dep_type)
|
395
404
|
|
396
405
|
parsed_pyproject.dig("tool", "poetry", dep_type).each do |_, req|
|
@@ -12,7 +12,7 @@ require "dependabot/python/name_normaliser"
|
|
12
12
|
module Dependabot
|
13
13
|
module Python
|
14
14
|
class FileParser
|
15
|
-
class
|
15
|
+
class PyprojectFilesParser
|
16
16
|
POETRY_DEPENDENCY_TYPES = %w(dependencies dev-dependencies).freeze
|
17
17
|
|
18
18
|
# https://python-poetry.org/docs/dependency-specification/
|
@@ -25,7 +25,7 @@ module Dependabot
|
|
25
25
|
def dependency_set
|
26
26
|
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
27
27
|
|
28
|
-
dependency_set += pyproject_dependencies
|
28
|
+
dependency_set += pyproject_dependencies if using_poetry? || using_pep621?
|
29
29
|
dependency_set += lockfile_dependencies if lockfile
|
30
30
|
|
31
31
|
dependency_set
|
@@ -36,6 +36,14 @@ module Dependabot
|
|
36
36
|
attr_reader :dependency_files
|
37
37
|
|
38
38
|
def pyproject_dependencies
|
39
|
+
if using_poetry?
|
40
|
+
poetry_dependencies
|
41
|
+
else
|
42
|
+
pep621_dependencies
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def poetry_dependencies
|
39
47
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
40
48
|
|
41
49
|
POETRY_DEPENDENCY_TYPES.each do |type|
|
@@ -59,6 +67,44 @@ module Dependabot
|
|
59
67
|
dependencies
|
60
68
|
end
|
61
69
|
|
70
|
+
def pep621_dependencies
|
71
|
+
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
72
|
+
|
73
|
+
# PDM is not yet supported, so we want to ignore it for now because in
|
74
|
+
# the current state of things, going on would result in updating
|
75
|
+
# pyproject.toml but leaving pdm.lock out of sync, which is
|
76
|
+
# undesirable. Leave PDM alone until properly supported
|
77
|
+
return dependencies if using_pdm?
|
78
|
+
|
79
|
+
parsed_pep621_dependencies.each do |dep|
|
80
|
+
# If a requirement has a `<` or `<=` marker then updating it is
|
81
|
+
# probably blocked. Ignore it.
|
82
|
+
next if dep["markers"].include?("<")
|
83
|
+
|
84
|
+
# If no requirement, don't add it
|
85
|
+
next if dep["requirement"].empty?
|
86
|
+
|
87
|
+
dependencies <<
|
88
|
+
Dependency.new(
|
89
|
+
name: normalised_name(dep["name"], dep["extras"]),
|
90
|
+
version: dep["version"]&.include?("*") ? nil : dep["version"],
|
91
|
+
requirements: [{
|
92
|
+
requirement: dep["requirement"],
|
93
|
+
file: Pathname.new(dep["file"]).cleanpath.to_path,
|
94
|
+
source: nil,
|
95
|
+
groups: [dep["requirement_type"]]
|
96
|
+
}],
|
97
|
+
package_manager: "pip"
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
dependencies
|
102
|
+
end
|
103
|
+
|
104
|
+
def normalised_name(name, extras)
|
105
|
+
NameNormaliser.normalise_including_extras(name, extras)
|
106
|
+
end
|
107
|
+
|
62
108
|
# @param req can be an Array, Hash or String that represents the constraints for a dependency
|
63
109
|
def parse_requirements_from(req, type)
|
64
110
|
[req].flatten.compact.filter_map do |requirement|
|
@@ -75,6 +121,18 @@ module Dependabot
|
|
75
121
|
end
|
76
122
|
end
|
77
123
|
|
124
|
+
def using_poetry?
|
125
|
+
!parsed_pyproject.dig("tool", "poetry").nil?
|
126
|
+
end
|
127
|
+
|
128
|
+
def using_pep621?
|
129
|
+
!parsed_pyproject.dig("project", "dependencies").nil?
|
130
|
+
end
|
131
|
+
|
132
|
+
def using_pdm?
|
133
|
+
using_pep621? && pdm_lock
|
134
|
+
end
|
135
|
+
|
78
136
|
# Create a DependencySet where each element has no requirement. Any
|
79
137
|
# requirements will be added when combining the DependencySet with
|
80
138
|
# other DependencySets.
|
@@ -146,6 +204,24 @@ module Dependabot
|
|
146
204
|
poetry_lock || pyproject_lock
|
147
205
|
end
|
148
206
|
|
207
|
+
def parsed_pep621_dependencies
|
208
|
+
SharedHelpers.in_a_temporary_directory do
|
209
|
+
write_temporary_pyproject
|
210
|
+
|
211
|
+
SharedHelpers.run_helper_subprocess(
|
212
|
+
command: "pyenv exec python #{NativeHelpers.python_helper_path}",
|
213
|
+
function: "parse_pep621_dependencies",
|
214
|
+
args: [pyproject.name]
|
215
|
+
)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def write_temporary_pyproject
|
220
|
+
path = pyproject.name
|
221
|
+
FileUtils.mkdir_p(Pathname.new(path).dirname)
|
222
|
+
File.write(path, pyproject.content)
|
223
|
+
end
|
224
|
+
|
149
225
|
def parsed_lockfile
|
150
226
|
return parsed_poetry_lock if poetry_lock
|
151
227
|
return parsed_pyproject_lock if pyproject_lock
|
@@ -160,6 +236,11 @@ module Dependabot
|
|
160
236
|
@poetry_lock ||=
|
161
237
|
dependency_files.find { |f| f.name == "poetry.lock" }
|
162
238
|
end
|
239
|
+
|
240
|
+
def pdm_lock
|
241
|
+
@pdm_lock ||=
|
242
|
+
dependency_files.find { |f| f.name == "pdm.lock" }
|
243
|
+
end
|
163
244
|
end
|
164
245
|
end
|
165
246
|
end
|
@@ -12,10 +12,10 @@ module Dependabot
|
|
12
12
|
module Python
|
13
13
|
class FileParser
|
14
14
|
class SetupFileParser
|
15
|
-
INSTALL_REQUIRES_REGEX = /install_requires\s*=\s*\[/m
|
16
|
-
SETUP_REQUIRES_REGEX = /setup_requires\s*=\s*\[/m
|
17
|
-
TESTS_REQUIRE_REGEX = /tests_require\s*=\s*\[/m
|
18
|
-
EXTRAS_REQUIRE_REGEX = /extras_require\s*=\s*\{/m
|
15
|
+
INSTALL_REQUIRES_REGEX = /install_requires\s*=\s*\[/m
|
16
|
+
SETUP_REQUIRES_REGEX = /setup_requires\s*=\s*\[/m
|
17
|
+
TESTS_REQUIRE_REGEX = /tests_require\s*=\s*\[/m
|
18
|
+
EXTRAS_REQUIRE_REGEX = /extras_require\s*=\s*\{/m
|
19
19
|
|
20
20
|
CLOSING_BRACKET = { "[" => "]", "{" => "}" }.freeze
|
21
21
|
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "toml-rb"
|
4
3
|
require "dependabot/dependency"
|
5
4
|
require "dependabot/file_parsers"
|
6
5
|
require "dependabot/file_parsers/base"
|
@@ -15,11 +14,9 @@ module Dependabot
|
|
15
14
|
module Python
|
16
15
|
class FileParser < Dependabot::FileParsers::Base
|
17
16
|
require_relative "file_parser/pipfile_files_parser"
|
18
|
-
require_relative "file_parser/
|
17
|
+
require_relative "file_parser/pyproject_files_parser"
|
19
18
|
require_relative "file_parser/setup_file_parser"
|
20
19
|
|
21
|
-
POETRY_DEPENDENCY_TYPES =
|
22
|
-
%w(tool.poetry.dependencies tool.poetry.dev-dependencies).freeze
|
23
20
|
DEPENDENCY_GROUP_KEYS = [
|
24
21
|
{
|
25
22
|
pipfile: "packages",
|
@@ -42,7 +39,7 @@ module Dependabot
|
|
42
39
|
dependency_set = DependencySet.new
|
43
40
|
|
44
41
|
dependency_set += pipenv_dependencies if pipfile
|
45
|
-
dependency_set +=
|
42
|
+
dependency_set += pyproject_file_dependencies if pyproject
|
46
43
|
dependency_set += requirement_dependencies if requirement_files.any?
|
47
44
|
dependency_set += setup_file_dependencies if setup_file || setup_cfg_file
|
48
45
|
|
@@ -62,9 +59,9 @@ module Dependabot
|
|
62
59
|
dependency_set
|
63
60
|
end
|
64
61
|
|
65
|
-
def
|
66
|
-
@
|
67
|
-
|
62
|
+
def pyproject_file_dependencies
|
63
|
+
@pyproject_file_dependencies ||=
|
64
|
+
PyprojectFilesParser.
|
68
65
|
new(dependency_files: dependency_files).
|
69
66
|
dependency_set
|
70
67
|
end
|
@@ -105,18 +102,6 @@ module Dependabot
|
|
105
102
|
end
|
106
103
|
end
|
107
104
|
|
108
|
-
def included_in_pipenv_deps?(dep_name)
|
109
|
-
return false unless pipfile
|
110
|
-
|
111
|
-
pipenv_dependencies.dependencies.map(&:name).include?(dep_name)
|
112
|
-
end
|
113
|
-
|
114
|
-
def included_in_poetry_deps?(dep_name)
|
115
|
-
return false unless using_poetry?
|
116
|
-
|
117
|
-
poetry_dependencies.dependencies.map(&:name).include?(dep_name)
|
118
|
-
end
|
119
|
-
|
120
105
|
def blocking_marker?(dep)
|
121
106
|
return false if dep["markers"] == "None"
|
122
107
|
return true if dep["markers"].include?("<")
|
@@ -215,15 +200,6 @@ module Dependabot
|
|
215
200
|
@pipfile_lock ||= get_original_file("Pipfile.lock")
|
216
201
|
end
|
217
202
|
|
218
|
-
def using_poetry?
|
219
|
-
return false unless pyproject
|
220
|
-
return true if poetry_lock || pyproject_lock
|
221
|
-
|
222
|
-
!TomlRB.parse(pyproject.content).dig("tool", "poetry").nil?
|
223
|
-
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
224
|
-
raise Dependabot::DependencyFileNotParseable, pyproject.path
|
225
|
-
end
|
226
|
-
|
227
203
|
def output_file_regex(filename)
|
228
204
|
"--output-file[=\s]+#{Regexp.escape(filename)}(?:\s|$)"
|
229
205
|
end
|
@@ -7,6 +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/helpers"
|
10
11
|
require "dependabot/python/native_helpers"
|
11
12
|
require "dependabot/python/python_versions"
|
12
13
|
require "dependabot/python/name_normaliser"
|
@@ -22,10 +23,9 @@ module Dependabot
|
|
22
23
|
require_relative "setup_file_sanitizer"
|
23
24
|
|
24
25
|
UNSAFE_PACKAGES = %w(setuptools distribute pip).freeze
|
25
|
-
INCOMPATIBLE_VERSIONS_REGEX = /There are incompatible versions in the resolved dependencies:.*\z/m
|
26
|
-
WARNINGS = /\s*# WARNING:.*\Z/m
|
27
|
-
UNSAFE_NOTE =
|
28
|
-
/\s*# The following packages are considered to be unsafe.*\Z/m.freeze
|
26
|
+
INCOMPATIBLE_VERSIONS_REGEX = /There are incompatible versions in the resolved dependencies:.*\z/m
|
27
|
+
WARNINGS = /\s*# WARNING:.*\Z/m
|
28
|
+
UNSAFE_NOTE = /\s*# The following packages are considered to be unsafe.*\Z/m
|
29
29
|
|
30
30
|
attr_reader :dependencies, :dependency_files, :credentials
|
31
31
|
|
@@ -66,7 +66,7 @@ module Dependabot
|
|
66
66
|
def compile_new_requirement_files
|
67
67
|
SharedHelpers.in_a_temporary_directory do
|
68
68
|
write_updated_dependency_files
|
69
|
-
install_required_python
|
69
|
+
Helpers.install_required_python(python_version)
|
70
70
|
|
71
71
|
filenames_to_compile.each do |filename|
|
72
72
|
# Shell out to pip-compile, generate a new set of requirements.
|
@@ -81,12 +81,6 @@ module Dependabot
|
|
81
81
|
"#{SharedHelpers.escape_command(version_part)}",
|
82
82
|
allow_unsafe_shell_command: true
|
83
83
|
)
|
84
|
-
# Run pip-compile a second time, without an update argument, to
|
85
|
-
# ensure it resets the right comments.
|
86
|
-
run_pip_compile_command(
|
87
|
-
"pyenv exec pip-compile #{pip_compile_options(filename)} " \
|
88
|
-
"#{filename}"
|
89
|
-
)
|
90
84
|
end
|
91
85
|
|
92
86
|
# Remove any .python-version file before parsing the reqs
|
@@ -219,15 +213,6 @@ module Dependabot
|
|
219
213
|
end
|
220
214
|
end
|
221
215
|
|
222
|
-
def install_required_python
|
223
|
-
return if run_command("pyenv versions").include?("#{python_version}\n")
|
224
|
-
|
225
|
-
run_command("pyenv install -s #{python_version}")
|
226
|
-
run_command("pyenv exec pip install --upgrade pip")
|
227
|
-
run_command("pyenv exec pip install -r " \
|
228
|
-
"#{NativeHelpers.python_requirements_path}")
|
229
|
-
end
|
230
|
-
|
231
216
|
def sanitized_setup_file_content(file)
|
232
217
|
@sanitized_setup_file_content ||= {}
|
233
218
|
return @sanitized_setup_file_content[file.name] if @sanitized_setup_file_content[file.name]
|
@@ -302,11 +302,7 @@ module Dependabot
|
|
302
302
|
nil
|
303
303
|
end
|
304
304
|
|
305
|
-
|
306
|
-
|
307
|
-
requirements_path = NativeHelpers.python_requirements_path
|
308
|
-
run_command("pyenv install -s #{python_version}")
|
309
|
-
run_command("pyenv exec pip install -r #{requirements_path}")
|
305
|
+
Helpers.install_required_python(python_version)
|
310
306
|
end
|
311
307
|
|
312
308
|
def sanitized_setup_file_content(file)
|
@@ -4,6 +4,7 @@ require "toml-rb"
|
|
4
4
|
require "open3"
|
5
5
|
require "dependabot/dependency"
|
6
6
|
require "dependabot/shared_helpers"
|
7
|
+
require "dependabot/python/helpers"
|
7
8
|
require "dependabot/python/version"
|
8
9
|
require "dependabot/python/requirement"
|
9
10
|
require "dependabot/python/python_versions"
|
@@ -131,7 +132,7 @@ module Dependabot
|
|
131
132
|
end
|
132
133
|
|
133
134
|
def lock_declaration_to_new_version!(poetry_object, dep)
|
134
|
-
Dependabot::Python::FileParser::
|
135
|
+
Dependabot::Python::FileParser::PyprojectFilesParser::POETRY_DEPENDENCY_TYPES.each do |type|
|
135
136
|
names = poetry_object[type]&.keys || []
|
136
137
|
pkg_name = names.find { |nm| normalise(nm) == dep.name }
|
137
138
|
next unless pkg_name
|
@@ -170,11 +171,11 @@ module Dependabot
|
|
170
171
|
write_temporary_dependency_files(pyproject_content)
|
171
172
|
add_auth_env_vars
|
172
173
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
174
|
+
Helpers.install_required_python(python_version)
|
175
|
+
|
176
|
+
# use system git instead of the pure Python dulwich
|
177
|
+
unless python_version&.start_with?("3.6")
|
178
|
+
run_poetry_command("pyenv exec poetry config experimental.system-git-client true")
|
178
179
|
end
|
179
180
|
|
180
181
|
run_poetry_command(poetry_update_command)
|
@@ -52,7 +52,7 @@ module Dependabot
|
|
52
52
|
poetry_object = pyproject_object["tool"]["poetry"]
|
53
53
|
excluded_names = dependencies.map(&:name) + ["python"]
|
54
54
|
|
55
|
-
Dependabot::Python::FileParser::
|
55
|
+
Dependabot::Python::FileParser::PyprojectFilesParser::POETRY_DEPENDENCY_TYPES.each do |key|
|
56
56
|
next unless poetry_object[key]
|
57
57
|
|
58
58
|
source_types = %w(directory file url)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "toml-rb"
|
3
4
|
require "dependabot/file_updaters"
|
4
5
|
require "dependabot/file_updaters/base"
|
5
6
|
require "dependabot/shared_helpers"
|
@@ -61,7 +62,13 @@ module Dependabot
|
|
61
62
|
# Otherwise, this is a top-level dependency, and we can figure out
|
62
63
|
# which resolver to use based on the filename of its requirements
|
63
64
|
return :pipfile if changed_req_files.any?("Pipfile")
|
64
|
-
|
65
|
+
|
66
|
+
if changed_req_files.any?("pyproject.toml")
|
67
|
+
return :poetry if poetry_based?
|
68
|
+
|
69
|
+
return :requirements
|
70
|
+
end
|
71
|
+
|
65
72
|
return :pip_compile if changed_req_files.any? { |f| f.end_with?(".in") }
|
66
73
|
|
67
74
|
:requirements
|
@@ -119,6 +126,12 @@ module Dependabot
|
|
119
126
|
raise "Missing required files!"
|
120
127
|
end
|
121
128
|
|
129
|
+
def poetry_based?
|
130
|
+
return false unless pyproject
|
131
|
+
|
132
|
+
!TomlRB.parse(pyproject.content).dig("tool", "poetry").nil?
|
133
|
+
end
|
134
|
+
|
122
135
|
def pipfile
|
123
136
|
@pipfile ||= get_original_file("Pipfile")
|
124
137
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/logger"
|
4
|
+
|
5
|
+
module Dependabot
|
6
|
+
module Python
|
7
|
+
module Helpers
|
8
|
+
def self.install_required_python(python_version)
|
9
|
+
# The leading space is important in the version check
|
10
|
+
return if SharedHelpers.run_shell_command("pyenv versions").include?(" #{python_version}")
|
11
|
+
|
12
|
+
Dependabot.logger.info("Installing required Python #{python_version}.")
|
13
|
+
SharedHelpers.run_shell_command("pyenv install -s #{python_version}")
|
14
|
+
SharedHelpers.run_shell_command("pyenv exec pip install --upgrade pip")
|
15
|
+
SharedHelpers.run_shell_command("pyenv exec pip install -r" \
|
16
|
+
"#{NativeHelpers.python_requirements_path}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -4,16 +4,16 @@ module Dependabot
|
|
4
4
|
module Python
|
5
5
|
module PythonVersions
|
6
6
|
PRE_INSTALLED_PYTHON_VERSIONS = %w(
|
7
|
-
3.10.
|
7
|
+
3.10.7
|
8
8
|
).freeze
|
9
9
|
|
10
10
|
# Due to an OpenSSL issue we can only install the following versions in
|
11
11
|
# the Dependabot container.
|
12
12
|
SUPPORTED_VERSIONS = %w(
|
13
|
-
3.10.5 3.10.4 3.10.3 3.10.2 3.10.1 3.10.0
|
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
|
15
|
-
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
|
16
|
-
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
|
13
|
+
3.10.7 3.10.6 3.10.5 3.10.4 3.10.3 3.10.2 3.10.1 3.10.0
|
14
|
+
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
|
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
|
16
|
+
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
|
17
17
|
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
|
18
18
|
3.6.2 3.6.1 3.6.0 3.5.10 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3
|
19
19
|
).freeze
|