dependabot-python 0.392.0 → 0.394.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 +3 -3
- data/lib/dependabot/python/file_parser/pep_dependency.rb +53 -0
- data/lib/dependabot/python/file_parser/poetry_lock.rb +95 -0
- data/lib/dependabot/python/file_parser/pyproject_document.rb +242 -0
- data/lib/dependabot/python/file_parser/pyproject_files_parser.rb +134 -128
- data/lib/dependabot/python/file_parser/setup_file_parser.rb +26 -8
- data/lib/dependabot/python/file_parser.rb +3 -0
- data/lib/dependabot/python/file_updater/pipfile_file_updater.rb +13 -4
- data/lib/dependabot/python/file_updater/poetry_file_updater.rb +13 -2
- data/lib/dependabot/python/package/package_details_fetcher.rb +81 -35
- data/lib/dependabot/python/package/package_registry_finder.rb +11 -4
- data/lib/dependabot/python/package/simple_api_parser.rb +91 -0
- data/lib/dependabot/python/shared_file_fetcher.rb +1 -2
- data/lib/dependabot/python/update_checker/latest_version_finder.rb +16 -0
- data/lib/dependabot/python/update_checker.rb +4 -4
- metadata +10 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "toml-rb"
|
|
@@ -25,7 +25,8 @@ module Dependabot
|
|
|
25
25
|
sig { params(dependency_files: T::Array[Dependabot::DependencyFile]).void }
|
|
26
26
|
def initialize(dependency_files:)
|
|
27
27
|
@dependency_files = dependency_files
|
|
28
|
-
@
|
|
28
|
+
@pyproject_document = T.let(nil, T.nilable(PyprojectDocument))
|
|
29
|
+
@poetry_lock_document = T.let(nil, T.nilable(PoetryLock))
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
|
@@ -63,16 +64,11 @@ module Dependabot
|
|
|
63
64
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
|
64
65
|
|
|
65
66
|
POETRY_DEPENDENCY_TYPES.each do |type|
|
|
66
|
-
|
|
67
|
-
dependencies += parse_poetry_dependency_group(type, deps_hash)
|
|
67
|
+
dependencies += parse_poetry_dependency_group(type, pyproject_document.poetry_dependencies(type))
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
deps = group_spec["dependencies"]
|
|
73
|
-
next unless deps
|
|
74
|
-
|
|
75
|
-
dependencies += parse_poetry_dependency_group(group, deps)
|
|
70
|
+
pyproject_document.poetry_groups.each do |group, dependencies_by_name|
|
|
71
|
+
dependencies += parse_poetry_dependency_group(group, dependencies_by_name)
|
|
76
72
|
end
|
|
77
73
|
dependencies
|
|
78
74
|
end
|
|
@@ -92,17 +88,17 @@ module Dependabot
|
|
|
92
88
|
|
|
93
89
|
dependencies <<
|
|
94
90
|
Dependency.new(
|
|
95
|
-
name: normalise(dep
|
|
96
|
-
version: dep
|
|
91
|
+
name: normalise(dep.name),
|
|
92
|
+
version: dep.version&.include?("*") ? nil : dep.version,
|
|
97
93
|
requirements: [{
|
|
98
|
-
requirement: dep
|
|
99
|
-
file: Pathname.new(dep
|
|
94
|
+
requirement: dep.requirement,
|
|
95
|
+
file: Pathname.new(dep.file).cleanpath.to_path,
|
|
100
96
|
source: nil,
|
|
101
|
-
groups: [dep
|
|
97
|
+
groups: [dep.requirement_type].compact
|
|
102
98
|
}],
|
|
103
99
|
package_manager: "pip",
|
|
104
|
-
metadata: extras_metadata(dep
|
|
105
|
-
source_requirement: dep
|
|
100
|
+
metadata: extras_metadata(dep.extras).merge(
|
|
101
|
+
source_requirement: dep.source_requirement
|
|
106
102
|
).compact
|
|
107
103
|
)
|
|
108
104
|
end
|
|
@@ -113,17 +109,16 @@ module Dependabot
|
|
|
113
109
|
sig do
|
|
114
110
|
params(
|
|
115
111
|
type: String,
|
|
116
|
-
deps_hash:
|
|
112
|
+
deps_hash: PyprojectDocument::PoetryDependencyMap
|
|
117
113
|
).returns(Dependabot::FileParsers::Base::DependencySet)
|
|
118
114
|
end
|
|
119
115
|
def parse_poetry_dependency_group(type, deps_hash)
|
|
120
116
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
|
121
|
-
return dependencies if deps_hash.nil?
|
|
122
117
|
|
|
123
|
-
deps_hash.each do |name,
|
|
118
|
+
deps_hash.each do |name, requirements_data|
|
|
124
119
|
next if normalise(name) == "python"
|
|
125
120
|
|
|
126
|
-
requirements = parse_requirements_from(
|
|
121
|
+
requirements = parse_requirements_from(requirements_data, type)
|
|
127
122
|
next if requirements.empty?
|
|
128
123
|
|
|
129
124
|
dependencies << Dependency.new(
|
|
@@ -151,102 +146,108 @@ module Dependabot
|
|
|
151
146
|
{ extras: extras.join(",") }
|
|
152
147
|
end
|
|
153
148
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
[
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
{
|
|
180
|
-
requirement: requirement,
|
|
181
|
-
file: T.must(pyproject).name,
|
|
182
|
-
source: nil,
|
|
183
|
-
groups: [type]
|
|
184
|
-
}
|
|
185
|
-
else
|
|
186
|
-
check_requirements(requirement)
|
|
187
|
-
# String sources are registry name references (e.g., "custom") that reference
|
|
188
|
-
# [[tool.poetry.source]] definitions. Resolve them to proper hashes.
|
|
189
|
-
source_value = requirement.fetch("source", nil)
|
|
190
|
-
source = resolve_source(source_value)
|
|
191
|
-
{
|
|
192
|
-
requirement: requirement["version"],
|
|
193
|
-
file: T.must(pyproject).name,
|
|
194
|
-
source: source,
|
|
195
|
-
groups: [type]
|
|
196
|
-
}
|
|
197
|
-
end
|
|
149
|
+
sig do
|
|
150
|
+
params(
|
|
151
|
+
requirements_data: T::Array[PyprojectDocument::PoetryRequirement],
|
|
152
|
+
type: String
|
|
153
|
+
).returns(T::Array[Dependabot::Dependency::RequirementInput])
|
|
154
|
+
end
|
|
155
|
+
def parse_requirements_from(requirements_data, type)
|
|
156
|
+
requirements_data.filter_map { |requirement| poetry_requirement(requirement, type) }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
sig do
|
|
160
|
+
params(
|
|
161
|
+
requirement: PyprojectDocument::PoetryRequirement,
|
|
162
|
+
type: String
|
|
163
|
+
).returns(T.nilable(Dependabot::Dependency::RequirementInput))
|
|
164
|
+
end
|
|
165
|
+
def poetry_requirement(requirement, type)
|
|
166
|
+
if requirement.is_a?(String)
|
|
167
|
+
check_requirements(requirement)
|
|
168
|
+
return {
|
|
169
|
+
requirement: requirement,
|
|
170
|
+
file: T.must(pyproject).name,
|
|
171
|
+
source: nil,
|
|
172
|
+
groups: [type]
|
|
173
|
+
}
|
|
198
174
|
end
|
|
175
|
+
|
|
176
|
+
return if UNSUPPORTED_DEPENDENCY_TYPES.intersect?(requirement.keys)
|
|
177
|
+
|
|
178
|
+
git = requirement_string(requirement, "git")
|
|
179
|
+
tag = requirement_string(requirement, "tag")
|
|
180
|
+
return if git && !tag
|
|
181
|
+
|
|
182
|
+
return git_requirement(git, tag, type) if git && tag
|
|
183
|
+
|
|
184
|
+
check_requirements(requirement)
|
|
185
|
+
{
|
|
186
|
+
requirement: requirement_string(requirement, "version"),
|
|
187
|
+
file: T.must(pyproject).name,
|
|
188
|
+
source: resolve_source(requirement["source"]),
|
|
189
|
+
groups: [type]
|
|
190
|
+
}
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
sig { params(git: String, tag: String, type: String).returns(Dependabot::Dependency::RequirementInput) }
|
|
194
|
+
def git_requirement(git, tag, type)
|
|
195
|
+
{
|
|
196
|
+
requirement: nil,
|
|
197
|
+
file: T.must(pyproject).name,
|
|
198
|
+
source: {
|
|
199
|
+
type: "git",
|
|
200
|
+
url: git,
|
|
201
|
+
ref: tag,
|
|
202
|
+
branch: nil
|
|
203
|
+
},
|
|
204
|
+
groups: [type]
|
|
205
|
+
}
|
|
199
206
|
end
|
|
200
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
|
201
207
|
|
|
202
|
-
sig { returns(T
|
|
208
|
+
sig { returns(T::Boolean) }
|
|
203
209
|
def using_poetry?
|
|
204
|
-
|
|
210
|
+
pyproject_document.poetry?
|
|
205
211
|
end
|
|
206
212
|
|
|
207
213
|
sig { returns(T::Boolean) }
|
|
208
214
|
def using_pep621?
|
|
209
|
-
|
|
210
|
-
!parsed_pyproject.dig("project", "optional-dependencies").nil? ||
|
|
211
|
-
!parsed_pyproject.dig("build-system", "requires").nil?
|
|
215
|
+
pyproject_document.pep621?
|
|
212
216
|
end
|
|
213
217
|
|
|
214
218
|
sig { returns(T::Boolean) }
|
|
215
219
|
def using_pep735?
|
|
216
|
-
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
sig { returns(T.nilable(T::Hash[String, T.untyped])) }
|
|
220
|
-
def poetry_root
|
|
221
|
-
parsed_pyproject.dig("tool", "poetry")
|
|
220
|
+
pyproject_document.pep735?
|
|
222
221
|
end
|
|
223
222
|
|
|
224
|
-
sig { returns(T
|
|
223
|
+
sig { returns(T::Boolean) }
|
|
225
224
|
def using_pdm?
|
|
226
|
-
using_pep621? && pdm_lock
|
|
225
|
+
using_pep621? && !pdm_lock.nil?
|
|
227
226
|
end
|
|
228
227
|
|
|
229
228
|
sig { returns(T::Array[String]) }
|
|
230
229
|
def dynamic_fields
|
|
231
|
-
|
|
230
|
+
pyproject_document.dynamic_fields
|
|
232
231
|
end
|
|
233
232
|
|
|
234
|
-
sig { params(dep:
|
|
233
|
+
sig { params(dep: PepDependency).returns(T::Boolean) }
|
|
235
234
|
def skip_pep621_dep?(dep)
|
|
236
235
|
# If a requirement has a `<` or `<=` marker then updating it is
|
|
237
236
|
# probably blocked. Ignore it.
|
|
238
|
-
return true if dep
|
|
237
|
+
return true if dep.markers&.include?("<")
|
|
239
238
|
|
|
240
239
|
# If no requirement, don't add it
|
|
241
|
-
|
|
240
|
+
requirement = dep.requirement
|
|
241
|
+
raise TypeError, "Python PEP dependency requirement must be a string" unless requirement
|
|
242
|
+
return true if requirement.empty?
|
|
242
243
|
|
|
243
244
|
# Skip build-system.requires dependencies when using Poetry
|
|
244
245
|
# Poetry manages its own build system dependencies
|
|
245
|
-
return true if using_poetry? && dep
|
|
246
|
+
return true if using_poetry? && dep.requirement_type == "build-system.requires"
|
|
246
247
|
|
|
247
248
|
# When dependencies or optional-dependencies are listed in project.dynamic,
|
|
248
249
|
# they are managed by the build backend (e.g. Poetry) — skip the PEP 621 path
|
|
249
|
-
dynamic_pep621_dep?(dep
|
|
250
|
+
dynamic_pep621_dep?(dep.requirement_type)
|
|
250
251
|
end
|
|
251
252
|
|
|
252
253
|
sig { params(requirement_type: T.nilable(String)).returns(T::Boolean) }
|
|
@@ -256,7 +257,7 @@ module Dependabot
|
|
|
256
257
|
|
|
257
258
|
if requirement_type == "dependencies"
|
|
258
259
|
dynamic_fields.include?("dependencies")
|
|
259
|
-
elsif
|
|
260
|
+
elsif pyproject_document.optional_dependency_group?(requirement_type)
|
|
260
261
|
dynamic_fields.include?("optional-dependencies")
|
|
261
262
|
else
|
|
262
263
|
false
|
|
@@ -271,15 +272,15 @@ module Dependabot
|
|
|
271
272
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
|
272
273
|
|
|
273
274
|
source_types = %w(directory git url)
|
|
274
|
-
|
|
275
|
-
next if source_types.include?(
|
|
275
|
+
poetry_lock_document.packages.each do |package|
|
|
276
|
+
next if source_types.include?(package.source_type)
|
|
276
277
|
|
|
277
|
-
name = normalise(
|
|
278
|
+
name = normalise(package.name)
|
|
278
279
|
|
|
279
280
|
dependencies <<
|
|
280
281
|
Dependency.new(
|
|
281
282
|
name: name,
|
|
282
|
-
version:
|
|
283
|
+
version: package.version,
|
|
283
284
|
requirements: [],
|
|
284
285
|
package_manager: "pip",
|
|
285
286
|
subdependency_metadata: [{
|
|
@@ -302,8 +303,10 @@ module Dependabot
|
|
|
302
303
|
sig { returns(T::Array[T.nilable(String)]) }
|
|
303
304
|
def parse_production_dependency_names
|
|
304
305
|
SharedHelpers.in_a_temporary_directory do
|
|
305
|
-
|
|
306
|
-
|
|
306
|
+
pyproject_file = T.must(pyproject)
|
|
307
|
+
lockfile_file = T.must(lockfile)
|
|
308
|
+
File.write(pyproject_file.name, pyproject_file.content)
|
|
309
|
+
File.write(lockfile_file.name, lockfile_file.content)
|
|
307
310
|
|
|
308
311
|
begin
|
|
309
312
|
output = SharedHelpers.run_shell_command("pyenv exec poetry show --only main")
|
|
@@ -322,18 +325,19 @@ module Dependabot
|
|
|
322
325
|
end
|
|
323
326
|
end
|
|
324
327
|
|
|
325
|
-
sig { params(dep_name: String).returns(T.
|
|
328
|
+
sig { params(dep_name: String).returns(T.nilable(String)) }
|
|
326
329
|
def version_from_lockfile(dep_name)
|
|
327
|
-
return unless
|
|
330
|
+
return unless poetry_lock
|
|
328
331
|
|
|
329
|
-
|
|
330
|
-
.find { |p| normalise(p.fetch("name")) == normalise(dep_name) }
|
|
331
|
-
&.fetch("version", nil)
|
|
332
|
+
poetry_lock_document.version_for(dep_name) { |name| normalise(name) }
|
|
332
333
|
end
|
|
333
334
|
|
|
334
|
-
sig
|
|
335
|
+
sig do
|
|
336
|
+
params(req: PyprojectDocument::PoetryRequirement)
|
|
337
|
+
.returns(T::Array[Dependabot::Python::Requirement])
|
|
338
|
+
end
|
|
335
339
|
def check_requirements(req)
|
|
336
|
-
requirement = req.is_a?(String) ? req : req
|
|
340
|
+
requirement = req.is_a?(String) ? req : requirement_string(req, "version")
|
|
337
341
|
Python::Requirement.requirements_array(requirement)
|
|
338
342
|
rescue Gem::Requirement::BadRequirementError => e
|
|
339
343
|
raise Dependabot::DependencyFileNotEvaluatable, e.message
|
|
@@ -344,21 +348,23 @@ module Dependabot
|
|
|
344
348
|
NameNormaliser.normalise(name)
|
|
345
349
|
end
|
|
346
350
|
|
|
347
|
-
sig
|
|
351
|
+
sig do
|
|
352
|
+
params(source_value: T.nilable(Object))
|
|
353
|
+
.returns(T.nilable(Dependabot::DependencyRequirement::Source))
|
|
354
|
+
end
|
|
348
355
|
def resolve_source(source_value)
|
|
349
356
|
# Return nil if no source specified
|
|
350
357
|
return nil if source_value.nil?
|
|
351
358
|
|
|
352
359
|
# If already a hash, return as-is (handles git sources)
|
|
353
|
-
return source_value if source_value.is_a?(Hash)
|
|
360
|
+
return PyprojectValueParser.object_hash(source_value, "Poetry dependency source") if source_value.is_a?(Hash)
|
|
354
361
|
|
|
355
362
|
# String sources are references to [[tool.poetry.source]] definitions
|
|
356
363
|
# Look up the source definition and create a hash
|
|
357
364
|
return nil unless source_value.is_a?(String)
|
|
358
365
|
|
|
359
366
|
source_name = source_value
|
|
360
|
-
|
|
361
|
-
source_def = poetry_sources.find { |s| s["name"] == source_name }
|
|
367
|
+
source_def = pyproject_document.poetry_source(source_name)
|
|
362
368
|
|
|
363
369
|
# If source definition not found, return nil
|
|
364
370
|
return nil unless source_def
|
|
@@ -367,26 +373,19 @@ module Dependabot
|
|
|
367
373
|
# Use "registry" as the type since these are package index sources
|
|
368
374
|
{
|
|
369
375
|
type: "registry",
|
|
370
|
-
url: source_def
|
|
376
|
+
url: source_def.url,
|
|
371
377
|
name: source_name
|
|
372
378
|
}
|
|
373
379
|
end
|
|
374
380
|
|
|
375
|
-
sig { returns(
|
|
376
|
-
def
|
|
377
|
-
@
|
|
378
|
-
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
|
379
|
-
raise Dependabot::DependencyFileNotParseable, T.must(pyproject).path
|
|
381
|
+
sig { returns(PyprojectDocument) }
|
|
382
|
+
def pyproject_document
|
|
383
|
+
@pyproject_document ||= PyprojectDocument.from_file(T.must(pyproject))
|
|
380
384
|
end
|
|
381
385
|
|
|
382
|
-
sig { returns(
|
|
383
|
-
def
|
|
384
|
-
@
|
|
385
|
-
TomlRB.parse(T.must(poetry_lock).content),
|
|
386
|
-
T.nilable(T::Hash[String, T.untyped])
|
|
387
|
-
)
|
|
388
|
-
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
|
389
|
-
raise Dependabot::DependencyFileNotParseable, T.must(poetry_lock).path
|
|
386
|
+
sig { returns(PoetryLock) }
|
|
387
|
+
def poetry_lock_document
|
|
388
|
+
@poetry_lock_document ||= PoetryLock.from_file(T.must(poetry_lock))
|
|
390
389
|
end
|
|
391
390
|
|
|
392
391
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
@@ -397,20 +396,22 @@ module Dependabot
|
|
|
397
396
|
)
|
|
398
397
|
end
|
|
399
398
|
|
|
400
|
-
sig { returns(T.
|
|
399
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
401
400
|
def lockfile
|
|
402
401
|
poetry_lock
|
|
403
402
|
end
|
|
404
403
|
|
|
405
|
-
sig { returns(T
|
|
404
|
+
sig { returns(T::Array[PepDependency]) }
|
|
406
405
|
def parse_pep621_pep735_dependencies
|
|
407
406
|
SharedHelpers.in_a_temporary_directory do
|
|
408
407
|
write_temporary_pyproject
|
|
409
408
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
409
|
+
PepDependency.from_helper_result(
|
|
410
|
+
SharedHelpers.run_helper_subprocess(
|
|
411
|
+
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
412
|
+
function: "parse_pep621_pep735_dependencies",
|
|
413
|
+
args: [T.must(pyproject).name]
|
|
414
|
+
)
|
|
414
415
|
)
|
|
415
416
|
end
|
|
416
417
|
end
|
|
@@ -422,11 +423,6 @@ module Dependabot
|
|
|
422
423
|
File.write(path, T.must(pyproject).content)
|
|
423
424
|
end
|
|
424
425
|
|
|
425
|
-
sig { returns(T.untyped) }
|
|
426
|
-
def parsed_lockfile
|
|
427
|
-
parsed_poetry_lock if poetry_lock
|
|
428
|
-
end
|
|
429
|
-
|
|
430
426
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
431
427
|
def poetry_lock
|
|
432
428
|
@poetry_lock ||= T.let(
|
|
@@ -435,6 +431,16 @@ module Dependabot
|
|
|
435
431
|
)
|
|
436
432
|
end
|
|
437
433
|
|
|
434
|
+
sig do
|
|
435
|
+
params(
|
|
436
|
+
requirement: PyprojectValueParser::ObjectHash,
|
|
437
|
+
key: String
|
|
438
|
+
).returns(T.nilable(String))
|
|
439
|
+
end
|
|
440
|
+
def requirement_string(requirement, key)
|
|
441
|
+
PyprojectValueParser.optional_string(requirement[key], "Poetry dependency #{key}")
|
|
442
|
+
end
|
|
443
|
+
|
|
438
444
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
439
445
|
def pdm_lock
|
|
440
446
|
@pdm_lock ||= T.let(
|
|
@@ -68,10 +68,19 @@ module Dependabot
|
|
|
68
68
|
SharedHelpers.in_a_temporary_directory do
|
|
69
69
|
write_temporary_dependency_files
|
|
70
70
|
|
|
71
|
-
requirements =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
requirements = T.cast(
|
|
72
|
+
SharedHelpers.run_helper_subprocess(
|
|
73
|
+
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
74
|
+
function: "parse_setup",
|
|
75
|
+
args: [Dir.pwd]
|
|
76
|
+
),
|
|
77
|
+
T.nilable(
|
|
78
|
+
T.any(
|
|
79
|
+
T::Hash[String, T.untyped],
|
|
80
|
+
String,
|
|
81
|
+
T::Array[T::Hash[String, T.untyped]]
|
|
82
|
+
)
|
|
83
|
+
)
|
|
75
84
|
)
|
|
76
85
|
|
|
77
86
|
check_requirements(requirements)
|
|
@@ -90,10 +99,19 @@ module Dependabot
|
|
|
90
99
|
SharedHelpers.in_a_temporary_directory do
|
|
91
100
|
write_sanitized_setup_file
|
|
92
101
|
|
|
93
|
-
requirements =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
requirements = T.cast(
|
|
103
|
+
SharedHelpers.run_helper_subprocess(
|
|
104
|
+
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
105
|
+
function: "parse_setup",
|
|
106
|
+
args: [Dir.pwd]
|
|
107
|
+
),
|
|
108
|
+
T.nilable(
|
|
109
|
+
T.any(
|
|
110
|
+
T::Hash[String, T.untyped],
|
|
111
|
+
String,
|
|
112
|
+
T::Array[T::Hash[String, T.untyped]]
|
|
113
|
+
)
|
|
114
|
+
)
|
|
97
115
|
)
|
|
98
116
|
|
|
99
117
|
check_requirements(requirements)
|
|
@@ -21,6 +21,9 @@ module Dependabot
|
|
|
21
21
|
class FileParser < Dependabot::FileParsers::Base # rubocop:disable Metrics/ClassLength
|
|
22
22
|
extend T::Sig
|
|
23
23
|
|
|
24
|
+
require_relative "file_parser/pyproject_document"
|
|
25
|
+
require_relative "file_parser/poetry_lock"
|
|
26
|
+
require_relative "file_parser/pep_dependency"
|
|
24
27
|
require_relative "file_parser/pipfile_files_parser"
|
|
25
28
|
require_relative "file_parser/pyproject_files_parser"
|
|
26
29
|
require_relative "file_parser/setup_file_parser"
|
|
@@ -345,10 +345,19 @@ module Dependabot
|
|
|
345
345
|
def pipfile_hash_for(pipfile_content)
|
|
346
346
|
SharedHelpers.in_a_temporary_directory do |dir|
|
|
347
347
|
File.write(File.join(dir, "Pipfile"), pipfile_content)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
348
|
+
T.cast(
|
|
349
|
+
SharedHelpers.run_helper_subprocess(
|
|
350
|
+
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
351
|
+
function: "get_pipfile_hash",
|
|
352
|
+
args: [T.cast(dir, Pathname).to_s]
|
|
353
|
+
),
|
|
354
|
+
T.nilable(
|
|
355
|
+
T.any(
|
|
356
|
+
T::Hash[String, T.untyped],
|
|
357
|
+
String,
|
|
358
|
+
T::Array[T::Hash[String, T.untyped]]
|
|
359
|
+
)
|
|
360
|
+
)
|
|
352
361
|
)
|
|
353
362
|
end
|
|
354
363
|
end
|
|
@@ -18,6 +18,16 @@ require "dependabot/package/release_cooldown_options"
|
|
|
18
18
|
|
|
19
19
|
module Dependabot
|
|
20
20
|
module Python
|
|
21
|
+
PoetryPyprojectHashResult = T.type_alias do
|
|
22
|
+
T.nilable(
|
|
23
|
+
T.any(
|
|
24
|
+
T::Hash[String, T.untyped],
|
|
25
|
+
String,
|
|
26
|
+
T::Array[T::Hash[String, T.untyped]]
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
21
31
|
class FileUpdater
|
|
22
32
|
class PoetryFileUpdater
|
|
23
33
|
require_relative "pyproject_preparer"
|
|
@@ -367,17 +377,18 @@ module Dependabot
|
|
|
367
377
|
.add_auth_env_vars(credentials)
|
|
368
378
|
end
|
|
369
379
|
|
|
370
|
-
sig { params(pyproject_content: String).returns(
|
|
380
|
+
sig { params(pyproject_content: String).returns(PoetryPyprojectHashResult) }
|
|
371
381
|
def pyproject_hash_for(pyproject_content)
|
|
372
382
|
SharedHelpers.in_a_temporary_directory do |dir|
|
|
373
383
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
|
374
384
|
write_temporary_dependency_files(pyproject_content)
|
|
375
385
|
|
|
376
|
-
SharedHelpers.run_helper_subprocess(
|
|
386
|
+
result = SharedHelpers.run_helper_subprocess(
|
|
377
387
|
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
378
388
|
function: "get_pyproject_hash",
|
|
379
389
|
args: [T.cast(dir, Pathname).to_s]
|
|
380
390
|
)
|
|
391
|
+
T.cast(result, PoetryPyprojectHashResult)
|
|
381
392
|
end
|
|
382
393
|
end
|
|
383
394
|
end
|