dependabot-nuget 0.247.0 → 0.249.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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 +25 -5
- 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_fetcher.rb +12 -8
- 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 +42 -11
- data/lib/dependabot/nuget/file_updater/property_value_updater.rb +1 -0
- data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +10 -1
- data/lib/dependabot/nuget/requirement.rb +17 -8
- 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/nupkg_fetcher.rb +76 -8
- data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +25 -3
- 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/requirements_updater.rb +32 -9
- data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +8 -3
- data/lib/dependabot/nuget/update_checker/tfm_finder.rb +51 -13
- data/lib/dependabot/nuget/update_checker/version_finder.rb +167 -62
- data/lib/dependabot/nuget/update_checker.rb +73 -29
- 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: c23304dabfd9e4506478efc6188332716cc7ff097f8042b45c67bfda9cf1b6ae
|
4
|
+
data.tar.gz: 74f8d095b039666ca96e098913667e8c40552df5963187cf4ae66a86ac429ae1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 904dae0561b8288c0cc8b319269a6352cdfa1d4d443e01b052e99bf3294277523f1a227944a7787024a216ad1661a21647330e116f6e5a9c66d95cbd630d7f47
|
7
|
+
data.tar.gz: 75cff9a26706bc60d8f5423d8e096fe4b1a1ccf20c3bb3fff5a5c6428ac6cfdd3b58e0a9ce490a9fb6577e852bd59417917bde19ad3697ed8d76aa789bdb4591
|
@@ -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
|
{
|
@@ -25,7 +25,7 @@ module Dependabot
|
|
25
25
|
return true if filenames.any? { |f| f.match?("^src$") }
|
26
26
|
return true if filenames.any? { |f| f.end_with?(".proj") }
|
27
27
|
|
28
|
-
filenames.any? { |name| name.match?(/\.
|
28
|
+
filenames.any? { |name| name.match?(/\.(cs|vb|fs)proj$/) }
|
29
29
|
end
|
30
30
|
|
31
31
|
sig { override.returns(String) }
|
@@ -53,7 +53,7 @@ module Dependabot
|
|
53
53
|
end
|
54
54
|
|
55
55
|
sig { override.returns(T::Array[DependencyFile]) }
|
56
|
-
def fetch_files
|
56
|
+
def fetch_files
|
57
57
|
fetched_files = []
|
58
58
|
fetched_files += project_files
|
59
59
|
fetched_files += directory_build_files
|
@@ -73,10 +73,7 @@ module Dependabot
|
|
73
73
|
if project_files.none? && packages_config_files.none?
|
74
74
|
raise T.must(@missing_sln_project_file_errors.first) if @missing_sln_project_file_errors&.any?
|
75
75
|
|
76
|
-
|
77
|
-
Dependabot::DependencyFileNotFound,
|
78
|
-
File.join(directory, "<anything>.(cs|vb|fs)proj")
|
79
|
-
)
|
76
|
+
raise_dependency_file_not_found
|
80
77
|
end
|
81
78
|
|
82
79
|
fetched_files
|
@@ -102,9 +99,16 @@ module Dependabot
|
|
102
99
|
project_files
|
103
100
|
end
|
104
101
|
rescue Octokit::NotFound, Gitlab::Error::NotFound
|
102
|
+
raise_dependency_file_not_found
|
103
|
+
end
|
104
|
+
|
105
|
+
sig { returns(T.noreturn) }
|
106
|
+
def raise_dependency_file_not_found
|
105
107
|
raise(
|
106
|
-
Dependabot::DependencyFileNotFound
|
107
|
-
|
108
|
+
Dependabot::DependencyFileNotFound.new(
|
109
|
+
File.join(directory, "*.(sln|csproj|vbproj|fsproj|proj)"),
|
110
|
+
"Unable to find `*.sln`, `*.(cs|vb|fs)proj`, or `*.proj` in directory `#{directory}`"
|
111
|
+
)
|
108
112
|
)
|
109
113
|
end
|
110
114
|
|
@@ -44,6 +44,16 @@ module Dependabot
|
|
44
44
|
Dependabot.logger.warn "Dependency '#{d.name}' excluded due to unparsable version: #{d.version}"
|
45
45
|
end
|
46
46
|
|
47
|
+
dependency_info = dependencies.map do |d|
|
48
|
+
requirements_info = d.requirements.filter_map { |r| " file: #{r[:file]}, metadata: #{r[:metadata]}" }
|
49
|
+
.join("\n")
|
50
|
+
" name: #{d.name}, version: #{d.version}\n#{requirements_info}"
|
51
|
+
end.join("\n")
|
52
|
+
|
53
|
+
if dependencies.length.positive?
|
54
|
+
Dependabot.logger.info "The following dependencies were found:\n#{dependency_info}"
|
55
|
+
end
|
56
|
+
|
47
57
|
dependencies
|
48
58
|
end
|
49
59
|
|
@@ -53,9 +63,18 @@ module Dependabot
|
|
53
63
|
def project_file_dependencies
|
54
64
|
dependency_set = DependencySet.new
|
55
65
|
|
56
|
-
|
57
|
-
|
58
|
-
|
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)
|
59
78
|
end
|
60
79
|
|
61
80
|
dependency_set
|
@@ -99,14 +118,21 @@ module Dependabot
|
|
99
118
|
)
|
100
119
|
end
|
101
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
|
+
|
102
130
|
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
103
131
|
def project_files
|
104
|
-
|
105
|
-
packageprops = /[Dd]irectory.[Pp]ackages.props/
|
132
|
+
projectfile = /\.(cs|vb|fs)proj$/
|
106
133
|
|
107
134
|
dependency_files.select do |df|
|
108
|
-
df.name.match?(
|
109
|
-
df.name.match?(packageprops)
|
135
|
+
df.name.match?(projectfile)
|
110
136
|
end
|
111
137
|
end
|
112
138
|
|
@@ -134,19 +160,24 @@ module Dependabot
|
|
134
160
|
|
135
161
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
136
162
|
def global_json
|
137
|
-
dependency_files.find { |f| f.name.casecmp("global.json")
|
163
|
+
dependency_files.find { |f| f.name.casecmp?("global.json") }
|
138
164
|
end
|
139
165
|
|
140
166
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
141
167
|
def dotnet_tools_json
|
142
|
-
dependency_files.find { |f| f.name.casecmp(".config/dotnet-tools.json")
|
168
|
+
dependency_files.find { |f| f.name.casecmp?(".config/dotnet-tools.json") }
|
143
169
|
end
|
144
170
|
|
145
171
|
sig { override.void }
|
146
172
|
def check_required_files
|
147
|
-
|
173
|
+
if project_files.any? || proj_files.any? || packages_config_files.any? || global_json || dotnet_tools_json
|
174
|
+
return
|
175
|
+
end
|
148
176
|
|
149
|
-
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
|
+
)
|
150
181
|
end
|
151
182
|
end
|
152
183
|
end
|
@@ -1,18 +1,25 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strong
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
module Dependabot
|
5
7
|
module Nuget
|
6
8
|
module NuGetConfigCredentialHelpers
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig { returns(String) }
|
7
12
|
def self.user_nuget_config_path
|
8
13
|
home_directory = Dir.home
|
9
14
|
File.join(home_directory, ".nuget", "NuGet", "NuGet.Config")
|
10
15
|
end
|
11
16
|
|
17
|
+
sig { returns(String) }
|
12
18
|
def self.temporary_nuget_config_path
|
13
19
|
user_nuget_config_path + "_ORIGINAL"
|
14
20
|
end
|
15
21
|
|
22
|
+
sig { params(credentials: T::Array[Dependabot::Credential]).void }
|
16
23
|
def self.add_credentials_to_nuget_config(credentials)
|
17
24
|
return unless File.exist?(user_nuget_config_path)
|
18
25
|
|
@@ -48,6 +55,7 @@ module Dependabot
|
|
48
55
|
File.write(user_nuget_config_path, nuget_config)
|
49
56
|
end
|
50
57
|
|
58
|
+
sig { void }
|
51
59
|
def self.restore_user_nuget_config
|
52
60
|
return unless File.exist?(temporary_nuget_config_path)
|
53
61
|
|
@@ -55,6 +63,7 @@ module Dependabot
|
|
55
63
|
File.rename(temporary_nuget_config_path, user_nuget_config_path)
|
56
64
|
end
|
57
65
|
|
66
|
+
sig { params(credentials: T::Array[Dependabot::Credential], _block: T.proc.void).void }
|
58
67
|
def self.patch_nuget_config_for_action(credentials, &_block)
|
59
68
|
add_credentials_to_nuget_config(credentials)
|
60
69
|
begin
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "sorbet-runtime"
|
@@ -12,6 +12,9 @@ require "dependabot/nuget/version"
|
|
12
12
|
module Dependabot
|
13
13
|
module Nuget
|
14
14
|
class Requirement < Dependabot::Requirement
|
15
|
+
extend T::Sig
|
16
|
+
|
17
|
+
sig { override.params(obj: T.any(Gem::Version, String)).returns([String, Gem::Version]) }
|
15
18
|
def self.parse(obj)
|
16
19
|
return ["=", Nuget::Version.new(obj.to_s)] if obj.is_a?(Gem::Version)
|
17
20
|
|
@@ -28,11 +31,12 @@ module Dependabot
|
|
28
31
|
# For consistency with other languages, we define a requirements array.
|
29
32
|
# Dotnet doesn't have an `OR` separator for requirements, so it always
|
30
33
|
# contains a single element.
|
31
|
-
sig { override.params(requirement_string: T.nilable(String)).returns(T::Array[Requirement]) }
|
34
|
+
sig { override.params(requirement_string: T.nilable(String)).returns(T::Array[Dependabot::Requirement]) }
|
32
35
|
def self.requirements_array(requirement_string)
|
33
36
|
[new(requirement_string)]
|
34
37
|
end
|
35
38
|
|
39
|
+
sig { params(requirements: T.any(T.nilable(String), T::Array[T.nilable(String)])).void }
|
36
40
|
def initialize(*requirements)
|
37
41
|
requirements = requirements.flatten.flat_map do |req_string|
|
38
42
|
convert_dotnet_constraint_to_ruby_constraint(req_string)
|
@@ -41,6 +45,7 @@ module Dependabot
|
|
41
45
|
super(requirements)
|
42
46
|
end
|
43
47
|
|
48
|
+
sig { override.params(version: Gem::Version).returns(T::Boolean) }
|
44
49
|
def satisfied_by?(version)
|
45
50
|
version = Nuget::Version.new(version.to_s)
|
46
51
|
super
|
@@ -48,10 +53,11 @@ module Dependabot
|
|
48
53
|
|
49
54
|
private
|
50
55
|
|
56
|
+
sig { params(req_string: T.nilable(String)).returns(T.nilable(T.any(String, T::Array[String]))) }
|
51
57
|
def convert_dotnet_constraint_to_ruby_constraint(req_string)
|
52
58
|
return unless req_string
|
53
59
|
|
54
|
-
return convert_dotnet_range_to_ruby_range(req_string) if req_string
|
60
|
+
return convert_dotnet_range_to_ruby_range(req_string) if req_string.start_with?("(", "[")
|
55
61
|
|
56
62
|
return req_string.split(",").map(&:strip) if req_string.include?(",")
|
57
63
|
|
@@ -61,6 +67,7 @@ module Dependabot
|
|
61
67
|
end
|
62
68
|
|
63
69
|
# rubocop:disable Metrics/PerceivedComplexity
|
70
|
+
sig { params(req_string: String).returns(T::Array[String]) }
|
64
71
|
def convert_dotnet_range_to_ruby_range(req_string)
|
65
72
|
lower_b, upper_b = req_string.split(",").map(&:strip).map do |bound|
|
66
73
|
next convert_range_wildcard_req(bound) if bound.include?("*")
|
@@ -70,9 +77,9 @@ module Dependabot
|
|
70
77
|
|
71
78
|
lower_b =
|
72
79
|
if ["(", "["].include?(lower_b) then nil
|
73
|
-
elsif lower_b.start_with?("(") then "> #{lower_b.sub(/\(\s*/, '')}"
|
80
|
+
elsif T.must(lower_b).start_with?("(") then "> #{T.must(lower_b).sub(/\(\s*/, '')}"
|
74
81
|
else
|
75
|
-
">= #{lower_b.sub(/\[\s*/, '').strip}"
|
82
|
+
">= #{T.must(lower_b).sub(/\[\s*/, '').strip}"
|
76
83
|
end
|
77
84
|
|
78
85
|
upper_b =
|
@@ -87,20 +94,22 @@ module Dependabot
|
|
87
94
|
end
|
88
95
|
# rubocop:enable Metrics/PerceivedComplexity
|
89
96
|
|
97
|
+
sig { params(req_string: String).returns(String) }
|
90
98
|
def convert_range_wildcard_req(req_string)
|
91
|
-
range_end = req_string[-1]
|
92
|
-
defined_part = req_string.split("*").first
|
99
|
+
range_end = T.must(req_string[-1])
|
100
|
+
defined_part = T.must(req_string.split("*").first)
|
93
101
|
version = defined_part + "0"
|
94
102
|
version += range_end if [")", "]"].include?(range_end)
|
95
103
|
version
|
96
104
|
end
|
97
105
|
|
106
|
+
sig { params(req_string: String).returns(String) }
|
98
107
|
def convert_wildcard_req(req_string)
|
99
108
|
return ">= 0-a" if req_string == "*-*"
|
100
109
|
|
101
110
|
return ">= 0" if req_string.start_with?("*")
|
102
111
|
|
103
|
-
defined_part = req_string.split("*").first
|
112
|
+
defined_part = T.must(req_string.split("*").first)
|
104
113
|
suffix = defined_part.end_with?(".") ? "0" : "a"
|
105
114
|
version = defined_part + suffix
|
106
115
|
"~> #{version}"
|
@@ -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}"
|