dependabot-nuget 0.290.0 → 0.291.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 +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +3 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyFinder.cs +2 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +44 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscovery.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs +2 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +19 -11
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +3 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +3 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +43 -18
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +40 -14
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProcessExtensions.cs +45 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +41 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +246 -60
- data/lib/dependabot/nuget/file_fetcher.rb +1 -0
- data/lib/dependabot/nuget/file_parser.rb +90 -0
- data/lib/dependabot/nuget/language.rb +82 -0
- data/lib/dependabot/nuget/native_helpers.rb +23 -0
- data/lib/dependabot/nuget/package_manager.rb +51 -0
- metadata +7 -5
@@ -34,7 +34,8 @@ internal static partial class MSBuildHelper
|
|
34
34
|
// Ensure MSBuild types are registered before calling a method that loads the types
|
35
35
|
if (!IsMSBuildRegistered)
|
36
36
|
{
|
37
|
-
|
37
|
+
var experimentsManager = new ExperimentsManager() { InstallDotnetSdks = false }; // `global.json` definitely needs to be moved for this operation
|
38
|
+
HandleGlobalJsonAsync(currentDirectory, rootDirectory, experimentsManager, () =>
|
38
39
|
{
|
39
40
|
var defaultInstance = MSBuildLocator.QueryVisualStudioInstances().First();
|
40
41
|
MSBuildPath = defaultInstance.MSBuildPath;
|
@@ -44,9 +45,23 @@ internal static partial class MSBuildHelper
|
|
44
45
|
}
|
45
46
|
}
|
46
47
|
|
47
|
-
public static async Task<T>
|
48
|
+
public static async Task<T> HandleGlobalJsonAsync<T>(
|
49
|
+
string currentDirectory,
|
50
|
+
string rootDirectory,
|
51
|
+
ExperimentsManager experimentsManager,
|
52
|
+
Func<Task<T>> action,
|
53
|
+
ILogger? logger = null,
|
54
|
+
bool retainMSBuildSdks = false
|
55
|
+
)
|
48
56
|
{
|
49
57
|
logger ??= new ConsoleLogger();
|
58
|
+
if (experimentsManager.InstallDotnetSdks)
|
59
|
+
{
|
60
|
+
logger.Info($"{nameof(ExperimentsManager.InstallDotnetSdks)} == true; retaining `global.json` contents.");
|
61
|
+
var result = await action();
|
62
|
+
return result;
|
63
|
+
}
|
64
|
+
|
50
65
|
var candidateDirectories = PathHelper.GetAllDirectoriesToRoot(currentDirectory, rootDirectory);
|
51
66
|
var globalJsonPaths = candidateDirectories.Select(d => Path.Combine(d, "global.json")).Where(File.Exists).Select(p => (p, p + Guid.NewGuid().ToString())).ToArray();
|
52
67
|
foreach (var (globalJsonPath, tempGlobalJsonPath) in globalJsonPaths)
|
@@ -322,13 +337,13 @@ internal static partial class MSBuildHelper
|
|
322
337
|
return false;
|
323
338
|
}
|
324
339
|
|
325
|
-
internal static async Task<bool> DependenciesAreCoherentAsync(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, ILogger logger)
|
340
|
+
internal static async Task<bool> DependenciesAreCoherentAsync(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, ExperimentsManager experimentsManager, ILogger logger)
|
326
341
|
{
|
327
342
|
var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
|
328
343
|
try
|
329
344
|
{
|
330
345
|
var tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages, logger);
|
331
|
-
var (exitCode, stdOut, stdErr) = await ProcessEx.
|
346
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["restore", tempProjectPath], tempDirectory.FullName, experimentsManager);
|
332
347
|
|
333
348
|
// NU1608: Detected package version outside of dependency constraint
|
334
349
|
|
@@ -340,7 +355,7 @@ internal static partial class MSBuildHelper
|
|
340
355
|
}
|
341
356
|
}
|
342
357
|
|
343
|
-
internal static async Task<Dependency[]?> ResolveDependencyConflicts(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, ILogger logger)
|
358
|
+
internal static async Task<Dependency[]?> ResolveDependencyConflicts(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, ExperimentsManager experimentsManager, ILogger logger)
|
344
359
|
{
|
345
360
|
var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
|
346
361
|
PackageManager packageManager = new PackageManager(repoRoot, projectPath);
|
@@ -348,7 +363,7 @@ internal static partial class MSBuildHelper
|
|
348
363
|
try
|
349
364
|
{
|
350
365
|
string tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages, logger);
|
351
|
-
var (exitCode, stdOut, stdErr) = await ProcessEx.
|
366
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["restore", tempProjectPath], tempDirectory.FullName, experimentsManager);
|
352
367
|
|
353
368
|
// Add Dependency[] packages to List<PackageToUpdate> existingPackages
|
354
369
|
List<PackageToUpdate> existingPackages = packages
|
@@ -498,13 +513,13 @@ internal static partial class MSBuildHelper
|
|
498
513
|
}
|
499
514
|
}
|
500
515
|
|
501
|
-
internal static async Task<Dependency[]?> ResolveDependencyConflictsWithBruteForce(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, ILogger logger)
|
516
|
+
internal static async Task<Dependency[]?> ResolveDependencyConflictsWithBruteForce(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, ExperimentsManager experimentsManager, ILogger logger)
|
502
517
|
{
|
503
518
|
var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
|
504
519
|
try
|
505
520
|
{
|
506
521
|
var tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages, logger);
|
507
|
-
var (exitCode, stdOut, stdErr) = await ProcessEx.
|
522
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["restore", tempProjectPath], tempDirectory.FullName, experimentsManager);
|
508
523
|
ThrowOnUnauthenticatedFeed(stdOut);
|
509
524
|
|
510
525
|
// simple cases first
|
@@ -529,6 +544,7 @@ internal static partial class MSBuildHelper
|
|
529
544
|
foreach ((string PackageName, NuGetVersion packageVersion) in badPackagesAndVersions)
|
530
545
|
{
|
531
546
|
// this command dumps a JSON object with all versions of the specified package from all package sources
|
547
|
+
// not using the `dotnet` execution method because we want to force the latest MSBuild and SDK to be used
|
532
548
|
(exitCode, stdOut, stdErr) = await ProcessEx.RunAsync("dotnet", ["package", "search", PackageName, "--exact-match", "--format", "json"], workingDirectory: tempDirectory.FullName);
|
533
549
|
if (exitCode != 0)
|
534
550
|
{
|
@@ -591,7 +607,7 @@ internal static partial class MSBuildHelper
|
|
591
607
|
return p;
|
592
608
|
}).ToArray();
|
593
609
|
|
594
|
-
if (await DependenciesAreCoherentAsync(repoRoot, projectPath, targetFramework, candidatePackages, logger))
|
610
|
+
if (await DependenciesAreCoherentAsync(repoRoot, projectPath, targetFramework, candidatePackages, experimentsManager, logger))
|
595
611
|
{
|
596
612
|
// return as soon as we find a coherent set
|
597
613
|
return candidatePackages;
|
@@ -749,14 +765,23 @@ internal static partial class MSBuildHelper
|
|
749
765
|
return tempProjectPath;
|
750
766
|
}
|
751
767
|
|
752
|
-
internal static async Task<ImmutableArray<string>> GetTargetFrameworkValuesFromProject(string repoRoot, string projectPath, ILogger logger)
|
768
|
+
internal static async Task<ImmutableArray<string>> GetTargetFrameworkValuesFromProject(string repoRoot, string projectPath, ExperimentsManager experimentsManager, ILogger logger)
|
753
769
|
{
|
754
|
-
// TODO: once the updater image has all relevant SDKs installed, we won't have to sideline global.json anymore
|
755
770
|
var projectDirectory = Path.GetDirectoryName(projectPath)!;
|
756
|
-
var (exitCode, stdOut, stdErr) = await
|
771
|
+
var (exitCode, stdOut, stdErr) = await HandleGlobalJsonAsync(projectDirectory, repoRoot, experimentsManager, async () =>
|
757
772
|
{
|
758
773
|
var targetsHelperPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "TargetFrameworkReporter.targets");
|
759
|
-
var (exitCode, stdOut, stdErr) = await ProcessEx.
|
774
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(
|
775
|
+
[
|
776
|
+
"build",
|
777
|
+
projectPath,
|
778
|
+
"/t:ReportTargetFramework",
|
779
|
+
$"/p:CustomAfterMicrosoftCommonCrossTargetingTargets={targetsHelperPath}",
|
780
|
+
$"/p:CustomAfterMicrosoftCommonTargets={targetsHelperPath}"
|
781
|
+
],
|
782
|
+
projectDirectory,
|
783
|
+
experimentsManager
|
784
|
+
);
|
760
785
|
return (exitCode, stdOut, stdErr);
|
761
786
|
});
|
762
787
|
ThrowOnUnauthenticatedFeed(stdOut);
|
@@ -806,6 +831,7 @@ internal static partial class MSBuildHelper
|
|
806
831
|
string projectPath,
|
807
832
|
string targetFramework,
|
808
833
|
IReadOnlyCollection<Dependency> packages,
|
834
|
+
ExperimentsManager experimentsManager,
|
809
835
|
ILogger logger)
|
810
836
|
{
|
811
837
|
var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-resolution_");
|
@@ -814,7 +840,7 @@ internal static partial class MSBuildHelper
|
|
814
840
|
var topLevelPackagesNames = packages.Select(p => p.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
815
841
|
var tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages, logger);
|
816
842
|
|
817
|
-
var (exitCode, stdout, stderr) = await ProcessEx.
|
843
|
+
var (exitCode, stdout, stderr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["build", tempProjectPath, "/t:_ReportDependencies"], tempDirectory.FullName, experimentsManager);
|
818
844
|
ThrowOnUnauthenticatedFeed(stdout);
|
819
845
|
|
820
846
|
if (exitCode == 0)
|
@@ -4,13 +4,13 @@ namespace NuGetUpdater.Core;
|
|
4
4
|
|
5
5
|
internal static class NuGetHelper
|
6
6
|
{
|
7
|
-
internal static async Task<bool> DownloadNuGetPackagesAsync(string repoRoot, string projectPath, IReadOnlyCollection<Dependency> packages, ILogger logger)
|
7
|
+
internal static async Task<bool> DownloadNuGetPackagesAsync(string repoRoot, string projectPath, IReadOnlyCollection<Dependency> packages, ExperimentsManager experimentsManager, ILogger logger)
|
8
8
|
{
|
9
9
|
var tempDirectory = Directory.CreateTempSubdirectory("msbuild_sdk_restore_");
|
10
10
|
try
|
11
11
|
{
|
12
12
|
var tempProjectPath = await MSBuildHelper.CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, "netstandard2.0", packages, logger, usePackageDownload: true);
|
13
|
-
var (exitCode, stdOut, stdErr) = await ProcessEx.
|
13
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["restore", tempProjectPath], tempDirectory.FullName, experimentsManager);
|
14
14
|
|
15
15
|
return exitCode == 0;
|
16
16
|
}
|
@@ -5,19 +5,57 @@ namespace NuGetUpdater.Core;
|
|
5
5
|
|
6
6
|
public static class ProcessEx
|
7
7
|
{
|
8
|
-
|
8
|
+
/// <summary>
|
9
|
+
/// Run the `dotnet` command with the given values. This will exclude all `MSBuild*` environment variables from the execution.
|
10
|
+
/// </summary>
|
11
|
+
public static Task<(int ExitCode, string Output, string Error)> RunDotnetWithoutMSBuildEnvironmentVariablesAsync(IEnumerable<string> arguments, string workingDirectory, ExperimentsManager experimentsManager)
|
12
|
+
{
|
13
|
+
var environmentVariablesToUnset = new List<string>();
|
14
|
+
if (experimentsManager.InstallDotnetSdks)
|
15
|
+
{
|
16
|
+
// If using the SDK specified by a `global.json` file, these environment variables need to be unset to
|
17
|
+
// allow the new process to discover the correct MSBuild binaries to load, and not load the ones that
|
18
|
+
// this process is using.
|
19
|
+
environmentVariablesToUnset.Add("MSBuildExtensionsPath");
|
20
|
+
environmentVariablesToUnset.Add("MSBuildLoadMicrosoftTargetsReadOnly");
|
21
|
+
environmentVariablesToUnset.Add("MSBUILDLOGIMPORTS");
|
22
|
+
environmentVariablesToUnset.Add("MSBuildSDKsPath");
|
23
|
+
environmentVariablesToUnset.Add("MSBUILDTARGETOUTPUTLOGGING");
|
24
|
+
environmentVariablesToUnset.Add("MSBUILD_EXE_PATH");
|
25
|
+
}
|
26
|
+
|
27
|
+
var environmentVariableOverrides = environmentVariablesToUnset.Select(name => (name, (string?)null));
|
28
|
+
return RunAsync("dotnet",
|
29
|
+
arguments,
|
30
|
+
workingDirectory,
|
31
|
+
environmentVariableOverrides
|
32
|
+
);
|
33
|
+
}
|
34
|
+
|
35
|
+
public static Task<(int ExitCode, string Output, string Error)> RunAsync(
|
36
|
+
string fileName,
|
37
|
+
IEnumerable<string>? arguments = null,
|
38
|
+
string? workingDirectory = null,
|
39
|
+
IEnumerable<(string Name, string? Value)>? environmentVariableOverrides = null
|
40
|
+
)
|
9
41
|
{
|
10
42
|
var tcs = new TaskCompletionSource<(int, string, string)>();
|
11
43
|
|
12
44
|
var redirectInitiated = new ManualResetEventSlim();
|
45
|
+
var psi = new ProcessStartInfo(fileName, arguments ?? [])
|
46
|
+
{
|
47
|
+
UseShellExecute = false, // required to redirect output and set environment variables
|
48
|
+
RedirectStandardOutput = true,
|
49
|
+
RedirectStandardError = true,
|
50
|
+
};
|
51
|
+
foreach (var (name, value) in environmentVariableOverrides ?? [])
|
52
|
+
{
|
53
|
+
psi.EnvironmentVariables[name] = value;
|
54
|
+
}
|
55
|
+
|
13
56
|
var process = new Process
|
14
57
|
{
|
15
|
-
StartInfo =
|
16
|
-
{
|
17
|
-
UseShellExecute = false, // required to redirect output
|
18
|
-
RedirectStandardOutput = true,
|
19
|
-
RedirectStandardError = true,
|
20
|
-
},
|
58
|
+
StartInfo = psi,
|
21
59
|
EnableRaisingEvents = true
|
22
60
|
};
|
23
61
|
|
@@ -1094,6 +1094,47 @@ public partial class DiscoveryWorkerTests : DiscoveryWorkerTestBase
|
|
1094
1094
|
);
|
1095
1095
|
}
|
1096
1096
|
|
1097
|
+
[Theory]
|
1098
|
+
[InlineData(true)]
|
1099
|
+
[InlineData(false)]
|
1100
|
+
public async Task DiscoveryReportsDependencyFileNotParseable(bool useDirectDiscovery)
|
1101
|
+
{
|
1102
|
+
var experimentsManager = new ExperimentsManager() { UseDirectDiscovery = useDirectDiscovery };
|
1103
|
+
await TestDiscoveryAsync(
|
1104
|
+
experimentsManager: experimentsManager,
|
1105
|
+
workspacePath: "",
|
1106
|
+
files:
|
1107
|
+
[
|
1108
|
+
("project.csproj", """
|
1109
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
1110
|
+
<PropertyGroup>
|
1111
|
+
<TargetFramework>net8.0</TargetFramework>
|
1112
|
+
</PropertyGroup>
|
1113
|
+
<ItemGroup>
|
1114
|
+
<PackageReference Include="Some.Package" Version="1.2.3" />
|
1115
|
+
</ItemGroup>
|
1116
|
+
</Project>
|
1117
|
+
"""),
|
1118
|
+
("project2.csproj", """
|
1119
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
1120
|
+
<PropertyGroup>
|
1121
|
+
<TargetFramework>net8.0</TargetFramework>
|
1122
|
+
</PropertyGroup>
|
1123
|
+
<ItemGroup>
|
1124
|
+
<PackageReference: Include="Some.Package2" Version="1.2.3" />
|
1125
|
+
</ItemGroup>
|
1126
|
+
</Project>
|
1127
|
+
"""),
|
1128
|
+
],
|
1129
|
+
expectedResult: new()
|
1130
|
+
{
|
1131
|
+
Path = "",
|
1132
|
+
Projects = [],
|
1133
|
+
ErrorType = ErrorType.DependencyFileNotParseable,
|
1134
|
+
ErrorDetails = "project2.csproj",
|
1135
|
+
});
|
1136
|
+
}
|
1137
|
+
|
1097
1138
|
[Fact]
|
1098
1139
|
public async Task ResultFileHasCorrectShapeForAuthenticationFailure()
|
1099
1140
|
{
|
@@ -21,6 +21,7 @@ public record ExpectedSdkProjectDiscoveryResult : ExpectedDependencyDiscoveryRes
|
|
21
21
|
public required ImmutableArray<string> ReferencedProjectPaths { get; init; }
|
22
22
|
public required ImmutableArray<string> ImportedFiles { get; init; }
|
23
23
|
public required ImmutableArray<string> AdditionalFiles { get; init; }
|
24
|
+
public string? ErrorDetails { get; init; }
|
24
25
|
}
|
25
26
|
|
26
27
|
public record ExpectedDependencyDiscoveryResult : IDiscoveryResultWithDependencies
|
@@ -488,7 +488,7 @@ public class SdkProjectDiscoveryTests : DiscoveryWorkerTestBase
|
|
488
488
|
var logger = new TestLogger();
|
489
489
|
var fullProjectPath = Path.Combine(testDirectory.DirectoryPath, projectPath);
|
490
490
|
var experimentsManager = new ExperimentsManager() { UseDirectDiscovery = true }; // the following method is direct discovery; this just makes the call to Validate... happy
|
491
|
-
var projectDiscovery = await SdkProjectDiscovery.DiscoverWithBinLogAsync(testDirectory.DirectoryPath, Path.GetDirectoryName(fullProjectPath)!, fullProjectPath, logger);
|
491
|
+
var projectDiscovery = await SdkProjectDiscovery.DiscoverWithBinLogAsync(testDirectory.DirectoryPath, Path.GetDirectoryName(fullProjectPath)!, fullProjectPath, experimentsManager, logger);
|
492
492
|
ValidateProjectResults(expectedProjects, projectDiscovery, experimentsManager);
|
493
493
|
}
|
494
494
|
}
|
@@ -318,7 +318,8 @@ namespace NuGetUpdater.Core.Test
|
|
318
318
|
</Project>
|
319
319
|
"""
|
320
320
|
);
|
321
|
-
var
|
321
|
+
var experimentsManager = new ExperimentsManager();
|
322
|
+
var (exitCode, stdout, stderr) = ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["msbuild", projectPath, "/t:_ReportCurrentSdkVersion"], projectDir.FullName, experimentsManager).Result;
|
322
323
|
if (exitCode != 0)
|
323
324
|
{
|
324
325
|
throw new Exception($"Failed to report the current SDK version:\n{stdout}\n{stderr}");
|