dependabot-nuget 0.248.0 → 0.250.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +57 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +26 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +31 -0
- data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +1 -0
- data/lib/dependabot/nuget/file_fetcher/sln_project_paths_finder.rb +2 -0
- data/lib/dependabot/nuget/file_parser/dotnet_tools_json_parser.rb +1 -0
- data/lib/dependabot/nuget/file_parser/global_json_parser.rb +1 -0
- data/lib/dependabot/nuget/file_parser/packages_config_parser.rb +1 -0
- data/lib/dependabot/nuget/file_parser/project_file_parser.rb +1 -0
- data/lib/dependabot/nuget/file_parser/property_value_finder.rb +2 -0
- data/lib/dependabot/nuget/file_parser.rb +32 -11
- data/lib/dependabot/nuget/file_updater/property_value_updater.rb +1 -0
- data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +28 -7
- data/lib/dependabot/nuget/update_checker/dependency_finder.rb +70 -19
- data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +1 -1
- data/lib/dependabot/nuget/update_checker/property_updater.rb +108 -44
- data/lib/dependabot/nuget/update_checker/repository_finder.rb +90 -18
- data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +8 -3
- data/lib/dependabot/nuget/update_checker/tfm_finder.rb +51 -13
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 144460a4e43c2169e3526841828a5a3baa717f83e0becb327f128cb971a3deb8
|
4
|
+
data.tar.gz: 1fdb2e2284043c4c27eb536dbbc0eaef6d180a59c61e6c32c2a74f4aadfb9a85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d1c53febbc055e0eeecbff13cb9101c17f0b989b039caa719baf2cf6a69e4fc43f8babbe7e533cf75baeb97dd3d58e7344a1ede890410a4c5046ab7951fd2f3
|
7
|
+
data.tar.gz: 285ed503fcefca8cd3ed0d731f59543c76eca79b0da7c738ae1bef523521697c5ee05fcc0c2d8425d86e8c657d1b579464822f359699ed67ca01077d27eb5972
|
@@ -3,6 +3,8 @@ using System.IO;
|
|
3
3
|
using System.Text;
|
4
4
|
using System.Threading.Tasks;
|
5
5
|
|
6
|
+
using NuGetUpdater.Core;
|
7
|
+
using NuGetUpdater.Core.Test;
|
6
8
|
using NuGetUpdater.Core.Test.Update;
|
7
9
|
|
8
10
|
using Xunit;
|
@@ -291,6 +293,61 @@ public partial class EntryPointTests
|
|
291
293
|
);
|
292
294
|
}
|
293
295
|
|
296
|
+
[Fact]
|
297
|
+
public async Task UpdaterDoesNotUseRepoGlobalJsonForMSBuildTasks()
|
298
|
+
{
|
299
|
+
// This is a _very_ specific scenario where the `NuGetUpdater.Cli` tool might pick up a `global.json` from
|
300
|
+
// the root of the repo under test and use it's `sdk` property when trying to locate MSBuild. To properly
|
301
|
+
// test this, it must be tested in a new process where MSBuild has not been loaded yet and the runner tool
|
302
|
+
// must be started with its working directory at the test repo's root.
|
303
|
+
using var tempDir = new TemporaryDirectory();
|
304
|
+
await File.WriteAllTextAsync(Path.Join(tempDir.DirectoryPath, "global.json"), """
|
305
|
+
{
|
306
|
+
"sdk": {
|
307
|
+
"version": "99.99.99"
|
308
|
+
}
|
309
|
+
}
|
310
|
+
""");
|
311
|
+
await File.WriteAllTextAsync(Path.Join(tempDir.DirectoryPath, "project.csproj"), """
|
312
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
313
|
+
<PropertyGroup>
|
314
|
+
<TargetFramework>net8.0</TargetFramework>
|
315
|
+
</PropertyGroup>
|
316
|
+
<ItemGroup>
|
317
|
+
<PackageReference Include="Newtonsoft.Json" Version="7.0.1" />
|
318
|
+
</ItemGroup>
|
319
|
+
</Project>
|
320
|
+
""");
|
321
|
+
var executableName = $"NuGetUpdater.Cli{(Environment.OSVersion.Platform == PlatformID.Win32NT ? ".exe" : "")}";
|
322
|
+
var executableArgs = string.Join(" ",
|
323
|
+
[
|
324
|
+
"update",
|
325
|
+
"--repo-root",
|
326
|
+
tempDir.DirectoryPath,
|
327
|
+
"--solution-or-project",
|
328
|
+
Path.Join(tempDir.DirectoryPath, "project.csproj"),
|
329
|
+
"--dependency",
|
330
|
+
"Newtonsoft.Json",
|
331
|
+
"--new-version",
|
332
|
+
"13.0.1",
|
333
|
+
"--previous-version",
|
334
|
+
"7.0.1",
|
335
|
+
"--verbose"
|
336
|
+
]);
|
337
|
+
|
338
|
+
// verify base run
|
339
|
+
var (exitCode, output, error) = await ProcessEx.RunAsync(executableName, executableArgs, workingDirectory: tempDir.DirectoryPath);
|
340
|
+
Assert.True(exitCode == 0, $"Error running update on unsupported SDK.\nSTDOUT:\n{output}\nSTDERR:\n{error}");
|
341
|
+
|
342
|
+
// verify project update
|
343
|
+
var updatedProjectContents = await File.ReadAllTextAsync(Path.Join(tempDir.DirectoryPath, "project.csproj"));
|
344
|
+
Assert.Contains("13.0.1", updatedProjectContents);
|
345
|
+
|
346
|
+
// verify `global.json` untouched
|
347
|
+
var updatedGlobalJsonContents = await File.ReadAllTextAsync(Path.Join(tempDir.DirectoryPath, "global.json"));
|
348
|
+
Assert.Contains("99.99.99", updatedGlobalJsonContents);
|
349
|
+
}
|
350
|
+
|
294
351
|
private static async Task Run(Func<string, string[]> getArgs, (string Path, string Content)[] initialFiles, (string, string)[] expectedFiles)
|
295
352
|
{
|
296
353
|
var actualFiles = await RunUpdate(initialFiles, async path =>
|
@@ -231,7 +231,7 @@ internal static class SdkPackageUpdater
|
|
231
231
|
logger.Log($" Adding [{dependencyName}/{newDependencyVersion}] as a top-level package reference.");
|
232
232
|
|
233
233
|
// see https://learn.microsoft.com/nuget/consume-packages/install-use-packages-dotnet-cli
|
234
|
-
var (exitCode, _, _) = await ProcessEx.RunAsync("dotnet", $"add {projectPath} package {dependencyName} --version {newDependencyVersion}");
|
234
|
+
var (exitCode, _, _) = await ProcessEx.RunAsync("dotnet", $"add {projectPath} package {dependencyName} --version {newDependencyVersion}", workingDirectory: Path.GetDirectoryName(projectPath));
|
235
235
|
if (exitCode != 0)
|
236
236
|
{
|
237
237
|
logger.Log($" Transitive dependency [{dependencyName}/{newDependencyVersion}] was not added.");
|
@@ -41,9 +41,29 @@ internal static partial class MSBuildHelper
|
|
41
41
|
// Ensure MSBuild types are registered before calling a method that loads the types
|
42
42
|
if (!IsMSBuildRegistered)
|
43
43
|
{
|
44
|
-
var
|
45
|
-
|
46
|
-
|
44
|
+
var globalJsonPath = "global.json";
|
45
|
+
var tempGlobalJsonPath = globalJsonPath + Guid.NewGuid().ToString();
|
46
|
+
var globalJsonExists = File.Exists(globalJsonPath);
|
47
|
+
try
|
48
|
+
{
|
49
|
+
if (globalJsonExists)
|
50
|
+
{
|
51
|
+
Console.WriteLine("Temporarily removing `global.json` for MSBuild detection.");
|
52
|
+
File.Move(globalJsonPath, tempGlobalJsonPath);
|
53
|
+
}
|
54
|
+
|
55
|
+
var defaultInstance = MSBuildLocator.QueryVisualStudioInstances().First();
|
56
|
+
MSBuildPath = defaultInstance.MSBuildPath;
|
57
|
+
MSBuildLocator.RegisterInstance(defaultInstance);
|
58
|
+
}
|
59
|
+
finally
|
60
|
+
{
|
61
|
+
if (globalJsonExists)
|
62
|
+
{
|
63
|
+
Console.WriteLine("Restoring `global.json` after MSBuild detection.");
|
64
|
+
File.Move(tempGlobalJsonPath, globalJsonPath);
|
65
|
+
}
|
66
|
+
}
|
47
67
|
}
|
48
68
|
}
|
49
69
|
|
@@ -311,7 +331,7 @@ internal static partial class MSBuildHelper
|
|
311
331
|
try
|
312
332
|
{
|
313
333
|
var tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages);
|
314
|
-
var (exitCode, stdOut, stdErr) = await ProcessEx.RunAsync("dotnet", $"restore \"{tempProjectPath}\"");
|
334
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunAsync("dotnet", $"restore \"{tempProjectPath}\"", workingDirectory: tempDirectory.FullName);
|
315
335
|
|
316
336
|
// NU1608: Detected package version outside of dependency constraint
|
317
337
|
|
@@ -451,7 +471,7 @@ internal static partial class MSBuildHelper
|
|
451
471
|
{
|
452
472
|
var tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages);
|
453
473
|
|
454
|
-
var (exitCode, stdout, stderr) = await ProcessEx.RunAsync("dotnet", $"build \"{tempProjectPath}\" /t:_ReportDependencies");
|
474
|
+
var (exitCode, stdout, stderr) = await ProcessEx.RunAsync("dotnet", $"build \"{tempProjectPath}\" /t:_ReportDependencies", workingDirectory: tempDirectory.FullName);
|
455
475
|
|
456
476
|
if (exitCode == 0)
|
457
477
|
{
|
@@ -548,6 +568,7 @@ internal static partial class MSBuildHelper
|
|
548
568
|
var repoRootPathPrefix = repoRootPath.NormalizePathToUnix() + "/";
|
549
569
|
var buildFilesInRepo = buildFileList
|
550
570
|
.Where(f => f.StartsWith(repoRootPathPrefix, StringComparison.OrdinalIgnoreCase))
|
571
|
+
.Where(File.Exists)
|
551
572
|
.Distinct()
|
552
573
|
.ToArray();
|
553
574
|
var result = buildFilesInRepo
|
@@ -2497,5 +2497,36 @@ public partial class UpdateWorkerTests
|
|
2497
2497
|
"""
|
2498
2498
|
);
|
2499
2499
|
}
|
2500
|
+
|
2501
|
+
[Fact]
|
2502
|
+
public async Task ProcessingProjectWithAspireDoesNotFailEvenThoughWorkloadIsNotInstalled()
|
2503
|
+
{
|
2504
|
+
// enumerating the build files will fail if the Aspire workload is not installed; this test ensures we can
|
2505
|
+
// still process the update
|
2506
|
+
await TestUpdateForProject("Newtonsoft.Json", "7.0.1", "13.0.1",
|
2507
|
+
projectContents: """
|
2508
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
2509
|
+
<PropertyGroup>
|
2510
|
+
<TargetFramework>net8.0</TargetFramework>
|
2511
|
+
<IsAspireHost>true</IsAspireHost>
|
2512
|
+
</PropertyGroup>
|
2513
|
+
<ItemGroup>
|
2514
|
+
<PackageReference Include="Newtonsoft.Json" Version="7.0.1" />
|
2515
|
+
</ItemGroup>
|
2516
|
+
</Project>
|
2517
|
+
""",
|
2518
|
+
expectedProjectContents: """
|
2519
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
2520
|
+
<PropertyGroup>
|
2521
|
+
<TargetFramework>net8.0</TargetFramework>
|
2522
|
+
<IsAspireHost>true</IsAspireHost>
|
2523
|
+
</PropertyGroup>
|
2524
|
+
<ItemGroup>
|
2525
|
+
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
2526
|
+
</ItemGroup>
|
2527
|
+
</Project>
|
2528
|
+
"""
|
2529
|
+
);
|
2530
|
+
}
|
2500
2531
|
}
|
2501
2532
|
}
|
@@ -63,9 +63,18 @@ module Dependabot
|
|
63
63
|
def project_file_dependencies
|
64
64
|
dependency_set = DependencySet.new
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
project_files.each do |project_file|
|
67
|
+
tfms = project_file_parser.target_frameworks(project_file: project_file)
|
68
|
+
unless tfms.any?
|
69
|
+
Dependabot.logger.warn "Excluding project file '#{project_file.name}' due to unresolvable target framework"
|
70
|
+
next
|
71
|
+
end
|
72
|
+
|
73
|
+
dependency_set += project_file_parser.dependency_set(project_file: project_file)
|
74
|
+
end
|
75
|
+
|
76
|
+
proj_files.each do |proj_file|
|
77
|
+
dependency_set += project_file_parser.dependency_set(project_file: proj_file)
|
69
78
|
end
|
70
79
|
|
71
80
|
dependency_set
|
@@ -109,14 +118,21 @@ module Dependabot
|
|
109
118
|
)
|
110
119
|
end
|
111
120
|
|
121
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
122
|
+
def proj_files
|
123
|
+
projfile = /\.proj$/
|
124
|
+
|
125
|
+
dependency_files.select do |df|
|
126
|
+
df.name.match?(projfile)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
112
130
|
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
113
131
|
def project_files
|
114
|
-
|
115
|
-
packageprops = /[Dd]irectory.[Pp]ackages.props/
|
132
|
+
projectfile = /\.(cs|vb|fs)proj$/
|
116
133
|
|
117
134
|
dependency_files.select do |df|
|
118
|
-
df.name.match?(
|
119
|
-
df.name.match?(packageprops)
|
135
|
+
df.name.match?(projectfile)
|
120
136
|
end
|
121
137
|
end
|
122
138
|
|
@@ -144,19 +160,24 @@ module Dependabot
|
|
144
160
|
|
145
161
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
146
162
|
def global_json
|
147
|
-
dependency_files.find { |f| f.name.casecmp("global.json")
|
163
|
+
dependency_files.find { |f| f.name.casecmp?("global.json") }
|
148
164
|
end
|
149
165
|
|
150
166
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
151
167
|
def dotnet_tools_json
|
152
|
-
dependency_files.find { |f| f.name.casecmp(".config/dotnet-tools.json")
|
168
|
+
dependency_files.find { |f| f.name.casecmp?(".config/dotnet-tools.json") }
|
153
169
|
end
|
154
170
|
|
155
171
|
sig { override.void }
|
156
172
|
def check_required_files
|
157
|
-
|
173
|
+
if project_files.any? || proj_files.any? || packages_config_files.any? || global_json || dotnet_tools_json
|
174
|
+
return
|
175
|
+
end
|
158
176
|
|
159
|
-
raise
|
177
|
+
raise Dependabot::DependencyFileNotFound.new(
|
178
|
+
"*.(cs|vb|fs)proj, *.proj, packages.config, global.json, dotnet-tools.json",
|
179
|
+
"No project file, *.proj, packages.config, global.json, or dotnet-tools.json!"
|
180
|
+
)
|
160
181
|
end
|
161
182
|
end
|
162
183
|
end
|
@@ -1,22 +1,34 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
require "dependabot/update_checkers/base"
|
5
7
|
|
6
8
|
module Dependabot
|
7
9
|
module Nuget
|
8
10
|
class CompatibilityChecker
|
11
|
+
extend T::Sig
|
12
|
+
|
9
13
|
require_relative "nuspec_fetcher"
|
10
14
|
require_relative "nupkg_fetcher"
|
11
15
|
require_relative "tfm_finder"
|
12
16
|
require_relative "tfm_comparer"
|
13
17
|
|
18
|
+
sig do
|
19
|
+
params(
|
20
|
+
dependency_urls: T::Array[T::Hash[Symbol, String]],
|
21
|
+
dependency: Dependabot::Dependency,
|
22
|
+
tfm_finder: Dependabot::Nuget::TfmFinder
|
23
|
+
).void
|
24
|
+
end
|
14
25
|
def initialize(dependency_urls:, dependency:, tfm_finder:)
|
15
26
|
@dependency_urls = dependency_urls
|
16
27
|
@dependency = dependency
|
17
28
|
@tfm_finder = tfm_finder
|
18
29
|
end
|
19
30
|
|
31
|
+
sig { params(version: String).returns(T::Boolean) }
|
20
32
|
def compatible?(version)
|
21
33
|
nuspec_xml = NuspecFetcher.fetch_nuspec(dependency_urls, dependency.name, version)
|
22
34
|
return false unless nuspec_xml
|
@@ -32,15 +44,23 @@ module Dependabot
|
|
32
44
|
return true if package_tfms.nil?
|
33
45
|
return false if package_tfms.empty?
|
34
46
|
|
35
|
-
return false if project_tfms.nil? || project_tfms
|
47
|
+
return false if project_tfms.nil? || project_tfms&.empty?
|
36
48
|
|
37
|
-
TfmComparer.are_frameworks_compatible?(project_tfms, package_tfms)
|
49
|
+
TfmComparer.are_frameworks_compatible?(T.must(project_tfms), package_tfms)
|
38
50
|
end
|
39
51
|
|
40
52
|
private
|
41
53
|
|
42
|
-
|
54
|
+
sig { returns(T::Array[T::Hash[Symbol, String]]) }
|
55
|
+
attr_reader :dependency_urls
|
43
56
|
|
57
|
+
sig { returns(Dependabot::Dependency) }
|
58
|
+
attr_reader :dependency
|
59
|
+
|
60
|
+
sig { returns(Dependabot::Nuget::TfmFinder) }
|
61
|
+
attr_reader :tfm_finder
|
62
|
+
|
63
|
+
sig { params(nuspec_xml: Nokogiri::XML::Document).returns(T::Boolean) }
|
44
64
|
def pure_development_dependency?(nuspec_xml)
|
45
65
|
contents = nuspec_xml.at_xpath("package/metadata/developmentDependency")&.content&.strip
|
46
66
|
return false unless contents # no `developmentDependency` element
|
@@ -55,16 +75,17 @@ module Dependabot
|
|
55
75
|
dependency_groups_with_target_framework.to_a.empty?
|
56
76
|
end
|
57
77
|
|
78
|
+
sig { params(nuspec_xml: Nokogiri::XML::Document).returns(T::Array[String]) }
|
58
79
|
def parse_package_tfms(nuspec_xml)
|
59
80
|
nuspec_xml.xpath("//dependencies/group").filter_map { |group| group.attribute("targetFramework") }
|
60
81
|
end
|
61
82
|
|
83
|
+
sig { returns(T.nilable(T::Array[String])) }
|
62
84
|
def project_tfms
|
63
|
-
|
64
|
-
|
65
|
-
@project_tfms = tfm_finder.frameworks(dependency)
|
85
|
+
@project_tfms ||= T.let(tfm_finder.frameworks(dependency), T.nilable(T::Array[String]))
|
66
86
|
end
|
67
87
|
|
88
|
+
sig { params(dependency_version: String).returns(T.nilable(T::Array[String])) }
|
68
89
|
def fetch_package_tfms(dependency_version)
|
69
90
|
cache = CacheManager.cache("compatibility_checker_tfms_cache")
|
70
91
|
key = "#{dependency.name}::#{dependency_version}"
|
@@ -1,9 +1,11 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "nokogiri"
|
5
|
-
require "
|
5
|
+
require "sorbet-runtime"
|
6
6
|
require "stringio"
|
7
|
+
require "zip"
|
8
|
+
|
7
9
|
require "dependabot/update_checkers/base"
|
8
10
|
require "dependabot/nuget/version"
|
9
11
|
|
@@ -11,21 +13,34 @@ module Dependabot
|
|
11
13
|
module Nuget
|
12
14
|
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
13
15
|
class DependencyFinder
|
16
|
+
extend T::Sig
|
17
|
+
|
14
18
|
require_relative "requirements_updater"
|
15
19
|
require_relative "nuspec_fetcher"
|
16
20
|
|
21
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
17
22
|
def self.transitive_dependencies_cache
|
18
23
|
CacheManager.cache("dependency_finder_transitive_dependencies")
|
19
24
|
end
|
20
25
|
|
26
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
21
27
|
def self.updated_peer_dependencies_cache
|
22
28
|
CacheManager.cache("dependency_finder_updated_peer_dependencies")
|
23
29
|
end
|
24
30
|
|
31
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
25
32
|
def self.fetch_dependencies_cache
|
26
33
|
CacheManager.cache("dependency_finder_fetch_dependencies")
|
27
34
|
end
|
28
35
|
|
36
|
+
sig do
|
37
|
+
params(
|
38
|
+
dependency: Dependabot::Dependency,
|
39
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
40
|
+
credentials: T::Array[Dependabot::Credential],
|
41
|
+
repo_contents_path: T.nilable(String)
|
42
|
+
).void
|
43
|
+
end
|
29
44
|
def initialize(dependency:, dependency_files:, credentials:, repo_contents_path:)
|
30
45
|
@dependency = dependency
|
31
46
|
@dependency_files = dependency_files
|
@@ -33,6 +48,7 @@ module Dependabot
|
|
33
48
|
@repo_contents_path = repo_contents_path
|
34
49
|
end
|
35
50
|
|
51
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
36
52
|
def transitive_dependencies
|
37
53
|
key = "#{dependency.name.downcase}::#{dependency.version}"
|
38
54
|
cache = DependencyFinder.transitive_dependencies_cache
|
@@ -44,7 +60,7 @@ module Dependabot
|
|
44
60
|
|
45
61
|
cache[key] = fetch_transitive_dependencies(
|
46
62
|
@dependency.name,
|
47
|
-
@dependency.version
|
63
|
+
T.must(@dependency.version)
|
48
64
|
).map do |dependency_info|
|
49
65
|
package_name = dependency_info["packageName"]
|
50
66
|
target_version = dependency_info["version"]
|
@@ -65,13 +81,14 @@ module Dependabot
|
|
65
81
|
cache[key]
|
66
82
|
end
|
67
83
|
|
84
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
68
85
|
def updated_peer_dependencies
|
69
86
|
key = "#{dependency.name.downcase}::#{dependency.version}"
|
70
87
|
cache = DependencyFinder.updated_peer_dependencies_cache
|
71
88
|
|
72
89
|
cache[key] ||= fetch_transitive_dependencies(
|
73
90
|
@dependency.name,
|
74
|
-
@dependency.version
|
91
|
+
T.must(@dependency.version)
|
75
92
|
).filter_map do |dependency_info|
|
76
93
|
package_name = dependency_info["packageName"]
|
77
94
|
target_version = dependency_info["version"]
|
@@ -104,48 +121,79 @@ module Dependabot
|
|
104
121
|
|
105
122
|
private
|
106
123
|
|
107
|
-
|
124
|
+
sig { returns(Dependabot::Dependency) }
|
125
|
+
attr_reader :dependency
|
126
|
+
|
127
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
128
|
+
attr_reader :dependency_files
|
129
|
+
|
130
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
131
|
+
attr_reader :credentials
|
108
132
|
|
133
|
+
sig { returns(T.nilable(String)) }
|
134
|
+
attr_reader :repo_contents_path
|
135
|
+
|
136
|
+
sig do
|
137
|
+
params(
|
138
|
+
dep: Dependabot::Dependency,
|
139
|
+
target_version_details: T::Hash[Symbol, T.untyped]
|
140
|
+
)
|
141
|
+
.returns(T::Array[T::Hash[String, T.untyped]])
|
142
|
+
end
|
109
143
|
def updated_requirements(dep, target_version_details)
|
110
|
-
@updated_requirements ||= {}
|
144
|
+
@updated_requirements ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
|
111
145
|
@updated_requirements[dep.name] ||=
|
112
146
|
RequirementsUpdater.new(
|
113
147
|
requirements: dep.requirements,
|
114
148
|
latest_version: target_version_details.fetch(:version).to_s,
|
115
|
-
source_details: target_version_details
|
116
|
-
&.slice(:nuspec_url, :repo_url, :source_url)
|
149
|
+
source_details: target_version_details.slice(:nuspec_url, :repo_url, :source_url)
|
117
150
|
).updated_requirements
|
118
151
|
end
|
119
152
|
|
153
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
120
154
|
def top_level_dependencies
|
121
155
|
@top_level_dependencies ||=
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
156
|
+
T.let(
|
157
|
+
Nuget::FileParser.new(
|
158
|
+
dependency_files: dependency_files,
|
159
|
+
source: nil
|
160
|
+
).parse.select(&:top_level?),
|
161
|
+
T.nilable(T::Array[Dependabot::Dependency])
|
162
|
+
)
|
126
163
|
end
|
127
164
|
|
165
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
128
166
|
def nuget_configs
|
129
167
|
@nuget_configs ||=
|
130
|
-
|
168
|
+
T.let(
|
169
|
+
@dependency_files.select { |f| f.name.match?(/nuget\.config$/i) },
|
170
|
+
T.nilable(T::Array[Dependabot::DependencyFile])
|
171
|
+
)
|
131
172
|
end
|
132
173
|
|
174
|
+
sig { returns(T::Array[T::Hash[Symbol, String]]) }
|
133
175
|
def dependency_urls
|
134
176
|
@dependency_urls ||=
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
177
|
+
T.let(
|
178
|
+
RepositoryFinder.new(
|
179
|
+
dependency: @dependency,
|
180
|
+
credentials: @credentials,
|
181
|
+
config_files: nuget_configs
|
182
|
+
)
|
183
|
+
.dependency_urls
|
184
|
+
.select { |url| url.fetch(:repository_type) == "v3" },
|
185
|
+
T.nilable(T::Array[T::Hash[Symbol, String]])
|
186
|
+
)
|
141
187
|
end
|
142
188
|
|
189
|
+
sig { params(package_id: String, package_version: String).returns(T::Array[T::Hash[String, T.untyped]]) }
|
143
190
|
def fetch_transitive_dependencies(package_id, package_version)
|
144
191
|
all_dependencies = {}
|
145
192
|
fetch_transitive_dependencies_impl(package_id, package_version, all_dependencies)
|
146
193
|
all_dependencies.map { |_, dependency_info| dependency_info }
|
147
194
|
end
|
148
195
|
|
196
|
+
sig { params(package_id: String, package_version: String, all_dependencies: T::Hash[String, T.untyped]).void }
|
149
197
|
def fetch_transitive_dependencies_impl(package_id, package_version, all_dependencies)
|
150
198
|
dependencies = fetch_dependencies(package_id, package_version)
|
151
199
|
return unless dependencies.any?
|
@@ -175,6 +223,7 @@ module Dependabot
|
|
175
223
|
end
|
176
224
|
end
|
177
225
|
|
226
|
+
sig { params(package_id: String, package_version: String).returns(T::Array[T::Hash[String, T.untyped]]) }
|
178
227
|
def fetch_dependencies(package_id, package_version)
|
179
228
|
key = "#{package_id.downcase}::#{package_version}"
|
180
229
|
cache = DependencyFinder.fetch_dependencies_cache
|
@@ -191,6 +240,7 @@ module Dependabot
|
|
191
240
|
cache[key]
|
192
241
|
end
|
193
242
|
|
243
|
+
sig { params(nuspec_xml: Nokogiri::XML::Document).returns(T::Array[T::Hash[String, String]]) }
|
194
244
|
def read_dependencies_from_nuspec(nuspec_xml) # rubocop:disable Metrics/PerceivedComplexity
|
195
245
|
# we want to exclude development dependencies from the lookup
|
196
246
|
allowed_attributes = %w(all compile native runtime)
|
@@ -223,6 +273,7 @@ module Dependabot
|
|
223
273
|
dependency_list
|
224
274
|
end
|
225
275
|
|
276
|
+
sig { params(dep: Dependabot::Dependency).returns(Dependabot::Nuget::UpdateChecker::VersionFinder) }
|
226
277
|
def version_finder(dep)
|
227
278
|
VersionFinder.new(
|
228
279
|
dependency: dep,
|