diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs index 49fd4afb9bb..a0ff6c0548c 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs @@ -1381,4 +1381,57 @@ await TestDiscoveryAsync( } ); } + + // If the "Restore" target is invoked and $(RestoreUseStaticGraphEvaluation) is set to true, NuGet can throw + // a NullReferenceException. + // https://github.com/NuGet/Home/issues/11761#issuecomment-1105218996 + [Fact] + public async Task NullReferenceExceptionFromNuGetRestoreIsWorkedAround() + { + await TestDiscoveryAsync( + packages: [ + MockNuGetPackage.CreateSimplePackage("Some.Package", "1.2.3", "net8.0"), + ], + experimentsManager: new ExperimentsManager() { UseDirectDiscovery = true }, + workspacePath: "", + files: [ + ("project.csproj", """ + + + net8.0 + true + + + + + + """), + // a pattern seen in the wild; always run restore + ("Directory.Build.rsp", """ + /Restore + """) + ], + expectedResult: new() + { + Path = "", + Projects = [ + new() + { + FilePath = "project.csproj", + TargetFrameworks = ["net8.0"], + Dependencies = [ + new("Some.Package", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true) + ], + Properties = [ + new("RestoreUseStaticGraphEvaluation", "true", "project.csproj"), + new("TargetFramework", "net8.0", "project.csproj"), + ], + ReferencedProjectPaths = [], + ImportedFiles = [], + AdditionalFiles = [], + } + ] + } + ); + } } diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs index 6b551773082..c0f90ad89f4 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs @@ -101,7 +101,7 @@ public static async Task> DiscoverWithBin { // the built-in target `GenerateBuildDependencyFile` forces resolution of all NuGet packages, but doesn't invoke a full build var dependencyDiscoveryTargetsPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "DependencyDiscovery.targets"); - var args = new string[] + var args = new List() { "build", startingProjectPath, @@ -112,6 +112,16 @@ public static async Task> DiscoverWithBin $"/bl:{binLogPath}" }; var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(args, startingProjectDirectory, experimentsManager); + if (exitCode != 0 && stdOut.Contains("error : Object reference not set to an instance of an object.")) + { + // https://github.com/NuGet/Home/issues/11761#issuecomment-1105218996 + // Due to a bug in NuGet, there can be a null reference exception thrown and adding this command line argument will work around it, + // but this argument can't always be added; it can cause problems in other instances, so we're taking the approach of not using it + // unless we have to. + args.Add("/RestoreProperty:__Unused__=__Unused__"); + (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(args, startingProjectDirectory, experimentsManager); + } + return (exitCode, stdOut, stdErr); }, logger, retainMSBuildSdks: true); MSBuildHelper.ThrowOnError(stdOut);