dependabot-nuget 0.245.0 → 0.247.0

Sign up to get free protection for your applications and to get access to all the features.
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