dependabot-nuget 0.245.0 → 0.247.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +42 -7
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +164 -90
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +38 -2
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +92 -18
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +1 -1
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +27 -0
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +115 -14
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/{UpdateWorker.DirsProj.cs → UpdateWorkerTests.DirsProj.cs} +22 -24
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +66 -0
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +373 -83
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +117 -4
  13. data/lib/dependabot/nuget/cache_manager.rb +9 -3
  14. data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +15 -12
  15. data/lib/dependabot/nuget/file_fetcher/sln_project_paths_finder.rb +13 -3
  16. data/lib/dependabot/nuget/file_fetcher.rb +79 -31
  17. data/lib/dependabot/nuget/file_parser/dotnet_tools_json_parser.rb +10 -2
  18. data/lib/dependabot/nuget/file_parser/global_json_parser.rb +10 -2
  19. data/lib/dependabot/nuget/file_parser/packages_config_parser.rb +11 -2
  20. data/lib/dependabot/nuget/file_parser/project_file_parser.rb +140 -45
  21. data/lib/dependabot/nuget/file_parser/property_value_finder.rb +57 -5
  22. data/lib/dependabot/nuget/file_parser.rb +18 -4
  23. data/lib/dependabot/nuget/file_updater/property_value_updater.rb +25 -8
  24. data/lib/dependabot/nuget/file_updater.rb +74 -38
  25. data/lib/dependabot/nuget/http_response_helpers.rb +19 -0
  26. data/lib/dependabot/nuget/metadata_finder.rb +32 -4
  27. data/lib/dependabot/nuget/nuget_client.rb +31 -13
  28. data/lib/dependabot/nuget/requirement.rb +4 -1
  29. data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +26 -15
  30. data/lib/dependabot/nuget/update_checker/dependency_finder.rb +23 -13
  31. data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +83 -21
  32. data/lib/dependabot/nuget/update_checker/repository_finder.rb +29 -13
  33. data/lib/dependabot/nuget/update_checker/tfm_finder.rb +2 -2
  34. data/lib/dependabot/nuget/update_checker/version_finder.rb +15 -6
  35. data/lib/dependabot/nuget/update_checker.rb +6 -7
  36. data/lib/dependabot/nuget/version.rb +7 -2
  37. metadata +21 -7
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/SdkPackageUpdaterTests.cs +0 -317
@@ -36,7 +36,9 @@ public class MSBuildHelperTests
36
36
  };
37
37
 
38
38
  // Act
39
- var rootValue = MSBuildHelper.GetRootedValue(projectContents, propertyInfo);
39
+ var (resultType, evaluatedValue, _) = MSBuildHelper.GetEvaluatedValue(projectContents, propertyInfo);
40
+
41
+ Assert.Equal(MSBuildHelper.EvaluationResultType.Success, resultType);
40
42
 
41
43
  // Assert
42
44
  Assert.Equal("""
@@ -48,7 +50,7 @@ public class MSBuildHelperTests
48
50
  <PackageReference Include="Newtonsoft.Json" Version="1.1.1" />
49
51
  </ItemGroup>
50
52
  </Project>
51
- """, rootValue);
53
+ """, evaluatedValue);
52
54
  }
53
55
 
54
56
  [Fact(Timeout = 1000)]
@@ -74,10 +76,11 @@ public class MSBuildHelperTests
74
76
  await Task.Delay(1);
75
77
 
76
78
  // Act
77
- var ex = Assert.Throws<InvalidDataException>(() => MSBuildHelper.GetRootedValue(projectContents, propertyInfo));
79
+ var (resultType, _, errorMessage) = MSBuildHelper.GetEvaluatedValue(projectContents, propertyInfo);
78
80
 
79
81
  // Assert
80
- Assert.Equal("Property 'PackageVersion1' has a circular reference.", ex.Message);
82
+ Assert.Equal(MSBuildHelper.EvaluationResultType.CircularReference, resultType);
83
+ Assert.Equal("Property 'PackageVersion1' has a circular reference.", errorMessage);
81
84
  }
82
85
 
83
86
  [Theory]
@@ -316,6 +319,116 @@ public class MSBuildHelperTests
316
319
  Assert.Equal(expectedDependencies, actualDependencies);
317
320
  }
318
321
 
322
+ [Fact]
323
+ public async Task GetAllPackageDependencies_NugetConfigInvalid_DoesNotThrow()
324
+ {
325
+ var nugetPackagesDirectory = Environment.GetEnvironmentVariable("NUGET_PACKAGES");
326
+ var nugetHttpCacheDirectory = Environment.GetEnvironmentVariable("NUGET_HTTP_CACHE_PATH");
327
+
328
+ try
329
+ {
330
+ using var temp = new TemporaryDirectory();
331
+
332
+ // It is important to have empty NuGet caches for this test, so override them with temp directories.
333
+ var tempNuGetPackagesDirectory = Path.Combine(temp.DirectoryPath, ".nuget", "packages");
334
+ Environment.SetEnvironmentVariable("NUGET_PACKAGES", tempNuGetPackagesDirectory);
335
+ var tempNuGetHttpCacheDirectory = Path.Combine(temp.DirectoryPath, ".nuget", "v3-cache");
336
+ Environment.SetEnvironmentVariable("NUGET_HTTP_CACHE_PATH", tempNuGetHttpCacheDirectory);
337
+
338
+ // Write the NuGet.config with a missing "/>"
339
+ await File.WriteAllTextAsync(
340
+ Path.Combine(temp.DirectoryPath, "NuGet.Config"), """
341
+ <?xml version="1.0" encoding="utf-8"?>
342
+ <configuration>
343
+ <packageSources>
344
+ <clear />
345
+ <add key="contoso" value="https://contoso.com/v3/index.json"
346
+ </packageSources>
347
+ </configuration>
348
+ """);
349
+
350
+ // Asserting it didn't throw
351
+ var actualDependencies = await MSBuildHelper.GetAllPackageDependenciesAsync(
352
+ temp.DirectoryPath,
353
+ temp.DirectoryPath,
354
+ "netstandard2.0",
355
+ [new Dependency("Newtonsoft.Json", "4.5.11", DependencyType.Unknown)]
356
+ );
357
+ }
358
+ finally
359
+ {
360
+ // Restore the NuGet caches.
361
+ Environment.SetEnvironmentVariable("NUGET_PACKAGES", nugetPackagesDirectory);
362
+ Environment.SetEnvironmentVariable("NUGET_HTTP_CACHE_PATH", nugetHttpCacheDirectory);
363
+ }
364
+ }
365
+
366
+ [Fact]
367
+ public async Task GetAllPackageDependencies_LocalNuGetRepos_AreCopiedToTempProject()
368
+ {
369
+ // If we end up using this EnvVar pattern again I think it'd be worth it to abstract it out into an IDisposable.
370
+ var nugetPackagesDirectory = Environment.GetEnvironmentVariable("NUGET_PACKAGES");
371
+ var nugetHttpCacheDirectory = Environment.GetEnvironmentVariable("NUGET_HTTP_CACHE_PATH");
372
+ var logger = new Logger(verbose: true);
373
+ try
374
+ {
375
+ // First create a fake local nuget repository
376
+ using var restoreDir = new TemporaryDirectory();
377
+
378
+ var restoreNuGetPackagesDirectory = Path.Combine(restoreDir.DirectoryPath, ".nuget", "packages");
379
+ Environment.SetEnvironmentVariable("NUGET_PACKAGES", restoreNuGetPackagesDirectory);
380
+ var restoreNuGetHttpCacheDirectory = Path.Combine(restoreDir.DirectoryPath, ".nuget", "v3-cache");
381
+ Environment.SetEnvironmentVariable("NUGET_HTTP_CACHE_PATH", restoreNuGetHttpCacheDirectory);
382
+
383
+ using var temp = new TemporaryDirectory();
384
+ using (var restoreProjectTemp = new TemporaryDirectory())
385
+ {
386
+ // dotnet restore .csproj with things we want
387
+ await MSBuildHelper.DependenciesAreCoherentAsync(restoreProjectTemp.DirectoryPath, restoreProjectTemp.DirectoryPath, "netstandard2.0",
388
+ [new Dependency("Newtonsoft.Json", "4.5.11", DependencyType.Unknown)], logger);
389
+ Assert.True(Directory.Exists(restoreNuGetPackagesDirectory), "packages directory didn't exist");
390
+ PathHelper.CopyDirectory(restoreNuGetPackagesDirectory, Path.Combine(temp.DirectoryPath, "local_repo"));
391
+ }
392
+
393
+ // It is important to have empty NuGet caches for this test, so override them with temp directories.
394
+ var tempNuGetPackagesDirectory = Path.Combine(temp.DirectoryPath, ".nuget", "packages");
395
+ Environment.SetEnvironmentVariable("NUGET_PACKAGES", tempNuGetPackagesDirectory);
396
+ var tempNuGetHttpCacheDirectory = Path.Combine(temp.DirectoryPath, ".nuget", "v3-cache");
397
+ Environment.SetEnvironmentVariable("NUGET_HTTP_CACHE_PATH", tempNuGetHttpCacheDirectory);
398
+
399
+ // Write the NuGet.config.
400
+ await File.WriteAllTextAsync(
401
+ Path.Combine(temp.DirectoryPath, "NuGet.Config"), """
402
+ <?xml version="1.0" encoding="utf-8"?>
403
+ <configuration>
404
+ <packageSources>
405
+ <clear />
406
+ <add key="local-repo" value="local_repo" />
407
+ </packageSources>
408
+ </configuration>
409
+ """);
410
+ var expectedDependencies = new Dependency[]
411
+ {
412
+ new("Newtonsoft.Json", "4.5.11", DependencyType.Unknown),
413
+ new("NETStandard.Library", "2.0.3", DependencyType.Unknown),
414
+ };
415
+ var actualDependencies = await MSBuildHelper.GetAllPackageDependenciesAsync(
416
+ temp.DirectoryPath,
417
+ temp.DirectoryPath,
418
+ "netstandard2.0",
419
+ [new Dependency("Newtonsoft.Json", "4.5.11", DependencyType.Unknown)]
420
+ );
421
+ Assert.False(Directory.Exists(tempNuGetHttpCacheDirectory), "The .nuget/.v3-cache directory was created, meaning http was used.");
422
+ Assert.Equal(expectedDependencies, actualDependencies);
423
+ }
424
+ finally
425
+ {
426
+ // Restore the NuGet caches.
427
+ Environment.SetEnvironmentVariable("NUGET_PACKAGES", nugetPackagesDirectory);
428
+ Environment.SetEnvironmentVariable("NUGET_HTTP_CACHE_PATH", nugetHttpCacheDirectory);
429
+ }
430
+ }
431
+
319
432
  [Fact]
320
433
  public async Task AllPackageDependenciesCanBeFoundWithNuGetConfig()
321
434
  {
@@ -1,21 +1,27 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "set"
5
+ require "sorbet-runtime"
6
+
4
7
  require "dependabot/file_fetchers"
5
8
  require "dependabot/file_fetchers/base"
6
- require "set"
7
9
 
8
10
  module Dependabot
9
11
  module Nuget
10
12
  class CacheManager
13
+ extend T::Sig
14
+
15
+ sig { returns(T::Boolean) }
11
16
  def self.caching_disabled?
12
17
  ENV["DEPENDABOT_NUGET_CACHE_DISABLED"] == "true"
13
18
  end
14
19
 
20
+ sig { params(name: String).returns(T::Hash[String, T.untyped]) }
15
21
  def self.cache(name)
16
22
  return {} if caching_disabled?
17
23
 
18
- @cache ||= {}
24
+ @cache ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
19
25
  @cache[name] ||= {}
20
26
  @cache[name]
21
27
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "nokogiri"
@@ -10,24 +10,28 @@ module Dependabot
10
10
  module Nuget
11
11
  class FileFetcher
12
12
  class ImportPathsFinder
13
+ extend T::Sig
14
+ sig { params(project_file: T.untyped).void }
13
15
  def initialize(project_file:)
14
- @project_file = project_file
16
+ @project_file = T.let(project_file, Dependabot::DependencyFile)
15
17
  end
16
18
 
19
+ sig { returns(T::Array[String]) }
17
20
  def import_paths
18
- doc = Nokogiri::XML(project_file.content)
21
+ doc = T.let(Nokogiri::XML(project_file.content), Nokogiri::XML::Document)
19
22
  doc.remove_namespaces!
20
- doc.xpath("/Project/Import").map do |import_node|
23
+ doc.xpath("/Project/Import").filter_map do |import_node|
21
24
  path = import_node.attribute("Project").value.strip.tr("\\", "/")
22
25
  path = File.join(current_dir, path) unless current_dir.nil?
23
26
  Pathname.new(path).cleanpath.to_path
24
27
  end
25
28
  end
26
29
 
30
+ sig { returns(T::Array[String]) }
27
31
  def project_reference_paths
28
- doc = Nokogiri::XML(project_file.content)
32
+ doc = T.let(Nokogiri::XML(project_file.content), Nokogiri::XML::Document)
29
33
  doc.remove_namespaces!
30
- nodes = doc.xpath("/Project/ItemGroup/ProjectReference").map do |node|
34
+ doc.xpath("/Project/ItemGroup/ProjectReference").filter_map do |node|
31
35
  attribute = node.attribute("Include")
32
36
  next unless attribute
33
37
 
@@ -35,14 +39,13 @@ module Dependabot
35
39
  path = File.join(current_dir, path) unless current_dir.nil?
36
40
  Pathname.new(path).cleanpath.to_path
37
41
  end
38
-
39
- nodes.compact
40
42
  end
41
43
 
44
+ sig { returns(T::Array[String]) }
42
45
  def project_file_paths
43
- doc = Nokogiri::XML(project_file.content)
46
+ doc = T.let(Nokogiri::XML(project_file.content), Nokogiri::XML::Document)
44
47
  doc.remove_namespaces!
45
- nodes = doc.xpath("/Project/ItemGroup/ProjectFile").map do |node|
48
+ doc.xpath("/Project/ItemGroup/ProjectFile").filter_map do |node|
46
49
  attribute = node.attribute("Include")
47
50
  next unless attribute
48
51
 
@@ -50,14 +53,14 @@ module Dependabot
50
53
  path = File.join(current_dir, path) unless current_dir.nil?
51
54
  Pathname.new(path).cleanpath.to_path
52
55
  end
53
-
54
- nodes.compact
55
56
  end
56
57
 
57
58
  private
58
59
 
60
+ sig { returns(Dependabot::DependencyFile) }
59
61
  attr_reader :project_file
60
62
 
63
+ sig { returns(T.nilable(String)) }
61
64
  def current_dir
62
65
  current_dir = project_file.name.rpartition("/").first
63
66
  current_dir = nil if current_dir == ""
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "pathname"
@@ -8,19 +8,27 @@ module Dependabot
8
8
  module Nuget
9
9
  class FileFetcher
10
10
  class SlnProjectPathsFinder
11
+ extend T::Sig
12
+
13
+ sig { params(sln_file: Dependabot::DependencyFile).void }
11
14
  def initialize(sln_file:)
12
15
  @sln_file = sln_file
13
16
  end
14
17
 
18
+ sig { returns(T::Array[String]) }
15
19
  def project_paths
16
- paths = []
17
- sln_file_lines = sln_file.content.lines
20
+ paths = T.let([], T::Array[String])
21
+ return paths unless sln_file.content
22
+
23
+ sln_file_lines = T.must(sln_file.content).lines
18
24
 
19
25
  sln_file_lines.each do |line|
20
26
  next unless line.match?(/^\s*Project\(/)
21
27
  next unless line.split('"')[5]
22
28
 
23
29
  path = line.split('"')[5]
30
+ next unless path
31
+
24
32
  path = path.tr("\\", "/")
25
33
 
26
34
  # If the path doesn't have an extension it's probably a directory
@@ -35,8 +43,10 @@ module Dependabot
35
43
 
36
44
  private
37
45
 
46
+ sig { returns(Dependabot::DependencyFile) }
38
47
  attr_reader :sln_file
39
48
 
49
+ sig { returns(T.nilable(String)) }
40
50
  def current_dir
41
51
  current_dir = sln_file.name.rpartition("/").first
42
52
  current_dir = nil if current_dir == ""
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/file_fetchers"
@@ -18,6 +18,7 @@ module Dependabot
18
18
 
19
19
  BUILD_FILE_NAMES = /^Directory\.Build\.(props|targets)$/i # Directory.Build.props, Directory.Build.targets
20
20
 
21
+ sig { override.params(filenames: T::Array[String]).returns(T::Boolean) }
21
22
  def self.required_files_in?(filenames)
22
23
  return true if filenames.any? { |f| f.match?(/^packages\.config$/i) }
23
24
  return true if filenames.any? { |f| f.end_with?(".sln") }
@@ -27,12 +28,32 @@ module Dependabot
27
28
  filenames.any? { |name| name.match?(/\.[a-z]{2}proj$/) }
28
29
  end
29
30
 
31
+ sig { override.returns(String) }
30
32
  def self.required_files_message
31
33
  "Repo must contain a .proj file, .(cs|vb|fs)proj file, or a packages.config."
32
34
  end
33
35
 
36
+ sig do
37
+ params(
38
+ source: Dependabot::Source,
39
+ credentials: T::Array[Credential],
40
+ repo_contents_path: T.nilable(String),
41
+ options: T::Hash[String, String]
42
+ ).void
43
+ end
44
+ def initialize(source:, credentials:, repo_contents_path: nil, options: {})
45
+ super(source: source, credentials: credentials, repo_contents_path: repo_contents_path, options: options)
46
+
47
+ @sln_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
48
+ @sln_project_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
49
+ @project_files = T.let([], T::Array[Dependabot::DependencyFile])
50
+ @fetched_files = T.let({}, T::Hash[String, T::Array[Dependabot::DependencyFile]])
51
+ @nuget_config_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
52
+ @packages_config_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
53
+ end
54
+
34
55
  sig { override.returns(T::Array[DependencyFile]) }
35
- def fetch_files
56
+ def fetch_files # rubocop:disable Metrics/AbcSize
36
57
  fetched_files = []
37
58
  fetched_files += project_files
38
59
  fetched_files += directory_build_files
@@ -50,7 +71,7 @@ module Dependabot
50
71
  end
51
72
 
52
73
  if project_files.none? && packages_config_files.none?
53
- raise @missing_sln_project_file_errors.first if @missing_sln_project_file_errors&.any?
74
+ raise T.must(@missing_sln_project_file_errors.first) if @missing_sln_project_file_errors&.any?
54
75
 
55
76
  raise(
56
77
  Dependabot::DependencyFileNotFound,
@@ -63,8 +84,11 @@ module Dependabot
63
84
 
64
85
  private
65
86
 
87
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
66
88
  def project_files
67
- @project_files ||=
89
+ return @project_files if @project_files.any?
90
+
91
+ @project_files =
68
92
  begin
69
93
  project_files = []
70
94
  project_files += csproj_file
@@ -84,13 +108,14 @@ module Dependabot
84
108
  )
85
109
  end
86
110
 
111
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
87
112
  def packages_config_files
88
113
  return @packages_config_files if @packages_config_files
89
114
 
90
115
  candidate_paths =
91
116
  [*project_files.map { |f| File.dirname(f.name) }, "."].uniq
92
117
 
93
- @packages_config_files ||=
118
+ @packages_config_files =
94
119
  candidate_paths.filter_map do |dir|
95
120
  file = repo_contents(dir: dir)
96
121
  .find { |f| f.name.casecmp("packages.config").zero? }
@@ -99,6 +124,7 @@ module Dependabot
99
124
  end
100
125
 
101
126
  # rubocop:disable Metrics/PerceivedComplexity
127
+ sig { returns(T.nilable(T::Array[T.untyped])) }
102
128
  def sln_file_names
103
129
  sln_files = repo_contents.select { |f| f.name.end_with?(".sln") }
104
130
  src_dir = repo_contents.any? { |f| f.name == "src" && f.type == "dir" }
@@ -117,13 +143,15 @@ module Dependabot
117
143
  end
118
144
  # rubocop:enable Metrics/PerceivedComplexity
119
145
 
146
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
120
147
  def directory_build_files
121
- @directory_build_files ||= fetch_directory_build_files
148
+ @directory_build_files ||= T.let(fetch_directory_build_files, T.nilable(T::Array[Dependabot::DependencyFile]))
122
149
  end
123
150
 
151
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
124
152
  def fetch_directory_build_files
125
- attempted_dirs = []
126
- directory_build_files = []
153
+ attempted_dirs = T.let([], T::Array[Pathname])
154
+ directory_build_files = T.let([], T::Array[Dependabot::DependencyFile])
127
155
  directory_path = Pathname.new(directory)
128
156
 
129
157
  # find all build files (Directory.Build.props/.targets) relative to the given project file
@@ -145,12 +173,13 @@ module Dependabot
145
173
  directory_build_files
146
174
  end
147
175
 
176
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
148
177
  def sln_project_files
149
178
  return [] unless sln_files
150
179
 
151
180
  @sln_project_files ||=
152
181
  begin
153
- paths = sln_files.flat_map do |sln_file|
182
+ paths = T.must(sln_files).flat_map do |sln_file|
154
183
  SlnProjectPathsFinder
155
184
  .new(sln_file: sln_file)
156
185
  .project_paths
@@ -159,7 +188,7 @@ module Dependabot
159
188
  paths.filter_map do |path|
160
189
  fetch_file_from_host(path)
161
190
  rescue Dependabot::DependencyFileNotFound => e
162
- @missing_sln_project_file_errors ||= []
191
+ @missing_sln_project_file_errors ||= T.let([], T.nilable(T::Array[Dependabot::DependencyFileNotFound]))
163
192
  @missing_sln_project_file_errors << e
164
193
  # Don't worry about missing files too much for now (at least
165
194
  # until we start resolving properties)
@@ -168,35 +197,42 @@ module Dependabot
168
197
  end
169
198
  end
170
199
 
200
+ sig { returns(T.nilable(T::Array[Dependabot::DependencyFile])) }
171
201
  def sln_files
172
202
  return unless sln_file_names
173
203
 
174
204
  @sln_files ||=
175
205
  sln_file_names
176
- .map { |sln_file_name| fetch_file_from_host(sln_file_name) }
177
- .select { |file| file.content.valid_encoding? }
206
+ &.map { |sln_file_name| fetch_file_from_host(sln_file_name) }
207
+ &.select { |file| file.content&.valid_encoding? }
178
208
  end
179
209
 
210
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
180
211
  def csproj_file
181
- @csproj_file ||= find_and_fetch_with_suffix(".csproj")
212
+ @csproj_file ||= T.let(find_and_fetch_with_suffix(".csproj"), T.nilable(T::Array[Dependabot::DependencyFile]))
182
213
  end
183
214
 
215
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
184
216
  def vbproj_file
185
- @vbproj_file ||= find_and_fetch_with_suffix(".vbproj")
217
+ @vbproj_file ||= T.let(find_and_fetch_with_suffix(".vbproj"), T.nilable(T::Array[Dependabot::DependencyFile]))
186
218
  end
187
219
 
220
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
188
221
  def fsproj_file
189
- @fsproj_file ||= find_and_fetch_with_suffix(".fsproj")
222
+ @fsproj_file ||= T.let(find_and_fetch_with_suffix(".fsproj"), T.nilable(T::Array[Dependabot::DependencyFile]))
190
223
  end
191
224
 
225
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
192
226
  def proj_files
193
- @proj_files ||= find_and_fetch_with_suffix(".proj")
227
+ @proj_files ||= T.let(find_and_fetch_with_suffix(".proj"), T.nilable(T::Array[Dependabot::DependencyFile]))
194
228
  end
195
229
 
230
+ sig { params(suffix: String).returns(T::Array[Dependabot::DependencyFile]) }
196
231
  def find_and_fetch_with_suffix(suffix)
197
232
  repo_contents.select { |f| f.name.end_with?(suffix) }.map { |f| fetch_file_from_host(f.name) }
198
233
  end
199
234
 
235
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
200
236
  def nuget_config_files
201
237
  return @nuget_config_files if @nuget_config_files
202
238
 
@@ -206,8 +242,15 @@ module Dependabot
206
242
  @nuget_config_files
207
243
  end
208
244
 
245
+ sig do
246
+ params(
247
+ project_file: Dependabot::DependencyFile,
248
+ expected_file_name: String
249
+ )
250
+ .returns(T.nilable(Dependabot::DependencyFile))
251
+ end
209
252
  def named_file_up_tree_from_project_file(project_file, expected_file_name)
210
- found_expected_file = nil
253
+ found_expected_file = T.let(nil, T.nilable(Dependabot::DependencyFile))
211
254
  directory_path = Pathname.new(directory)
212
255
  full_project_dir = Pathname.new(project_file.directory).join(project_file.name).dirname
213
256
  full_project_dir.ascend.each do |base|
@@ -228,26 +271,25 @@ module Dependabot
228
271
  found_expected_file
229
272
  end
230
273
 
274
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
231
275
  def global_json
232
- return @global_json if defined?(@global_json)
233
-
234
- @global_json = fetch_file_if_present("global.json")
276
+ @global_json ||= T.let(fetch_file_if_present("global.json"), T.nilable(Dependabot::DependencyFile))
235
277
  end
236
278
 
279
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
237
280
  def dotnet_tools_json
238
- return @dotnet_tools_json if defined?(@dotnet_tools_json)
239
-
240
- @dotnet_tools_json = fetch_file_if_present(".config/dotnet-tools.json")
281
+ @dotnet_tools_json ||= T.let(fetch_file_if_present(".config/dotnet-tools.json"),
282
+ T.nilable(Dependabot::DependencyFile))
241
283
  end
242
284
 
285
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
243
286
  def packages_props
244
- return @packages_props if defined?(@packages_props)
245
-
246
- @packages_props = fetch_file_if_present("Packages.props")
287
+ @packages_props ||= T.let(fetch_file_if_present("Packages.props"), T.nilable(Dependabot::DependencyFile))
247
288
  end
248
289
 
290
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
249
291
  def imported_property_files
250
- imported_property_files = []
292
+ imported_property_files = T.let([], T::Array[Dependabot::DependencyFile])
251
293
 
252
294
  files = [*project_files, *directory_build_files]
253
295
 
@@ -263,18 +305,24 @@ module Dependabot
263
305
  imported_property_files
264
306
  end
265
307
 
308
+ sig do
309
+ params(
310
+ file: Dependabot::DependencyFile,
311
+ previously_fetched_files: T::Array[Dependabot::DependencyFile]
312
+ )
313
+ .returns(T::Array[Dependabot::DependencyFile])
314
+ end
266
315
  def fetch_imported_property_files(file:, previously_fetched_files:)
267
316
  file_id = file.directory + "/" + file.name
268
- @fetched_files ||= {}
269
317
  if @fetched_files[file_id]
270
- @fetched_files[file_id]
318
+ T.must(@fetched_files[file_id])
271
319
  else
272
320
  paths =
273
321
  ImportPathsFinder.new(project_file: file).import_paths +
274
322
  ImportPathsFinder.new(project_file: file).project_reference_paths +
275
323
  ImportPathsFinder.new(project_file: file).project_file_paths
276
324
 
277
- paths.flat_map do |path|
325
+ paths.filter_map do |path|
278
326
  next if previously_fetched_files.map(&:name).include?(path)
279
327
  next if file.name == path
280
328
  next if path.include?("$(")
@@ -290,7 +338,7 @@ module Dependabot
290
338
  # Don't worry about missing files too much for now (at least
291
339
  # until we start resolving properties)
292
340
  nil
293
- end.compact
341
+ end.flatten
294
342
  end
295
343
  end
296
344
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "json"
@@ -12,12 +12,17 @@ module Dependabot
12
12
  module Nuget
13
13
  class FileParser
14
14
  class DotNetToolsJsonParser
15
+ extend T::Sig
16
+
15
17
  require "dependabot/file_parsers/base/dependency_set"
16
18
 
19
+ sig { params(dotnet_tools_json: Dependabot::DependencyFile).void }
17
20
  def initialize(dotnet_tools_json:)
18
21
  @dotnet_tools_json = dotnet_tools_json
22
+ @parsed_dotnet_tools_json = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
19
23
  end
20
24
 
25
+ sig { returns(Dependabot::FileParsers::Base::DependencySet) }
21
26
  def dependency_set
22
27
  dependency_set = Dependabot::FileParsers::Base::DependencySet.new
23
28
 
@@ -48,11 +53,14 @@ module Dependabot
48
53
 
49
54
  private
50
55
 
56
+ sig { returns(Dependabot::DependencyFile) }
51
57
  attr_reader :dotnet_tools_json
52
58
 
59
+ sig { returns(T::Hash[String, T.untyped]) }
53
60
  def parsed_dotnet_tools_json
54
61
  # Remove BOM if present as JSON should be UTF-8
55
- @parsed_dotnet_tools_json ||= JSON.parse(dotnet_tools_json.content.delete_prefix("\uFEFF"))
62
+ content = T.must(dotnet_tools_json.content)
63
+ @parsed_dotnet_tools_json ||= JSON.parse(content.delete_prefix("\uFEFF"))
56
64
  rescue JSON::ParserError
57
65
  raise Dependabot::DependencyFileNotParseable, dotnet_tools_json.path
58
66
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "json"
@@ -12,12 +12,17 @@ module Dependabot
12
12
  module Nuget
13
13
  class FileParser
14
14
  class GlobalJsonParser
15
+ extend T::Sig
16
+
15
17
  require "dependabot/file_parsers/base/dependency_set"
16
18
 
19
+ sig { params(global_json: Dependabot::DependencyFile).void }
17
20
  def initialize(global_json:)
18
21
  @global_json = global_json
22
+ @parsed_global_json = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
19
23
  end
20
24
 
25
+ sig { returns(Dependabot::FileParsers::Base::DependencySet) }
21
26
  def dependency_set
22
27
  dependency_set = Dependabot::FileParsers::Base::DependencySet.new
23
28
 
@@ -45,11 +50,14 @@ module Dependabot
45
50
 
46
51
  private
47
52
 
53
+ sig { returns(Dependabot::DependencyFile) }
48
54
  attr_reader :global_json
49
55
 
56
+ sig { returns(T::Hash[String, T.untyped]) }
50
57
  def parsed_global_json
51
58
  # Remove BOM if present as JSON should be UTF-8
52
- @parsed_global_json ||= JSON.parse(global_json.content.delete_prefix("\uFEFF"))
59
+ content = T.must(global_json.content)
60
+ @parsed_global_json ||= JSON.parse(content.delete_prefix("\uFEFF"))
53
61
  rescue JSON::ParserError
54
62
  raise Dependabot::DependencyFileNotParseable, global_json.path
55
63
  end