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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16f73abf3755178c72c29e83289797a4ed369364e69166caefb51082893b9f6c
4
- data.tar.gz: cbe0877963a964dd7799635533fcd310792b8ef1fef882b92aee02564a84b653
3
+ metadata.gz: 65f2f1c55ac562ad6abef01b525db3cbb33619731e81c0a076e3b568534fc113
4
+ data.tar.gz: b4b855731c6b90017d6a5a8edc77adaded62251983b94ccd0c772733bd5e57dd
5
5
  SHA512:
6
- metadata.gz: 1d1b6bf9acebd9fdcea9b2a9423fad240dd06b6854d58ed3b69322436869261cc3a0d0b24f388d3fabf6d79d8f78980518085fb463ad5c1321952c9258f11007
7
- data.tar.gz: 0cc86b9dec23ac4c5fc1fae9237c9aa55d611402f77ddf9e996aca436c823a238362ea6dab631060f47be18f97e234b215e43cb90df97047be4c838a6b2681ce
6
+ metadata.gz: 98f0de7da1e05b555a23953c5e3e23253fe62c0a6e9f17e0cc87a0a9c8028cf5d787189bf1436e908922fddb4cf04383fb113c0fae95f487ed40995c6f79a31e
7
+ data.tar.gz: bf20aa8c3ce3317ebb2588f320400abb6857db6b40dbb61a8e7897722bda77f11a44adb76bdd6319ffb1fcca7b8405c0584111bb7c03d7caa9e52d95c45912b2
@@ -1,4 +1,4 @@
1
- # typed: true
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(cargo_toml).dig("package", "workspace")
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
- parsed_file(file).fetch(type, {}).each do |name, requirement|
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
- parsed_file(file).fetch("target", {}).each do |_, t_details|
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 = parsed_file(file).fetch("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(lockfile).fetch("package", []).each do |package_details|
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
- return [] unless parsed_file(root_manifest)["patch"]
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
- parsed_file(root_manifest)["patch"].values.flat_map(&:keys)
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
- return declaration == "" ? nil : declaration
192
- end
193
- raise "Unexpected dependency declaration: #{declaration}" unless declaration.is_a?(Hash)
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
- nil
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
- return name if declaration.is_a?(String)
201
- raise "Unexpected dependency declaration: #{declaration}" unless declaration.is_a?(Hash)
202
-
203
- declaration.fetch("package", name)
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
- return if declaration.is_a?(String)
208
- raise "Unexpected dependency declaration: #{declaration}" unless declaration.is_a?(Hash)
209
-
210
- return git_source_details(declaration) if declaration["git"]
211
- return { type: "path" } if declaration["path"]
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
- registry_source_details(declaration)
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
- parsed_file(cargo_config).dig(*key_name.split("."))
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
- parsed_file(lockfile).fetch("package", [])
289
- .select { |p| p["name"] == name }
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
- .select { |f| f.name.end_with?("Cargo.toml") }
348
- .reject(&:support_file?)
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: true
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
- rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
42
- raise Dependabot::DependencyFileNotResolvable, e.message
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 nil
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
- .named_captures.fetch("url").split(/[#?]/).first
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
- urls << url
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
- raise Dependabot::GitDependencyReferenceNotFound, dependency_url
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
- .fetch(:source).fetch(:url)
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
- .find { |f| f.name == "Cargo.lock" }
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
- .find { |f| f.name == "rust-toolchain" }
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 { |f| f.name == ".cargo/config.toml" }
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.325.1
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.325.1
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.325.1
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.325.1
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