dependabot-cargo 0.325.1 → 0.326.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/lib/dependabot/cargo/file_parser.rb +83 -35
- data/lib/dependabot/cargo/update_checker/version_resolver.rb +101 -47
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 65f2f1c55ac562ad6abef01b525db3cbb33619731e81c0a076e3b568534fc113
|
|
4
|
+
data.tar.gz: b4b855731c6b90017d6a5a8edc77adaded62251983b94ccd0c772733bd5e57dd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 98f0de7da1e05b555a23953c5e3e23253fe62c0a6e9f17e0cc87a0a9c8028cf5d787189bf1436e908922fddb4cf04383fb113c0fae95f487ed40995c6f79a31e
|
|
7
|
+
data.tar.gz: bf20aa8c3ce3317ebb2588f320400abb6857db6b40dbb61a8e7897722bda77f11a44adb76bdd6319ffb1fcca7b8405c0584111bb7c03d7caa9e52d95c45912b2
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "toml-rb"
|
|
@@ -25,6 +25,7 @@ module Dependabot
|
|
|
25
25
|
DEPENDENCY_TYPES =
|
|
26
26
|
%w(dependencies dev-dependencies build-dependencies).freeze
|
|
27
27
|
|
|
28
|
+
sig { override.returns(T::Array[Dependabot::Dependency]) }
|
|
28
29
|
def parse
|
|
29
30
|
check_rust_workspace_root
|
|
30
31
|
|
|
@@ -88,10 +89,14 @@ module Dependabot
|
|
|
88
89
|
end, T.nilable(String))
|
|
89
90
|
end
|
|
90
91
|
|
|
92
|
+
sig { void }
|
|
91
93
|
def check_rust_workspace_root
|
|
92
94
|
cargo_toml = dependency_files.find { |f| f.name == "Cargo.toml" }
|
|
93
|
-
workspace_root = parsed_file(
|
|
94
|
-
return unless workspace_root
|
|
95
|
+
workspace_root = parsed_file(T.must(cargo_toml))
|
|
96
|
+
return unless workspace_root.is_a?(Hash)
|
|
97
|
+
|
|
98
|
+
workspace_config = workspace_root.dig("package", "workspace")
|
|
99
|
+
return unless workspace_config
|
|
95
100
|
|
|
96
101
|
msg = "This project is part of a Rust workspace but is not the " \
|
|
97
102
|
"workspace root." \
|
|
@@ -106,19 +111,23 @@ module Dependabot
|
|
|
106
111
|
# rubocop:disable Metrics/AbcSize
|
|
107
112
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
108
113
|
# rubocop:disable Metrics/PerceivedComplexity
|
|
114
|
+
sig { returns(DependencySet) }
|
|
109
115
|
def manifest_dependencies
|
|
110
116
|
dependency_set = DependencySet.new
|
|
111
117
|
|
|
112
118
|
manifest_files.each do |file|
|
|
119
|
+
parsed_content = parsed_file(file)
|
|
120
|
+
next unless parsed_content.is_a?(Hash)
|
|
121
|
+
|
|
113
122
|
DEPENDENCY_TYPES.each do |type|
|
|
114
|
-
|
|
123
|
+
parsed_content.fetch(type, {}).each do |name, requirement|
|
|
115
124
|
next unless name == name_from_declaration(name, requirement)
|
|
116
125
|
next if lockfile && !version_from_lockfile(name, requirement)
|
|
117
126
|
|
|
118
127
|
dependency_set << build_dependency(name, requirement, type, file)
|
|
119
128
|
end
|
|
120
129
|
|
|
121
|
-
|
|
130
|
+
parsed_content.fetch("target", {}).each do |_, t_details|
|
|
122
131
|
t_details.fetch(type, {}).each do |name, requirement|
|
|
123
132
|
next unless name == name_from_declaration(name, requirement)
|
|
124
133
|
next if lockfile && !version_from_lockfile(name, requirement)
|
|
@@ -129,7 +138,7 @@ module Dependabot
|
|
|
129
138
|
end
|
|
130
139
|
end
|
|
131
140
|
|
|
132
|
-
workspace =
|
|
141
|
+
workspace = parsed_content.fetch("workspace", {})
|
|
133
142
|
workspace.fetch("dependencies", {}).each do |name, requirement|
|
|
134
143
|
next unless name == name_from_declaration(name, requirement)
|
|
135
144
|
next if lockfile && !version_from_lockfile(name, requirement)
|
|
@@ -145,6 +154,10 @@ module Dependabot
|
|
|
145
154
|
# rubocop:enable Metrics/CyclomaticComplexity
|
|
146
155
|
# rubocop:enable Metrics/PerceivedComplexity
|
|
147
156
|
|
|
157
|
+
sig do
|
|
158
|
+
params(name: String, requirement: T.any(String, T::Hash[String, String]), type: String,
|
|
159
|
+
file: Dependabot::DependencyFile).returns(Dependency)
|
|
160
|
+
end
|
|
148
161
|
def build_dependency(name, requirement, type, file)
|
|
149
162
|
Dependency.new(
|
|
150
163
|
name: name,
|
|
@@ -159,11 +172,15 @@ module Dependabot
|
|
|
159
172
|
)
|
|
160
173
|
end
|
|
161
174
|
|
|
175
|
+
sig { returns(DependencySet) }
|
|
162
176
|
def lockfile_dependencies
|
|
163
177
|
dependency_set = DependencySet.new
|
|
164
178
|
return dependency_set unless lockfile
|
|
165
179
|
|
|
166
|
-
parsed_file(
|
|
180
|
+
lockfile_content = parsed_file(T.must(lockfile))
|
|
181
|
+
return dependency_set unless lockfile_content.is_a?(Hash)
|
|
182
|
+
|
|
183
|
+
lockfile_content.fetch("package", []).each do |package_details|
|
|
167
184
|
next unless package_details["source"]
|
|
168
185
|
|
|
169
186
|
# TODO: This isn't quite right, as it will only give us one
|
|
@@ -179,40 +196,49 @@ module Dependabot
|
|
|
179
196
|
dependency_set
|
|
180
197
|
end
|
|
181
198
|
|
|
199
|
+
sig { returns(T::Array[String]) }
|
|
182
200
|
def patched_dependencies
|
|
183
201
|
root_manifest = manifest_files.find { |f| f.name == "Cargo.toml" }
|
|
184
|
-
|
|
202
|
+
parsed_content = parsed_file(T.must(root_manifest))
|
|
203
|
+
return [] unless parsed_content.is_a?(Hash)
|
|
204
|
+
return [] unless parsed_content["patch"]
|
|
185
205
|
|
|
186
|
-
|
|
206
|
+
parsed_content["patch"].values.flat_map(&:keys)
|
|
187
207
|
end
|
|
188
208
|
|
|
209
|
+
sig { params(declaration: T.any(String, T::Hash[String, String])).returns(T.nilable(String)) }
|
|
189
210
|
def requirement_from_declaration(declaration)
|
|
190
211
|
if declaration.is_a?(String)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return declaration["version"] if declaration["version"].is_a?(String) && declaration["version"] != ""
|
|
212
|
+
declaration == "" ? nil : declaration
|
|
213
|
+
else
|
|
214
|
+
return declaration["version"] if declaration["version"].is_a?(String) && declaration["version"] != ""
|
|
195
215
|
|
|
196
|
-
|
|
216
|
+
nil
|
|
217
|
+
end
|
|
197
218
|
end
|
|
198
219
|
|
|
220
|
+
sig { params(name: String, declaration: T.any(String, T::Hash[String, String])).returns(String) }
|
|
199
221
|
def name_from_declaration(name, declaration)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
222
|
+
if declaration.is_a?(String)
|
|
223
|
+
name
|
|
224
|
+
else
|
|
225
|
+
declaration.fetch("package", name)
|
|
226
|
+
end
|
|
204
227
|
end
|
|
205
228
|
|
|
229
|
+
sig { params(declaration: T.any(String, T::Hash[String, String])).returns(T.nilable(T::Hash[Symbol, String])) }
|
|
206
230
|
def source_from_declaration(declaration)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
231
|
+
if declaration.is_a?(String)
|
|
232
|
+
nil
|
|
233
|
+
else
|
|
234
|
+
return git_source_details(declaration) if declaration["git"]
|
|
235
|
+
return { type: "path" } if declaration["path"]
|
|
212
236
|
|
|
213
|
-
|
|
237
|
+
registry_source_details(declaration)
|
|
238
|
+
end
|
|
214
239
|
end
|
|
215
240
|
|
|
241
|
+
sig { params(declaration: T.any(String, T::Hash[String, String])).returns(T.nilable(T::Hash[Symbol, String])) }
|
|
216
242
|
def registry_source_details(declaration)
|
|
217
243
|
registry_name = declaration["registry"]
|
|
218
244
|
return if registry_name.nil?
|
|
@@ -242,6 +268,7 @@ module Dependabot
|
|
|
242
268
|
end
|
|
243
269
|
end
|
|
244
270
|
|
|
271
|
+
sig { params(registry_name: String, index_url: String).returns(T::Hash[Symbol, String]) }
|
|
245
272
|
def sparse_registry_source_details(registry_name, index_url)
|
|
246
273
|
token = credentials.find do |cred|
|
|
247
274
|
cred["type"] == "cargo_registry" && cred["registry"] == registry_name
|
|
@@ -268,25 +295,35 @@ module Dependabot
|
|
|
268
295
|
|
|
269
296
|
# Looks up dotted key name in cargo config
|
|
270
297
|
# e.g. "registries.my_registry.index"
|
|
298
|
+
sig { params(key_name: String).returns(T.nilable(String)) }
|
|
271
299
|
def cargo_config_field(key_name)
|
|
272
300
|
cargo_config_from_env(key_name) || cargo_config_from_file(key_name)
|
|
273
301
|
end
|
|
274
302
|
|
|
303
|
+
sig { params(key_name: String).returns(T.nilable(String)) }
|
|
275
304
|
def cargo_config_from_env(key_name)
|
|
276
305
|
env_var = "CARGO_#{key_name.upcase.tr('-.', '_')}"
|
|
277
306
|
ENV.fetch(env_var, nil)
|
|
278
307
|
end
|
|
279
308
|
|
|
309
|
+
sig { params(key_name: String).returns(T.nilable(String)) }
|
|
280
310
|
def cargo_config_from_file(key_name)
|
|
281
|
-
|
|
311
|
+
config_file = cargo_config
|
|
312
|
+
return nil unless config_file
|
|
313
|
+
|
|
314
|
+
parsed_file(config_file).dig(*key_name.split("."))
|
|
282
315
|
end
|
|
283
316
|
|
|
317
|
+
sig { params(name: String, declaration: T.any(String, T::Hash[String, String])).returns(T.nilable(String)) }
|
|
284
318
|
def version_from_lockfile(name, declaration)
|
|
285
319
|
return unless lockfile
|
|
286
320
|
|
|
321
|
+
lockfile_content = parsed_file(T.must(lockfile))
|
|
322
|
+
return unless lockfile_content.is_a?(Hash)
|
|
323
|
+
|
|
287
324
|
candidate_packages =
|
|
288
|
-
|
|
289
|
-
|
|
325
|
+
lockfile_content.fetch("package", [])
|
|
326
|
+
.select { |p| p["name"] == name }
|
|
290
327
|
|
|
291
328
|
if (req = requirement_from_declaration(declaration))
|
|
292
329
|
req = Cargo::Requirement.new(req)
|
|
@@ -311,10 +348,12 @@ module Dependabot
|
|
|
311
348
|
version_from_lockfile_details(package)
|
|
312
349
|
end
|
|
313
350
|
|
|
351
|
+
sig { params(declaration: T.any(String, T::Hash[String, String])).returns(T::Boolean) }
|
|
314
352
|
def git_req?(declaration)
|
|
315
353
|
source_from_declaration(declaration)&.fetch(:type, nil) == "git"
|
|
316
354
|
end
|
|
317
355
|
|
|
356
|
+
sig { params(declaration: T.any(String, T::Hash[String, String])).returns(T::Hash[Symbol, String]) }
|
|
318
357
|
def git_source_details(declaration)
|
|
319
358
|
{
|
|
320
359
|
type: "git",
|
|
@@ -324,38 +363,47 @@ module Dependabot
|
|
|
324
363
|
}
|
|
325
364
|
end
|
|
326
365
|
|
|
366
|
+
sig { params(package_details: T::Hash[String, String]).returns(String) }
|
|
327
367
|
def version_from_lockfile_details(package_details)
|
|
328
|
-
return package_details["version"] unless package_details["source"]&.start_with?("git+")
|
|
368
|
+
return T.must(package_details["version"]) unless package_details["source"]&.start_with?("git+")
|
|
329
369
|
|
|
330
|
-
package_details["source"].split("#").last
|
|
370
|
+
T.must(T.must(package_details["source"]).split("#").last)
|
|
331
371
|
end
|
|
332
372
|
|
|
373
|
+
sig { override.void }
|
|
333
374
|
def check_required_files
|
|
334
375
|
raise "No Cargo.toml!" unless get_original_file("Cargo.toml")
|
|
335
376
|
end
|
|
336
377
|
|
|
378
|
+
sig { params(file: DependencyFile).returns(T.untyped) }
|
|
337
379
|
def parsed_file(file)
|
|
338
|
-
@parsed_file ||= {}
|
|
380
|
+
@parsed_file ||= T.let({}, T.untyped)
|
|
339
381
|
@parsed_file[file.name] ||= TomlRB.parse(file.content)
|
|
340
382
|
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
|
341
383
|
raise Dependabot::DependencyFileNotParseable, file.path
|
|
342
384
|
end
|
|
343
385
|
|
|
386
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
344
387
|
def manifest_files
|
|
345
|
-
@manifest_files ||=
|
|
388
|
+
@manifest_files ||= T.let(
|
|
346
389
|
dependency_files
|
|
347
|
-
|
|
348
|
-
|
|
390
|
+
.select { |f| f.name.end_with?("Cargo.toml") }
|
|
391
|
+
.reject(&:support_file?),
|
|
392
|
+
T.nilable(T::Array[Dependabot::DependencyFile])
|
|
393
|
+
)
|
|
349
394
|
end
|
|
350
395
|
|
|
396
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
351
397
|
def lockfile
|
|
352
|
-
@lockfile ||= get_original_file("Cargo.lock")
|
|
398
|
+
@lockfile ||= T.let(get_original_file("Cargo.lock"), T.nilable(Dependabot::DependencyFile))
|
|
353
399
|
end
|
|
354
400
|
|
|
401
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
355
402
|
def cargo_config
|
|
356
|
-
@cargo_config ||= get_original_file(".cargo/config.toml")
|
|
403
|
+
@cargo_config ||= T.let(get_original_file(".cargo/config.toml"), T.nilable(Dependabot::DependencyFile))
|
|
357
404
|
end
|
|
358
405
|
|
|
406
|
+
sig { returns(T.class_of(Dependabot::Version)) }
|
|
359
407
|
def version_class
|
|
360
408
|
Cargo::Version
|
|
361
409
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "toml-rb"
|
|
@@ -12,7 +12,8 @@ require "dependabot/errors"
|
|
|
12
12
|
module Dependabot
|
|
13
13
|
module Cargo
|
|
14
14
|
class UpdateChecker
|
|
15
|
-
class VersionResolver
|
|
15
|
+
class VersionResolver # rubocop:disable Metrics/ClassLength
|
|
16
|
+
extend T::Sig
|
|
16
17
|
UNABLE_TO_UPDATE = /Unable to update (?<url>.*?)$/
|
|
17
18
|
BRANCH_NOT_FOUND_REGEX = /#{UNABLE_TO_UPDATE}.*to find branch `(?<branch>[^`]+)`/m
|
|
18
19
|
REVSPEC_PATTERN = /revspec '.*' not found/
|
|
@@ -26,31 +27,52 @@ module Dependabot
|
|
|
26
27
|
NOT_OUR_REF = /fatal: remote error: upload-pack: not our ref/
|
|
27
28
|
NOT_OUR_REF_REGEX = /#{NOT_OUR_REF}.*#{UNABLE_TO_UPDATE}/m
|
|
28
29
|
|
|
30
|
+
sig do
|
|
31
|
+
params(
|
|
32
|
+
dependency: Dependabot::Dependency,
|
|
33
|
+
credentials: T::Array[Dependabot::Credential],
|
|
34
|
+
original_dependency_files: T::Array[Dependabot::DependencyFile],
|
|
35
|
+
prepared_dependency_files: T::Array[Dependabot::DependencyFile]
|
|
36
|
+
).void
|
|
37
|
+
end
|
|
29
38
|
def initialize(dependency:, credentials:,
|
|
30
39
|
original_dependency_files:, prepared_dependency_files:)
|
|
31
40
|
@dependency = dependency
|
|
32
41
|
@prepared_dependency_files = prepared_dependency_files
|
|
33
42
|
@original_dependency_files = original_dependency_files
|
|
34
43
|
@credentials = credentials
|
|
44
|
+
|
|
45
|
+
# Initialize instance variables with proper T.let declarations
|
|
46
|
+
@prepared_manifest_files = T.let(nil, T.nilable(T::Array[DependencyFile]))
|
|
47
|
+
@original_manifest_files = T.let(nil, T.nilable(T::Array[DependencyFile]))
|
|
35
48
|
end
|
|
36
49
|
|
|
50
|
+
sig { returns(T.nilable(T.any(String, Gem::Version))) }
|
|
37
51
|
def latest_resolvable_version
|
|
38
52
|
return @latest_resolvable_version if defined?(@latest_resolvable_version)
|
|
39
53
|
|
|
40
|
-
@latest_resolvable_version = fetch_latest_resolvable_version
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
@latest_resolvable_version = T.let(fetch_latest_resolvable_version, T.nilable(T.any(String, Gem::Version)))
|
|
55
|
+
rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
|
|
56
|
+
raise Dependabot::DependencyFileNotResolvable, e.message
|
|
43
57
|
end
|
|
44
58
|
|
|
45
59
|
private
|
|
46
60
|
|
|
61
|
+
sig { returns(Dependency) }
|
|
47
62
|
attr_reader :dependency
|
|
63
|
+
|
|
64
|
+
sig { returns(T::Array[Credential]) }
|
|
48
65
|
attr_reader :credentials
|
|
66
|
+
|
|
67
|
+
sig { returns(T::Array[DependencyFile]) }
|
|
49
68
|
attr_reader :prepared_dependency_files
|
|
69
|
+
|
|
70
|
+
sig { returns(T::Array[DependencyFile]) }
|
|
50
71
|
attr_reader :original_dependency_files
|
|
51
72
|
|
|
73
|
+
sig { returns(T.nilable(T.any(String, Gem::Version))) }
|
|
52
74
|
def fetch_latest_resolvable_version
|
|
53
|
-
base_directory = prepared_dependency_files.first.directory
|
|
75
|
+
base_directory = T.must(prepared_dependency_files.first).directory
|
|
54
76
|
SharedHelpers.in_a_temporary_directory(base_directory) do
|
|
55
77
|
write_temporary_dependency_files
|
|
56
78
|
|
|
@@ -68,8 +90,10 @@ module Dependabot
|
|
|
68
90
|
rescue SharedHelpers::HelperSubprocessFailed => e
|
|
69
91
|
retry if better_specification_needed?(e)
|
|
70
92
|
handle_cargo_errors(e)
|
|
93
|
+
nil
|
|
71
94
|
end
|
|
72
95
|
|
|
96
|
+
sig { returns(T.nilable(T.any(String, Gem::Version))) }
|
|
73
97
|
def fetch_version_from_new_lockfile
|
|
74
98
|
check_rust_workspace_root unless File.exist?("Cargo.lock")
|
|
75
99
|
lockfile_content = File.read("Cargo.lock")
|
|
@@ -95,6 +119,7 @@ module Dependabot
|
|
|
95
119
|
# rubocop:disable Metrics/PerceivedComplexity
|
|
96
120
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
97
121
|
# rubocop:disable Metrics/AbcSize
|
|
122
|
+
sig { params(error: StandardError).returns(T::Boolean) }
|
|
98
123
|
def better_specification_needed?(error)
|
|
99
124
|
return false if @custom_specification
|
|
100
125
|
return false unless error.message.match?(/specification .* is ambigu/)
|
|
@@ -108,25 +133,26 @@ module Dependabot
|
|
|
108
133
|
dependency.version
|
|
109
134
|
end
|
|
110
135
|
|
|
111
|
-
if spec_options.count { |s| s.end_with?(ver) } == 1
|
|
112
|
-
@custom_specification = spec_options.find { |s| s.end_with?(ver) }
|
|
136
|
+
if spec_options.count { |s| s.end_with?(T.must(ver)) } == 1
|
|
137
|
+
@custom_specification = spec_options.find { |s| s.end_with?(T.must(ver)) }
|
|
113
138
|
return true
|
|
114
|
-
elsif spec_options.count { |s| s.end_with?(ver) } > 1
|
|
115
|
-
spec_options.select! { |s| s.end_with?(ver) }
|
|
139
|
+
elsif spec_options.count { |s| s.end_with?(T.must(ver)) } > 1
|
|
140
|
+
spec_options.select! { |s| s.end_with?(T.must(ver)) }
|
|
116
141
|
end
|
|
117
142
|
|
|
118
143
|
if git_dependency? && git_source_url &&
|
|
119
|
-
spec_options.count { |s| s.include?(git_source_url) } >= 1
|
|
120
|
-
spec_options.select! { |s| s.include?(git_source_url) }
|
|
144
|
+
spec_options.count { |s| s.include?(T.must(git_source_url)) } >= 1
|
|
145
|
+
spec_options.select! { |s| s.include?(T.must(git_source_url)) }
|
|
121
146
|
end
|
|
122
147
|
|
|
123
|
-
@custom_specification = spec_options.first
|
|
148
|
+
@custom_specification = T.let(spec_options.first, T.nilable(String))
|
|
124
149
|
true
|
|
125
150
|
end
|
|
126
151
|
# rubocop:enable Metrics/AbcSize
|
|
127
152
|
# rubocop:enable Metrics/CyclomaticComplexity
|
|
128
153
|
# rubocop:enable Metrics/PerceivedComplexity
|
|
129
154
|
|
|
155
|
+
sig { returns(String) }
|
|
130
156
|
def dependency_spec
|
|
131
157
|
return @custom_specification if @custom_specification
|
|
132
158
|
|
|
@@ -143,6 +169,7 @@ module Dependabot
|
|
|
143
169
|
|
|
144
170
|
# Shell out to Cargo, which handles everything for us, and does
|
|
145
171
|
# so without doing an install (so it's fast).
|
|
172
|
+
sig { void }
|
|
146
173
|
def run_cargo_update_command
|
|
147
174
|
run_cargo_command(
|
|
148
175
|
"cargo update -p #{dependency_spec} -vv",
|
|
@@ -150,6 +177,7 @@ module Dependabot
|
|
|
150
177
|
)
|
|
151
178
|
end
|
|
152
179
|
|
|
180
|
+
sig { params(command: String, fingerprint: T.nilable(String)).void }
|
|
153
181
|
def run_cargo_command(command, fingerprint: nil)
|
|
154
182
|
start = Time.now
|
|
155
183
|
command = SharedHelpers.escape_command(command)
|
|
@@ -176,40 +204,43 @@ module Dependabot
|
|
|
176
204
|
)
|
|
177
205
|
end
|
|
178
206
|
|
|
207
|
+
sig { params(prepared: T::Boolean).returns(T.nilable(Integer)) }
|
|
179
208
|
def write_temporary_dependency_files(prepared: true)
|
|
180
209
|
write_manifest_files(prepared: prepared)
|
|
181
210
|
|
|
182
|
-
File.write(lockfile.name, lockfile.content) if lockfile
|
|
183
|
-
File.write(toolchain.name, toolchain.content) if toolchain
|
|
211
|
+
File.write(T.must(lockfile).name, T.must(lockfile).content) if lockfile
|
|
212
|
+
File.write(T.must(toolchain).name, T.must(toolchain).content) if toolchain
|
|
184
213
|
return unless config
|
|
185
214
|
|
|
186
|
-
FileUtils.mkdir_p(File.dirname(config.name))
|
|
187
|
-
File.write(config.name, config.content)
|
|
215
|
+
FileUtils.mkdir_p(File.dirname(T.must(config).name))
|
|
216
|
+
File.write(T.must(config).name, T.must(config).content)
|
|
188
217
|
end
|
|
189
218
|
|
|
219
|
+
sig { void }
|
|
190
220
|
def check_rust_workspace_root
|
|
191
221
|
cargo_toml = original_dependency_files
|
|
192
222
|
.select { |f| f.name.end_with?("../Cargo.toml") }
|
|
193
223
|
.max_by { |f| f.name.length }
|
|
194
|
-
return unless TomlRB.parse(cargo_toml.content)["workspace"]
|
|
224
|
+
return unless TomlRB.parse(T.must(cargo_toml).content)["workspace"]
|
|
195
225
|
|
|
196
226
|
msg = "This project is part of a Rust workspace but is not the " \
|
|
197
227
|
"workspace root." \
|
|
198
228
|
|
|
199
|
-
if cargo_toml.directory != "/"
|
|
229
|
+
if T.must(cargo_toml).directory != "/"
|
|
200
230
|
msg += "Please update your settings so Dependabot points at the " \
|
|
201
|
-
"workspace root instead of #{cargo_toml.directory}."
|
|
231
|
+
"workspace root instead of #{T.must(cargo_toml).directory}."
|
|
202
232
|
end
|
|
203
233
|
raise Dependabot::DependencyFileNotResolvable, msg
|
|
204
234
|
end
|
|
205
235
|
|
|
206
236
|
# rubocop:disable Metrics/AbcSize
|
|
207
237
|
# rubocop:disable Metrics/PerceivedComplexity
|
|
238
|
+
sig { params(error: StandardError).void }
|
|
208
239
|
def handle_cargo_errors(error)
|
|
209
240
|
if error.message.include?("does not have these features")
|
|
210
241
|
# TODO: Ideally we should update the declaration not to ask
|
|
211
242
|
# for the specified features
|
|
212
|
-
return
|
|
243
|
+
return
|
|
213
244
|
end
|
|
214
245
|
|
|
215
246
|
if error.message.include?("authenticate when downloading repo") ||
|
|
@@ -218,22 +249,24 @@ module Dependabot
|
|
|
218
249
|
# consistent error)
|
|
219
250
|
urls = unreachable_git_urls
|
|
220
251
|
|
|
221
|
-
if urls.none?
|
|
222
|
-
url = error.message.match(UNABLE_TO_UPDATE)
|
|
223
|
-
|
|
224
|
-
raise if reachable_git_urls.include?(url)
|
|
252
|
+
if T.must(urls).none?
|
|
253
|
+
url = T.must(T.must(error.message.match(UNABLE_TO_UPDATE))
|
|
254
|
+
.named_captures.fetch("url")).split(/[#?]/).first
|
|
255
|
+
raise if T.must(reachable_git_urls).include?(url)
|
|
225
256
|
|
|
226
|
-
|
|
257
|
+
# Fix: Wrap url in T.must since split().first can return nil
|
|
258
|
+
T.must(urls) << T.must(url)
|
|
227
259
|
end
|
|
228
260
|
|
|
229
|
-
raise Dependabot::GitDependenciesNotReachable, urls
|
|
261
|
+
raise Dependabot::GitDependenciesNotReachable, T.must(urls)
|
|
230
262
|
end
|
|
231
263
|
|
|
232
264
|
[BRANCH_NOT_FOUND_REGEX, REF_NOT_FOUND_REGEX, GIT_REF_NOT_FOUND_REGEX, NOT_OUR_REF_REGEX].each do |regex|
|
|
233
265
|
next unless error.message.match?(regex)
|
|
234
266
|
|
|
235
|
-
dependency_url = error.message.match(regex).named_captures.fetch("url").split(/[#?]/).first
|
|
236
|
-
|
|
267
|
+
dependency_url = T.must(T.must(error.message.match(regex)).named_captures.fetch("url")).split(/[#?]/).first
|
|
268
|
+
# Fix: Wrap dependency_url in T.must since split().first can return nil
|
|
269
|
+
raise Dependabot::GitDependencyReferenceNotFound, T.must(dependency_url)
|
|
237
270
|
end
|
|
238
271
|
|
|
239
272
|
if workspace_native_library_update_error?(error.message)
|
|
@@ -268,8 +301,9 @@ module Dependabot
|
|
|
268
301
|
# rubocop:enable Metrics/AbcSize
|
|
269
302
|
# rubocop:enable Metrics/PerceivedComplexity
|
|
270
303
|
|
|
304
|
+
sig { params(message: T.nilable(String)).returns(T.any(Dependabot::Version, T::Boolean)) }
|
|
271
305
|
def using_old_toolchain?(message)
|
|
272
|
-
return true if message.include?("usage of sparse registries requires `-Z sparse-registry`")
|
|
306
|
+
return true if T.must(message).include?("usage of sparse registries requires `-Z sparse-registry`")
|
|
273
307
|
|
|
274
308
|
version_log = /rust version (?<version>\d.\d+)/.match(message)
|
|
275
309
|
return false unless version_log
|
|
@@ -277,11 +311,12 @@ module Dependabot
|
|
|
277
311
|
version_class.new(version_log[:version]) < version_class.new("1.68")
|
|
278
312
|
end
|
|
279
313
|
|
|
314
|
+
sig { returns(T.nilable(T::Array[String])) }
|
|
280
315
|
def unreachable_git_urls
|
|
281
316
|
return @unreachable_git_urls if defined?(@unreachable_git_urls)
|
|
282
317
|
|
|
283
|
-
@unreachable_git_urls = []
|
|
284
|
-
@reachable_git_urls = []
|
|
318
|
+
@unreachable_git_urls = T.let([], T.nilable(T::Array[String]))
|
|
319
|
+
@reachable_git_urls = T.let([], T.nilable(T::Array[String]))
|
|
285
320
|
|
|
286
321
|
dependencies = FileParser.new(
|
|
287
322
|
dependency_files: original_dependency_files,
|
|
@@ -295,19 +330,20 @@ module Dependabot
|
|
|
295
330
|
)
|
|
296
331
|
next unless checker.git_dependency?
|
|
297
332
|
|
|
298
|
-
url = dep.requirements.find { |r| r.dig(:source, :type) == "git" }
|
|
299
|
-
|
|
333
|
+
url = T.must(dep.requirements.find { |r| r.dig(:source, :type) == "git" })
|
|
334
|
+
.fetch(:source).fetch(:url)
|
|
300
335
|
|
|
301
336
|
if checker.git_repo_reachable?
|
|
302
|
-
@reachable_git_urls << url
|
|
337
|
+
T.must(@reachable_git_urls) << url
|
|
303
338
|
else
|
|
304
|
-
@unreachable_git_urls << url
|
|
339
|
+
T.must(@unreachable_git_urls) << url
|
|
305
340
|
end
|
|
306
341
|
end
|
|
307
342
|
|
|
308
343
|
@unreachable_git_urls
|
|
309
344
|
end
|
|
310
345
|
|
|
346
|
+
sig { returns(T.nilable(T::Array[String])) }
|
|
311
347
|
def reachable_git_urls
|
|
312
348
|
return @reachable_git_urls if defined?(@reachable_git_urls)
|
|
313
349
|
|
|
@@ -315,6 +351,7 @@ module Dependabot
|
|
|
315
351
|
@reachable_git_urls
|
|
316
352
|
end
|
|
317
353
|
|
|
354
|
+
sig { params(message: String).returns(T::Boolean) }
|
|
318
355
|
def resolvability_error?(message)
|
|
319
356
|
return true if message.include?("failed to parse lock")
|
|
320
357
|
return true if message.include?("believes it's in a workspace")
|
|
@@ -330,8 +367,9 @@ module Dependabot
|
|
|
330
367
|
!original_requirements_resolvable
|
|
331
368
|
end
|
|
332
369
|
|
|
370
|
+
sig { returns(T.any(TrueClass, FalseClass, Symbol)) }
|
|
333
371
|
def original_requirements_resolvable?
|
|
334
|
-
base_directory = original_dependency_files.first.directory
|
|
372
|
+
base_directory = T.must(original_dependency_files.first).directory
|
|
335
373
|
SharedHelpers.in_a_temporary_directory(base_directory) do
|
|
336
374
|
write_temporary_dependency_files(prepared: false)
|
|
337
375
|
|
|
@@ -353,10 +391,11 @@ module Dependabot
|
|
|
353
391
|
end
|
|
354
392
|
end
|
|
355
393
|
|
|
394
|
+
sig { params(message: String).returns(T::Boolean) }
|
|
356
395
|
def workspace_native_library_update_error?(message)
|
|
357
396
|
return false unless message.include?("native library")
|
|
358
397
|
|
|
359
|
-
library_count = prepared_manifest_files.count do |file|
|
|
398
|
+
library_count = T.must(prepared_manifest_files).count do |file|
|
|
360
399
|
package_name = TomlRB.parse(file.content).dig("package", "name")
|
|
361
400
|
next false unless package_name
|
|
362
401
|
|
|
@@ -366,17 +405,18 @@ module Dependabot
|
|
|
366
405
|
library_count >= 2
|
|
367
406
|
end
|
|
368
407
|
|
|
408
|
+
sig { params(prepared: T::Boolean).returns(T.nilable(T::Array[Dependabot::DependencyFile])) }
|
|
369
409
|
def write_manifest_files(prepared: true)
|
|
370
410
|
manifest_files = if prepared then prepared_manifest_files
|
|
371
411
|
else
|
|
372
412
|
original_manifest_files
|
|
373
413
|
end
|
|
374
414
|
|
|
375
|
-
manifest_files.each do |file|
|
|
415
|
+
T.must(manifest_files).each do |file|
|
|
376
416
|
path = file.name
|
|
377
417
|
dir = Pathname.new(path).dirname
|
|
378
418
|
FileUtils.mkdir_p(dir)
|
|
379
|
-
File.write(file.name, sanitized_manifest_content(file.content))
|
|
419
|
+
File.write(file.name, sanitized_manifest_content(T.must(file.content)))
|
|
380
420
|
|
|
381
421
|
next if virtual_manifest?(file)
|
|
382
422
|
|
|
@@ -388,26 +428,30 @@ module Dependabot
|
|
|
388
428
|
end
|
|
389
429
|
end
|
|
390
430
|
|
|
431
|
+
sig { returns(T.nilable(String)) }
|
|
391
432
|
def git_dependency_version
|
|
392
433
|
return unless lockfile
|
|
393
434
|
|
|
394
|
-
TomlRB.parse(lockfile.content)
|
|
435
|
+
TomlRB.parse(T.must(lockfile).content)
|
|
395
436
|
.fetch("package", [])
|
|
396
437
|
.select { |p| p["name"] == dependency.name }
|
|
397
438
|
.find { |p| p["source"].end_with?(dependency.version) }
|
|
398
439
|
.fetch("version")
|
|
399
440
|
end
|
|
400
441
|
|
|
442
|
+
sig { returns(T.nilable(String)) }
|
|
401
443
|
def git_source_url
|
|
402
444
|
dependency.requirements
|
|
403
445
|
.find { |r| r.dig(:source, :type) == "git" }
|
|
404
446
|
&.dig(:source, :url)
|
|
405
447
|
end
|
|
406
448
|
|
|
449
|
+
sig { returns(String) }
|
|
407
450
|
def dummy_app_content
|
|
408
451
|
%{fn main() {\nprintln!("Hello, world!");\n}}
|
|
409
452
|
end
|
|
410
453
|
|
|
454
|
+
sig { params(content: String).returns(String) }
|
|
411
455
|
def sanitized_manifest_content(content)
|
|
412
456
|
object = TomlRB.parse(content)
|
|
413
457
|
|
|
@@ -424,32 +468,40 @@ module Dependabot
|
|
|
424
468
|
TomlRB.dump(object)
|
|
425
469
|
end
|
|
426
470
|
|
|
471
|
+
sig { returns(T.nilable(T::Array[DependencyFile])) }
|
|
427
472
|
def prepared_manifest_files
|
|
428
473
|
@prepared_manifest_files ||=
|
|
429
474
|
prepared_dependency_files
|
|
430
475
|
.select { |f| f.name.end_with?("Cargo.toml") }
|
|
431
476
|
end
|
|
432
477
|
|
|
478
|
+
sig { returns(T.nilable(T::Array[DependencyFile])) }
|
|
433
479
|
def original_manifest_files
|
|
434
480
|
@original_manifest_files ||=
|
|
435
481
|
original_dependency_files
|
|
436
482
|
.select { |f| f.name.end_with?("Cargo.toml") }
|
|
437
483
|
end
|
|
438
484
|
|
|
485
|
+
sig { returns(T.nilable(DependencyFile)) }
|
|
439
486
|
def lockfile
|
|
440
|
-
@lockfile ||= prepared_dependency_files
|
|
441
|
-
|
|
487
|
+
@lockfile ||= T.let(prepared_dependency_files
|
|
488
|
+
.find { |f| f.name == "Cargo.lock" }, T.nilable(Dependabot::DependencyFile))
|
|
442
489
|
end
|
|
443
490
|
|
|
491
|
+
sig { returns(T.nilable(DependencyFile)) }
|
|
444
492
|
def toolchain
|
|
445
|
-
@toolchain ||= original_dependency_files
|
|
446
|
-
|
|
493
|
+
@toolchain ||= T.let(original_dependency_files
|
|
494
|
+
.find { |f| f.name == "rust-toolchain" }, T.nilable(Dependabot::DependencyFile))
|
|
447
495
|
end
|
|
448
496
|
|
|
497
|
+
sig { returns(T.nilable(DependencyFile)) }
|
|
449
498
|
def config
|
|
450
|
-
@config ||= original_dependency_files.find
|
|
499
|
+
@config ||= T.let(original_dependency_files.find do |f|
|
|
500
|
+
f.name == ".cargo/config.toml"
|
|
501
|
+
end, T.nilable(Dependabot::DependencyFile))
|
|
451
502
|
end
|
|
452
503
|
|
|
504
|
+
sig { returns(T::Boolean) }
|
|
453
505
|
def git_dependency?
|
|
454
506
|
GitCommitChecker.new(
|
|
455
507
|
dependency: dependency,
|
|
@@ -460,10 +512,12 @@ module Dependabot
|
|
|
460
512
|
# When the package table is not present in a workspace manifest, it is
|
|
461
513
|
# called a virtual manifest: https://doc.rust-lang.org/cargo/reference/
|
|
462
514
|
# manifest.html#virtual-manifest
|
|
515
|
+
sig { params(file: DependencyFile).returns(T::Boolean) }
|
|
463
516
|
def virtual_manifest?(file)
|
|
464
|
-
!file.content.include?("[package]")
|
|
517
|
+
!T.must(file.content).include?("[package]")
|
|
465
518
|
end
|
|
466
519
|
|
|
520
|
+
sig { returns(T.class_of(Dependabot::Version)) }
|
|
467
521
|
def version_class
|
|
468
522
|
dependency.version_class
|
|
469
523
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-cargo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.326.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.326.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.326.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: debug
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -265,7 +265,7 @@ licenses:
|
|
|
265
265
|
- MIT
|
|
266
266
|
metadata:
|
|
267
267
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
268
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
268
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.326.0
|
|
269
269
|
rdoc_options: []
|
|
270
270
|
require_paths:
|
|
271
271
|
- lib
|