dependabot-python 0.393.0 → 0.395.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 +2 -2
- 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 +284 -0
- data/lib/dependabot/python/file_parser/pyproject_files_parser.rb +134 -128
- data/lib/dependabot/python/file_parser.rb +3 -0
- data/lib/dependabot/python/file_updater/pip_compile_file_updater.rb +14 -8
- 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/pip_version_resolver.rb +1 -2
- data/lib/dependabot/python/update_checker/requirements_updater.rb +2 -3
- data/lib/dependabot/python/update_checker.rb +48 -49
- metadata +13 -9
|
@@ -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(
|
|
@@ -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"
|
|
@@ -17,7 +17,7 @@ require "dependabot/python/authed_url_builder"
|
|
|
17
17
|
module Dependabot
|
|
18
18
|
module Python
|
|
19
19
|
class FileUpdater
|
|
20
|
-
# rubocop:disable Metrics/ClassLength
|
|
20
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
21
21
|
class PipCompileFileUpdater
|
|
22
22
|
extend T::Sig
|
|
23
23
|
|
|
@@ -466,6 +466,7 @@ module Dependabot
|
|
|
466
466
|
end
|
|
467
467
|
|
|
468
468
|
sig { params(name: String, version: String, algorithm: String).returns(T::Array[String]) }
|
|
469
|
+
# rubocop:disable-next Metrics/PerceivedComplexity
|
|
469
470
|
def package_hashes_for(name:, version:, algorithm:)
|
|
470
471
|
index_urls = @index_urls || [nil]
|
|
471
472
|
hashes = []
|
|
@@ -477,12 +478,17 @@ module Dependabot
|
|
|
477
478
|
args << index_url if index_url
|
|
478
479
|
|
|
479
480
|
begin
|
|
481
|
+
helper_result = SharedHelpers.run_helper_subprocess(
|
|
482
|
+
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
483
|
+
function: "get_dependency_hash",
|
|
484
|
+
args: args
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
# Skip this index if helper returned nil (can happen with unavailable registries)
|
|
488
|
+
next if helper_result.nil?
|
|
489
|
+
|
|
480
490
|
native_helper_hashes = T.cast(
|
|
481
|
-
|
|
482
|
-
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
483
|
-
function: "get_dependency_hash",
|
|
484
|
-
args: args
|
|
485
|
-
),
|
|
491
|
+
helper_result,
|
|
486
492
|
T::Array[T::Hash[String, String]]
|
|
487
493
|
).map { |h| "--hash=#{algorithm}:#{h['hash']}" }
|
|
488
494
|
|
|
@@ -494,9 +500,10 @@ module Dependabot
|
|
|
494
500
|
end
|
|
495
501
|
end
|
|
496
502
|
|
|
503
|
+
raise DependencyFileNotResolvable, "Unable to find hashes for package #{name}" if hashes.empty?
|
|
504
|
+
|
|
497
505
|
hashes
|
|
498
506
|
end
|
|
499
|
-
|
|
500
507
|
sig { params(requirement_string: String).returns(T.nilable(String)) }
|
|
501
508
|
def hash_separator(requirement_string)
|
|
502
509
|
hash_regex = RequirementParser::HASH
|
|
@@ -807,7 +814,6 @@ module Dependabot
|
|
|
807
814
|
dependency_files.select { |f| f.name.end_with?("setup.cfg") }
|
|
808
815
|
end
|
|
809
816
|
end
|
|
810
|
-
# rubocop:enable Metrics/ClassLength
|
|
811
817
|
end
|
|
812
818
|
end
|
|
813
819
|
end
|