dependabot-nuget 0.247.0 → 0.249.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +57 -0
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +1 -1
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +25 -5
  5. data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +1 -0
  6. data/lib/dependabot/nuget/file_fetcher/sln_project_paths_finder.rb +2 -0
  7. data/lib/dependabot/nuget/file_fetcher.rb +12 -8
  8. data/lib/dependabot/nuget/file_parser/dotnet_tools_json_parser.rb +1 -0
  9. data/lib/dependabot/nuget/file_parser/global_json_parser.rb +1 -0
  10. data/lib/dependabot/nuget/file_parser/packages_config_parser.rb +1 -0
  11. data/lib/dependabot/nuget/file_parser/project_file_parser.rb +1 -0
  12. data/lib/dependabot/nuget/file_parser/property_value_finder.rb +2 -0
  13. data/lib/dependabot/nuget/file_parser.rb +42 -11
  14. data/lib/dependabot/nuget/file_updater/property_value_updater.rb +1 -0
  15. data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +10 -1
  16. data/lib/dependabot/nuget/requirement.rb +17 -8
  17. data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +28 -7
  18. data/lib/dependabot/nuget/update_checker/dependency_finder.rb +70 -19
  19. data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +76 -8
  20. data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +25 -3
  21. data/lib/dependabot/nuget/update_checker/property_updater.rb +108 -44
  22. data/lib/dependabot/nuget/update_checker/repository_finder.rb +90 -18
  23. data/lib/dependabot/nuget/update_checker/requirements_updater.rb +32 -9
  24. data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +8 -3
  25. data/lib/dependabot/nuget/update_checker/tfm_finder.rb +51 -13
  26. data/lib/dependabot/nuget/update_checker/version_finder.rb +167 -62
  27. data/lib/dependabot/nuget/update_checker.rb +73 -29
  28. metadata +5 -5
@@ -1,8 +1,10 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "excon"
5
5
  require "nokogiri"
6
+ require "sorbet-runtime"
7
+
6
8
  require "dependabot/errors"
7
9
  require "dependabot/update_checkers/base"
8
10
  require "dependabot/registry_client"
@@ -12,23 +14,34 @@ require "dependabot/nuget/http_response_helpers"
12
14
  module Dependabot
13
15
  module Nuget
14
16
  class RepositoryFinder
17
+ extend T::Sig
18
+
15
19
  DEFAULT_REPOSITORY_URL = "https://api.nuget.org/v3/index.json"
16
20
  DEFAULT_REPOSITORY_API_KEY = "nuget.org"
17
21
 
22
+ sig do
23
+ params(
24
+ dependency: Dependabot::Dependency,
25
+ credentials: T::Array[Dependabot::Credential],
26
+ config_files: T::Array[Dependabot::DependencyFile]
27
+ ).void
28
+ end
18
29
  def initialize(dependency:, credentials:, config_files: [])
19
30
  @dependency = dependency
20
31
  @credentials = credentials
21
32
  @config_files = config_files
22
33
  end
23
34
 
35
+ sig { returns(T::Array[T::Hash[Symbol, String]]) }
24
36
  def dependency_urls
25
37
  find_dependency_urls
26
38
  end
27
39
 
40
+ sig { returns(T::Array[T::Hash[Symbol, String]]) }
28
41
  def known_repositories
29
42
  return @known_repositories if @known_repositories
30
43
 
31
- @known_repositories = []
44
+ @known_repositories ||= T.let([], T.nilable(T::Array[T::Hash[Symbol, String]]))
32
45
  @known_repositories += credential_repositories
33
46
  @known_repositories += config_file_repositories
34
47
 
@@ -40,6 +53,7 @@ module Dependabot
40
53
  @known_repositories.uniq
41
54
  end
42
55
 
56
+ sig { params(dependency_name: String).returns(T::Hash[Symbol, T.untyped]) }
43
57
  def self.get_default_repository_details(dependency_name)
44
58
  {
45
59
  base_url: "https://api.nuget.org/v3-flatcontainer/",
@@ -56,21 +70,33 @@ module Dependabot
56
70
 
57
71
  private
58
72
 
59
- attr_reader :dependency, :credentials, :config_files
73
+ sig { returns(Dependabot::Dependency) }
74
+ attr_reader :dependency
75
+
76
+ sig { returns(T::Array[Dependabot::Credential]) }
77
+ attr_reader :credentials
78
+
79
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
80
+ attr_reader :config_files
60
81
 
82
+ sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
61
83
  def find_dependency_urls
62
84
  @find_dependency_urls ||=
63
- known_repositories.flat_map do |details|
64
- if details.fetch(:url) == DEFAULT_REPOSITORY_URL
65
- # Save a request for the default URL, since we already know how
66
- # it addresses packages
67
- next default_repository_details
68
- end
85
+ T.let(
86
+ known_repositories.flat_map do |details|
87
+ if details.fetch(:url) == DEFAULT_REPOSITORY_URL
88
+ # Save a request for the default URL, since we already know how
89
+ # it addresses packages
90
+ next default_repository_details
91
+ end
69
92
 
70
- build_url_for_details(details)
71
- end.compact.uniq
93
+ build_url_for_details(details)
94
+ end.compact.uniq,
95
+ T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
96
+ )
72
97
  end
73
98
 
99
+ sig { params(repo_details: T::Hash[Symbol, T.untyped]).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
74
100
  def build_url_for_details(repo_details)
75
101
  url = repo_details.fetch(:url)
76
102
  url_obj = URI.parse(url)
@@ -86,6 +112,7 @@ module Dependabot
86
112
  details
87
113
  end
88
114
 
115
+ sig { params(repo_details: T::Hash[Symbol, T.untyped]).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
89
116
  def build_url_for_details_remote(repo_details)
90
117
  response = get_repo_metadata(repo_details)
91
118
  check_repo_response(response, repo_details)
@@ -118,11 +145,12 @@ module Dependabot
118
145
 
119
146
  details
120
147
  rescue JSON::ParserError
121
- build_v2_url(response, repo_details)
148
+ build_v2_url(T.must(response), repo_details)
122
149
  rescue Excon::Error::Timeout, Excon::Error::Socket
123
150
  handle_timeout(repo_metadata_url: repo_details.fetch(:url))
124
151
  end
125
152
 
153
+ sig { params(repo_details: T::Hash[Symbol, T.untyped]).returns(Excon::Response) }
126
154
  def get_repo_metadata(repo_details)
127
155
  url = repo_details.fetch(:url)
128
156
  cache = CacheManager.cache("repo_finder_metadatacache")
@@ -138,6 +166,7 @@ module Dependabot
138
166
  end
139
167
  end
140
168
 
169
+ sig { params(metadata: T::Hash[String, T::Array[T::Hash[String, T.untyped]]]).returns(T.nilable(String)) }
141
170
  def base_url_from_v3_metadata(metadata)
142
171
  metadata
143
172
  .fetch("resources", [])
@@ -145,6 +174,7 @@ module Dependabot
145
174
  &.fetch("@id")
146
175
  end
147
176
 
177
+ sig { params(metadata: T::Hash[String, T::Array[T::Hash[String, T.untyped]]]).returns(T.nilable(String)) }
148
178
  def registration_url_from_v3_metadata(metadata)
149
179
  allowed_registration_types = %w(
150
180
  RegistrationsBaseUrl
@@ -159,6 +189,7 @@ module Dependabot
159
189
  &.fetch("@id")
160
190
  end
161
191
 
192
+ sig { params(metadata: T::Hash[String, T::Array[T::Hash[String, T.untyped]]]).returns(T.nilable(String)) }
162
193
  def search_url_from_v3_metadata(metadata)
163
194
  # allowable values from here: https://learn.microsoft.com/en-us/nuget/api/search-query-service-resource#versioning
164
195
  allowed_search_types = %w(
@@ -173,6 +204,13 @@ module Dependabot
173
204
  &.fetch("@id")
174
205
  end
175
206
 
207
+ sig do
208
+ params(
209
+ response: Excon::Response,
210
+ repo_details: T::Hash[Symbol, T.untyped]
211
+ )
212
+ .returns(T::Hash[Symbol, T.untyped])
213
+ end
176
214
  def build_v2_url(response, repo_details)
177
215
  doc = Nokogiri::XML(response.body)
178
216
 
@@ -194,6 +232,7 @@ module Dependabot
194
232
  }
195
233
  end
196
234
 
235
+ sig { params(response: Excon::Response, details: T::Hash[Symbol, T.untyped]).void }
197
236
  def check_repo_response(response, details)
198
237
  return unless [401, 402, 403].include?(response.status)
199
238
  raise if details.fetch(:url) == DEFAULT_REPOSITORY_URL
@@ -201,19 +240,25 @@ module Dependabot
201
240
  raise PrivateSourceAuthenticationFailure, details.fetch(:url)
202
241
  end
203
242
 
243
+ sig { params(repo_metadata_url: String).returns(T.noreturn) }
204
244
  def handle_timeout(repo_metadata_url:)
205
245
  raise if repo_metadata_url == DEFAULT_REPOSITORY_URL
206
246
 
207
247
  raise PrivateSourceTimedOut, repo_metadata_url
208
248
  end
209
249
 
250
+ sig { returns(T::Array[T::Hash[Symbol, String]]) }
210
251
  def credential_repositories
211
252
  @credential_repositories ||=
212
- credentials
213
- .select { |cred| cred["type"] == "nuget_feed" && cred["url"] }
214
- .map { |c| { url: c.fetch("url"), token: c["token"] } }
253
+ T.let(
254
+ credentials
255
+ .select { |cred| cred["type"] == "nuget_feed" && cred["url"] }
256
+ .map { |c| { url: c.fetch("url"), token: c["token"] } },
257
+ T.nilable(T::Array[T::Hash[Symbol, String]])
258
+ )
215
259
  end
216
260
 
261
+ sig { returns(T::Array[T::Hash[Symbol, String]]) }
217
262
  def config_file_repositories
218
263
  config_files.flat_map { |file| repos_from_config_file(file) }
219
264
  end
@@ -222,13 +267,14 @@ module Dependabot
222
267
  # rubocop:disable Metrics/PerceivedComplexity
223
268
  # rubocop:disable Metrics/MethodLength
224
269
  # rubocop:disable Metrics/AbcSize
270
+ sig { params(config_file: Dependabot::DependencyFile).returns(T::Array[T::Hash[Symbol, String]]) }
225
271
  def repos_from_config_file(config_file)
226
272
  doc = Nokogiri::XML(config_file.content)
227
273
  doc.remove_namespaces!
228
274
  # analogous to having a root config with the default repository
229
275
  base_sources = [{ url: DEFAULT_REPOSITORY_URL, key: "nuget.org" }]
230
276
 
231
- sources = []
277
+ sources = T.let([], T::Array[T::Hash[Symbol, String]])
232
278
 
233
279
  # regular package sources
234
280
  doc.css("configuration > packageSources").children.each do |node|
@@ -269,6 +315,23 @@ module Dependabot
269
315
  known_urls.include?(s.fetch(:url))
270
316
  end
271
317
 
318
+ # filter out based on packageSourceMapping
319
+ package_mapping_elements = doc.xpath("/configuration/packageSourceMapping/packageSource/package[@pattern]")
320
+ matching_package_elements = package_mapping_elements.select do |package_element|
321
+ pattern = package_element.attribute("pattern").value
322
+
323
+ # reusing this function for a case insensitive GLOB pattern patch (e.g., "Microsoft.Azure.*")
324
+ File.fnmatch(pattern, @dependency.name, File::FNM_CASEFOLD)
325
+ end
326
+ longest_matching_package_element = matching_package_elements.max_by do |package_element|
327
+ package_element.attribute("pattern").value.length
328
+ end
329
+ matching_key = longest_matching_package_element&.parent&.attribute("key")&.value
330
+ if matching_key
331
+ # found a matching source, only keep that one
332
+ sources.select! { |s| s.fetch(:key) == matching_key }
333
+ end
334
+
272
335
  add_config_file_credentials(sources: sources, doc: doc)
273
336
  sources.each { |details| details.delete(:key) }
274
337
 
@@ -279,11 +342,13 @@ module Dependabot
279
342
  # rubocop:enable Metrics/PerceivedComplexity
280
343
  # rubocop:enable Metrics/CyclomaticComplexity
281
344
 
345
+ sig { returns(T::Hash[Symbol, T.untyped]) }
282
346
  def default_repository_details
283
347
  RepositoryFinder.get_default_repository_details(dependency.name)
284
348
  end
285
349
 
286
350
  # rubocop:disable Metrics/PerceivedComplexity
351
+ sig { params(doc: Nokogiri::XML::Document).returns(T::Array[String]) }
287
352
  def disabled_sources(doc)
288
353
  doc.css("configuration > disabledPackageSources > add").filter_map do |node|
289
354
  value = node.attribute("value")&.value ||
@@ -298,6 +363,13 @@ module Dependabot
298
363
  # rubocop:enable Metrics/PerceivedComplexity
299
364
 
300
365
  # rubocop:disable Metrics/PerceivedComplexity
366
+ sig do
367
+ params(
368
+ sources: T::Array[T::Hash[Symbol, T.nilable(String)]],
369
+ doc: Nokogiri::XML::Document
370
+ )
371
+ .void
372
+ end
301
373
  def add_config_file_credentials(sources:, doc:)
302
374
  sources.each do |source_details|
303
375
  key = source_details.fetch(:key)
@@ -329,11 +401,10 @@ module Dependabot
329
401
  # Any non-ascii characters in the tag with cause a syntax error
330
402
  next source_details[:token] = nil
331
403
  end
332
-
333
- sources
334
404
  end
335
405
  # rubocop:enable Metrics/PerceivedComplexity
336
406
 
407
+ sig { params(string: String).returns(String) }
337
408
  def expand_windows_style_environment_variables(string)
338
409
  # NuGet.Config files can have Windows-style environment variables that need to be replaced
339
410
  # https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file#using-environment-variables
@@ -352,6 +423,7 @@ module Dependabot
352
423
  end
353
424
  end
354
425
 
426
+ sig { params(token: T.nilable(String)).returns(T::Hash[String, String]) }
355
427
  def auth_header_for_token(token)
356
428
  return {} unless token
357
429
 
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  #######################################################################
@@ -6,6 +6,8 @@
6
6
  # https://docs.microsoft.com/en-us/nuget/reference/package-versioning #
7
7
  #######################################################################
8
8
 
9
+ require "sorbet-runtime"
10
+
9
11
  require "dependabot/update_checkers/base"
10
12
  require "dependabot/nuget/version"
11
13
 
@@ -13,14 +15,25 @@ module Dependabot
13
15
  module Nuget
14
16
  class UpdateChecker < Dependabot::UpdateCheckers::Base
15
17
  class RequirementsUpdater
18
+ extend T::Sig
19
+
20
+ sig do
21
+ params(
22
+ requirements: T::Array[T::Hash[Symbol, T.untyped]],
23
+ latest_version: T.nilable(T.any(String, Dependabot::Nuget::Version)),
24
+ source_details: T.nilable(T::Hash[Symbol, T.untyped])
25
+ )
26
+ .void
27
+ end
16
28
  def initialize(requirements:, latest_version:, source_details:)
17
29
  @requirements = requirements
18
30
  @source_details = source_details
19
31
  return unless latest_version
20
32
 
21
- @latest_version = version_class.new(latest_version)
33
+ @latest_version = T.let(version_class.new(latest_version), Dependabot::Nuget::Version)
22
34
  end
23
35
 
36
+ sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
24
37
  def updated_requirements
25
38
  return requirements unless latest_version
26
39
 
@@ -52,32 +65,42 @@ module Dependabot
52
65
 
53
66
  private
54
67
 
55
- attr_reader :requirements, :latest_version, :source_details
68
+ sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
69
+ attr_reader :requirements
70
+
71
+ sig { returns(T.nilable(Dependabot::Nuget::Version)) }
72
+ attr_reader :latest_version
73
+
74
+ sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
75
+ attr_reader :source_details
56
76
 
77
+ sig { returns(T.class_of(Dependabot::Nuget::Version)) }
57
78
  def version_class
58
- Nuget::Version
79
+ Dependabot::Nuget::Version
59
80
  end
60
81
 
82
+ sig { params(req_string: String).returns(String) }
61
83
  def update_wildcard_requirement(req_string)
62
84
  return req_string if req_string == "*-*"
63
85
 
64
86
  return req_string if req_string == "*"
65
87
 
66
- precision = req_string.split("*").first.split(/\.|\-/).count
88
+ precision = T.must(req_string.split("*").first).split(/\.|\-/).count
67
89
  wildcard_section = req_string.partition(/(?=[.\-]\*)/).last
68
90
 
69
- version_parts = latest_version.segments.first(precision)
91
+ version_parts = T.must(latest_version).segments.first(precision)
70
92
  version = version_parts.join(".")
71
93
 
72
94
  version + wildcard_section
73
95
  end
74
96
 
97
+ sig { returns(T::Hash[Symbol, T.untyped]) }
75
98
  def updated_source
76
99
  {
77
100
  type: "nuget_repo",
78
- url: source_details.fetch(:repo_url),
79
- nuspec_url: source_details.fetch(:nuspec_url),
80
- source_url: source_details.fetch(:source_url)
101
+ url: source_details&.fetch(:repo_url),
102
+ nuspec_url: source_details&.fetch(:nuspec_url),
103
+ source_url: source_details&.fetch(:source_url)
81
104
  }
82
105
  end
83
106
  end
@@ -1,6 +1,8 @@
1
- # typed: true
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
5
+
4
6
  require "dependabot/update_checkers/base"
5
7
  require "dependabot/nuget/version"
6
8
  require "dependabot/nuget/requirement"
@@ -10,19 +12,22 @@ require "dependabot/shared_helpers"
10
12
  module Dependabot
11
13
  module Nuget
12
14
  class TfmComparer
15
+ extend T::Sig
16
+
17
+ sig { params(project_tfms: T::Array[String], package_tfms: T::Array[String]).returns(T::Boolean) }
13
18
  def self.are_frameworks_compatible?(project_tfms, package_tfms)
14
19
  return false if package_tfms.empty?
15
20
  return false if project_tfms.empty?
16
21
 
17
22
  key = "project_ftms:#{project_tfms.sort.join(',')}:package_tfms:#{package_tfms.sort.join(',')}".downcase
18
23
 
19
- @cached_framework_check ||= {}
24
+ @cached_framework_check ||= T.let({}, T.nilable(T::Hash[String, T::Boolean]))
20
25
  unless @cached_framework_check.key?(key)
21
26
  @cached_framework_check[key] =
22
27
  NativeHelpers.run_nuget_framework_check(project_tfms,
23
28
  package_tfms)
24
29
  end
25
- @cached_framework_check[key]
30
+ T.must(@cached_framework_check[key])
26
31
  end
27
32
  end
28
33
  end
@@ -1,8 +1,9 @@
1
- # typed: true
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "excon"
5
5
  require "nokogiri"
6
+ require "sorbet-runtime"
6
7
 
7
8
  require "dependabot/update_checkers/base"
8
9
  require "dependabot/nuget/version"
@@ -13,15 +14,25 @@ require "dependabot/shared_helpers"
13
14
  module Dependabot
14
15
  module Nuget
15
16
  class TfmFinder
17
+ extend T::Sig
18
+
16
19
  require "dependabot/nuget/file_parser/packages_config_parser"
17
20
  require "dependabot/nuget/file_parser/project_file_parser"
18
21
 
22
+ sig do
23
+ params(
24
+ dependency_files: T::Array[Dependabot::DependencyFile],
25
+ credentials: T::Array[Dependabot::Credential],
26
+ repo_contents_path: T.nilable(String)
27
+ ).void
28
+ end
19
29
  def initialize(dependency_files:, credentials:, repo_contents_path:)
20
30
  @dependency_files = dependency_files
21
31
  @credentials = credentials
22
32
  @repo_contents_path = repo_contents_path
23
33
  end
24
34
 
35
+ sig { params(dependency: Dependabot::Dependency).returns(T::Array[String]) }
25
36
  def frameworks(dependency)
26
37
  tfms = Set.new
27
38
  tfms += project_file_tfms(dependency)
@@ -31,14 +42,23 @@ module Dependabot
31
42
 
32
43
  private
33
44
 
34
- attr_reader :dependency_files, :credentials, :repo_contents_path
45
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
46
+ attr_reader :dependency_files
47
+
48
+ sig { returns(T::Array[Dependabot::Credential]) }
49
+ attr_reader :credentials
50
+
51
+ sig { returns(T.nilable(String)) }
52
+ attr_reader :repo_contents_path
35
53
 
54
+ sig { params(dependency: Dependabot::Dependency).returns(T::Array[String]) }
36
55
  def project_file_tfms(dependency)
37
56
  project_files_with_dependency(dependency).flat_map do |file|
38
57
  project_file_parser.target_frameworks(project_file: file)
39
58
  end
40
59
  end
41
60
 
61
+ sig { params(dependency: Dependabot::Dependency).returns(T::Array[Dependabot::DependencyFile]) }
42
62
  def project_files_with_dependency(dependency)
43
63
  project_files.select do |file|
44
64
  packages_config_contains_dependency?(file, dependency) ||
@@ -46,6 +66,7 @@ module Dependabot
46
66
  end
47
67
  end
48
68
 
69
+ sig { params(file: Dependabot::DependencyFile, dependency: Dependabot::Dependency).returns(T::Boolean) }
49
70
  def packages_config_contains_dependency?(file, dependency)
50
71
  config_file = find_packages_config_file(file)
51
72
  return false unless config_file
@@ -56,36 +77,48 @@ module Dependabot
56
77
  end
57
78
  end
58
79
 
80
+ sig { params(file: Dependabot::DependencyFile, dependency: Dependabot::Dependency).returns(T::Boolean) }
59
81
  def project_file_contains_dependency?(file, dependency)
60
82
  project_file_parser.dependency_set(project_file: file).dependencies.any? do |d|
61
83
  d.name.casecmp(dependency.name)&.zero?
62
84
  end
63
85
  end
64
86
 
87
+ sig { params(file: Dependabot::DependencyFile).returns(T.nilable(Dependabot::DependencyFile)) }
65
88
  def find_packages_config_file(file)
66
89
  return file if file.name.end_with?("packages.config")
67
90
 
68
91
  filename = File.basename(file.name)
69
92
  search_path = file.name.sub(filename, "packages.config")
70
93
 
71
- dependency_files.find { |f| f.name.casecmp(search_path).zero? }
94
+ dependency_files.find { |f| f.name.casecmp(search_path)&.zero? }
72
95
  end
73
96
 
97
+ sig { returns(T::Array[String]) }
74
98
  def project_import_file_tfms
75
- @project_import_file_tfms ||= project_import_files.flat_map do |file|
76
- project_file_parser.target_frameworks(project_file: file)
77
- end
99
+ @project_import_file_tfms ||=
100
+ T.let(
101
+ project_import_files.flat_map do |file|
102
+ project_file_parser.target_frameworks(project_file: file)
103
+ end,
104
+ T.nilable(T::Array[String])
105
+ )
78
106
  end
79
107
 
108
+ sig { returns(FileParser::ProjectFileParser) }
80
109
  def project_file_parser
81
110
  @project_file_parser ||=
82
- FileParser::ProjectFileParser.new(
83
- dependency_files: dependency_files,
84
- credentials: credentials,
85
- repo_contents_path: repo_contents_path
111
+ T.let(
112
+ FileParser::ProjectFileParser.new(
113
+ dependency_files: dependency_files,
114
+ credentials: credentials,
115
+ repo_contents_path: repo_contents_path
116
+ ),
117
+ T.nilable(FileParser::ProjectFileParser)
86
118
  )
87
119
  end
88
120
 
121
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
89
122
  def project_files
90
123
  projfile = /\.[a-z]{2}proj$/
91
124
  packageprops = /[Dd]irectory.[Pp]ackages.props/
@@ -96,12 +129,14 @@ module Dependabot
96
129
  end
97
130
  end
98
131
 
132
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
99
133
  def packages_config_files
100
134
  dependency_files.select do |f|
101
- f.name.split("/").last.casecmp("packages.config").zero?
135
+ f.name.split("/").last&.casecmp("packages.config")&.zero?
102
136
  end
103
137
  end
104
138
 
139
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
105
140
  def project_import_files
106
141
  dependency_files -
107
142
  project_files -
@@ -111,16 +146,19 @@ module Dependabot
111
146
  [dotnet_tools_json]
112
147
  end
113
148
 
149
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
114
150
  def nuget_configs
115
151
  dependency_files.select { |f| f.name.match?(/nuget\.config$/i) }
116
152
  end
117
153
 
154
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
118
155
  def global_json
119
- dependency_files.find { |f| f.name.casecmp("global.json").zero? }
156
+ dependency_files.find { |f| f.name.casecmp("global.json")&.zero? }
120
157
  end
121
158
 
159
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
122
160
  def dotnet_tools_json
123
- dependency_files.find { |f| f.name.casecmp(".config/dotnet-tools.json").zero? }
161
+ dependency_files.find { |f| f.name.casecmp(".config/dotnet-tools.json")&.zero? }
124
162
  end
125
163
  end
126
164
  end