diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs index 7dff9be25fb..fb1f959deb7 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs @@ -6,10 +6,61 @@ using Xunit; +using TestFile = (string Path, string Content); +using TestProject = (string Path, string Content, System.Guid ProjectId); + namespace NuGetUpdater.Core.Test.Update; public abstract class UpdateWorkerTestBase { + protected static Task TestNoChange( + string dependencyName, + string oldVersion, + string newVersion, + bool useSolution, + string projectContents, + bool isTransitive = false, + (string Path, string Content)[]? additionalFiles = null, + string projectFilePath = "test-project.csproj") + { + return useSolution + ? TestNoChangeforSolution(dependencyName, oldVersion, newVersion, projectFiles: [(projectFilePath, projectContents)], isTransitive, additionalFiles) + : TestNoChangeforProject(dependencyName, oldVersion, newVersion, projectContents, isTransitive, additionalFiles, projectFilePath); + } + + protected static Task TestUpdate( + string dependencyName, + string oldVersion, + string newVersion, + bool useSolution, + string projectContents, + string expectedProjectContents, + bool isTransitive = false, + TestFile[]? additionalFiles = null, + TestFile[]? additionalFilesExpected = null, + string projectFilePath = "test-project.csproj") + { + return useSolution + ? TestUpdateForSolution(dependencyName, oldVersion, newVersion, projectFiles: [(projectFilePath, projectContents)], projectFilesExpected: [(projectFilePath, expectedProjectContents)], isTransitive, additionalFiles, additionalFilesExpected) + : TestUpdateForProject(dependencyName, oldVersion, newVersion, projectFile: (projectFilePath, projectContents), expectedProjectContents, isTransitive, additionalFiles, additionalFilesExpected); + } + + protected static Task TestUpdate( + string dependencyName, + string oldVersion, + string newVersion, + bool useSolution, + TestFile projectFile, + string expectedProjectContents, + bool isTransitive = false, + TestFile[]? additionalFiles = null, + TestFile[]? additionalFilesExpected = null) + { + return useSolution + ? TestUpdateForSolution(dependencyName, oldVersion, newVersion, projectFiles: [projectFile], projectFilesExpected: [(projectFile.Path, expectedProjectContents)], isTransitive, additionalFiles, additionalFilesExpected) + : TestUpdateForProject(dependencyName, oldVersion, newVersion, projectFile, expectedProjectContents, isTransitive, additionalFiles, additionalFilesExpected); + } + protected static Task TestNoChangeforProject( string dependencyName, string oldVersion, @@ -35,8 +86,8 @@ public abstract class UpdateWorkerTestBase string projectContents, string expectedProjectContents, bool isTransitive = false, - (string Path, string Content)[]? additionalFiles = null, - (string Path, string Content)[]? additionalFilesExpected = null, + TestFile[]? additionalFiles = null, + TestFile[]? additionalFilesExpected = null, string projectFilePath = "test-project.csproj") => TestUpdateForProject( dependencyName, @@ -52,42 +103,92 @@ public abstract class UpdateWorkerTestBase string dependencyName, string oldVersion, string newVersion, - (string Path, string Content) projectFile, + TestFile projectFile, string expectedProjectContents, bool isTransitive = false, - (string Path, string Content)[]? additionalFiles = null, - (string Path, string Content)[]? additionalFilesExpected = null) + TestFile[]? additionalFiles = null, + TestFile[]? additionalFilesExpected = null) { additionalFiles ??= []; additionalFilesExpected ??= []; var projectFilePath = projectFile.Path; - var projectName = Path.GetFileNameWithoutExtension(projectFilePath); + var testFiles = new[] { projectFile }.Concat(additionalFiles).ToArray(); + + var actualResult = await RunUpdate(testFiles, async temporaryDirectory => + { + var worker = new UpdaterWorker(new Logger(verbose: true)); + await worker.RunAsync(temporaryDirectory, projectFilePath, dependencyName, oldVersion, newVersion, isTransitive); + }); + + var expectedResult = additionalFilesExpected.Prepend((projectFilePath, expectedProjectContents)).ToArray(); + + AssertContainsFiles(expectedResult, actualResult); + } + + protected static Task TestNoChangeforSolution( + string dependencyName, + string oldVersion, + string newVersion, + TestFile[] projectFiles, + bool isTransitive = false, + TestFile[]? additionalFiles = null) + => TestUpdateForSolution( + dependencyName, + oldVersion, + newVersion, + projectFiles, + projectFilesExpected: projectFiles, + isTransitive, + additionalFiles, + additionalFilesExpected: additionalFiles); + + protected static async Task TestUpdateForSolution( + string dependencyName, + string oldVersion, + string newVersion, + TestFile[] projectFiles, + TestFile[] projectFilesExpected, + bool isTransitive = false, + TestFile[]? additionalFiles = null, + TestFile[]? additionalFilesExpected = null) + { + additionalFiles ??= []; + additionalFilesExpected ??= []; + + var testProjects = projectFiles.Select(file => new TestProject(file.Path, file.Content, Guid.NewGuid())).ToArray(); + var projectDeclarations = testProjects.Select(project => $$""" + Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{Path.GetFileNameWithoutExtension(project.Path)}}", "{{project.Path}}", "{{project.ProjectId}}" + EndProject + """); + var debugConfiguration = testProjects.Select(project => $$""" + {{project.ProjectId}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {{project.ProjectId}}.Debug|Any CPU.Build.0 = Debug|Any CPU + {{project.ProjectId}}..Release|Any CPU.ActiveCfg = Release|Any CPU + {{project.ProjectId}}..Release|Any CPU.Build.0 = Release|Any CPU + """); + var slnName = "test-solution.sln"; var slnContent = $$""" Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.22705.0 MinimumVisualStudioVersion = 10.0.40219.1 - Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{projectName}}", "{{projectFilePath}}", "{782E0C0A-10D3-444D-9640-263D03D2B20C}" - EndProject + {{string.Join(Environment.NewLine, projectDeclarations)}} Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {782E0C0A-10D3-444D-9640-263D03D2B20C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {782E0C0A-10D3-444D-9640-263D03D2B20C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {782E0C0A-10D3-444D-9640-263D03D2B20C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {782E0C0A-10D3-444D-9640-263D03D2B20C}.Release|Any CPU.Build.0 = Release|Any CPU + {{string.Join(Environment.NewLine, debugConfiguration)}} EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal """; - var testFiles = new[] { (slnName, slnContent), projectFile }.Concat(additionalFiles).ToArray(); + var testFiles = new[] { (slnName, slnContent) }.Concat(projectFiles).Concat(additionalFiles).ToArray(); var actualResult = await RunUpdate(testFiles, async temporaryDirectory => { @@ -96,7 +197,7 @@ public abstract class UpdateWorkerTestBase await worker.RunAsync(temporaryDirectory, slnPath, dependencyName, oldVersion, newVersion, isTransitive); }); - var expectedResult = additionalFilesExpected.Prepend((projectFilePath, expectedProjectContents)).ToArray(); + var expectedResult = projectFilesExpected.Concat(additionalFilesExpected).ToArray(); AssertContainsFiles(expectedResult, actualResult); } diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorker.DirsProj.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs similarity index 95% rename from nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorker.DirsProj.cs rename to nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs index c74025d2147..c8a0043df34 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorker.DirsProj.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -24,7 +22,7 @@ public async Task UpdateSingleDependencyInDirsProj() // initial projectContents: """ - + @@ -39,7 +37,7 @@ public async Task UpdateSingleDependencyInDirsProj() netstandard2.0 - + @@ -49,7 +47,7 @@ public async Task UpdateSingleDependencyInDirsProj() // expected expectedProjectContents: """ - + @@ -64,7 +62,7 @@ public async Task UpdateSingleDependencyInDirsProj() netstandard2.0 - + @@ -101,7 +99,7 @@ public async Task UpdateSingleDependencyInNestedDirsProj() // initial projectContents: """ - + @@ -113,7 +111,7 @@ public async Task UpdateSingleDependencyInNestedDirsProj() ("src/dirs.proj", """ - + @@ -126,7 +124,7 @@ public async Task UpdateSingleDependencyInNestedDirsProj() netstandard2.0 - + @@ -136,7 +134,7 @@ public async Task UpdateSingleDependencyInNestedDirsProj() // expected expectedProjectContents: """ - + @@ -148,7 +146,7 @@ public async Task UpdateSingleDependencyInNestedDirsProj() ("src/dirs.proj", """ - + @@ -161,7 +159,7 @@ public async Task UpdateSingleDependencyInNestedDirsProj() netstandard2.0 - + @@ -177,7 +175,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingWildcard() // initial projectContents: """ - + @@ -189,7 +187,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingWildcard() ("src/dirs.proj", """ - + @@ -202,7 +200,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingWildcard() netstandard2.0 - + @@ -212,7 +210,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingWildcard() // expected expectedProjectContents: """ - + @@ -224,7 +222,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingWildcard() ("src/dirs.proj", """ - + @@ -237,7 +235,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingWildcard() netstandard2.0 - + @@ -253,7 +251,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingRecursiveWildcard() // initial projectContents: """ - + @@ -265,7 +263,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingRecursiveWildcard() ("src/dirs.proj", """ - + @@ -278,7 +276,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingRecursiveWildcard() netstandard2.0 - + @@ -288,7 +286,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingRecursiveWildcard() // expected expectedProjectContents: """ - + @@ -300,7 +298,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingRecursiveWildcard() ("src/dirs.proj", """ - + @@ -313,7 +311,7 @@ public async Task UpdateSingleDependencyInNestedDirsProjUsingRecursiveWildcard() netstandard2.0 - + diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs index 220a62a8677..c8d1f3f0baa 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs @@ -30,7 +30,7 @@ public async Task UpdateVersionAttribute_InProjectFile_ForPackageReferenceInclud {tfm} - + @@ -42,7 +42,7 @@ public async Task UpdateVersionAttribute_InProjectFile_ForPackageReferenceInclud {tfm} - + @@ -50,6 +50,149 @@ public async Task UpdateVersionAttribute_InProjectFile_ForPackageReferenceInclud """); } + [Fact] + public async Task UpdateVersionChildElement_InProjectFile_ForPackageReferenceInclude() + { + // update Newtonsoft.Json from 9.0.1 to 13.0.1 + await TestUpdateForProject("Newtonsoft.Json", "9.0.1", "13.0.1", + // initial + projectContents: $""" + + + netstandard2.0 + + + + 9.0.1 + + + + """, + // expected + expectedProjectContents: $""" + + + netstandard2.0 + + + + 13.0.1 + + + + """); + } + + [Fact] + public async Task UpdateVersions_InProjectFile_ForDuplicatePackageReferenceInclude() + { + // update Newtonsoft.Json from 9.0.1 to 13.0.1 + await TestUpdateForProject("Newtonsoft.Json", "9.0.1", "13.0.1", + // initial + projectContents: $""" + + + netstandard2.0 + + + + + 9.0.1 + + + + """, + // expected + expectedProjectContents: $""" + + + netstandard2.0 + + + + + 13.0.1 + + + + """); + } + + [Fact] + public async Task PartialUpdate_InMultipleProjectFiles_ForVersionConstraint() + { + // update Newtonsoft.Json from 12.0.1 to 13.0.1 + await TestUpdateForProject("Newtonsoft.Json", "12.0.1", "13.0.1", + // initial + projectContents: $""" + + + netstandard2.0 + + + + + + + """, + additionalFiles: + [ + (Path: "src/Project/Project.csproj", Content: """ + + + netstandard2.0 + + + + + + """), + ], + // expected + expectedProjectContents: $""" + + + netstandard2.0 + + + + + + + """, + additionalFilesExpected: + [ + (Path: "src/Project/Project.csproj", Content: """ + + + netstandard2.0 + + + + + + """), + ]); + } + + [Fact] + public async Task NoChange_WhenPackageHasVersionConstraint() + { + // Dependency package has version constraint + await TestNoChangeforProject("AWSSDK.Core", "3.3.21.19", "3.7.300.20", + projectContents: $""" + + + netstandard2.0 + + + + + + + """); + } + [Fact] public async Task UpdateVersionAttribute_InProjectFile_ForPackageReferenceInclude_Windows() { @@ -62,7 +205,7 @@ public async Task UpdateVersionAttribute_InProjectFile_ForPackageReferenceInclud net8.0-windows10.0.19041.0 win-x64 - + @@ -75,7 +218,7 @@ public async Task UpdateVersionAttribute_InProjectFile_ForPackageReferenceInclud net8.0-windows10.0.19041.0 win-x64 - + @@ -83,6 +226,73 @@ public async Task UpdateVersionAttribute_InProjectFile_ForPackageReferenceInclud """); } + [Fact] + public async Task UpdateVersionAttribute_InMultipleProjectFiles_ForPackageReferenceInclude() + { + // update Newtonsoft.Json from 9.0.1 to 13.0.1 + await TestUpdateForProject("Newtonsoft.Json", "9.0.1", "13.0.1", + // initial + projectContents: $""" + + + net8.0 + + + + + + + + + + + """, + additionalFiles: + [ + ("lib/Library.csproj", $""" + + + net8.0 + + + + + + + """) + ], + // expected + expectedProjectContents: $""" + + + net8.0 + + + + + + + + + + + """, + additionalFilesExpected: + [ + ("lib/Library.csproj", $""" + + + net8.0 + + + + + + + """) + ]); + } + [Theory] [InlineData("$(NewtonsoftJsonVersion")] [InlineData("$NewtonsoftJsonVersion)")] @@ -113,7 +323,7 @@ public async Task UpdateFindsNearestNugetConfig_AndSucceeds() var privateNugetContent = """ - + @@ -200,7 +410,7 @@ public async Task UpdateExactMatchVersionAttribute_InProjectFile_ForPackageRefer net6.0 - + @@ -212,7 +422,7 @@ public async Task UpdateExactMatchVersionAttribute_InProjectFile_ForPackageRefer net6.0 - + @@ -228,11 +438,11 @@ public async Task AddPackageReference_InProjectFile_ForTransientDependency() // initial projectContents: """ - + netcoreapp3.1 - + @@ -242,11 +452,11 @@ public async Task AddPackageReference_InProjectFile_ForTransientDependency() // expected expectedProjectContents: """ - + netcoreapp3.1 - + @@ -267,7 +477,7 @@ public async Task UpdateVersionAttribute_InProjectFile_ForAnalyzerPackageReferen netstandard2.0 - + all @@ -282,7 +492,7 @@ public async Task UpdateVersionAttribute_InProjectFile_ForAnalyzerPackageReferen netstandard2.0 - + all @@ -304,7 +514,7 @@ public async Task UpdateVersionAttribute_InProjectFile_ForMultiplePackageReferen netstandard2.0 - + @@ -317,7 +527,7 @@ public async Task UpdateVersionAttribute_InProjectFile_ForMultiplePackageReferen netstandard2.0 - + @@ -337,7 +547,7 @@ public async Task UpdateVersionAttribute_InProjectFile_ForPackageReferenceUpdate netstandard2.0 - + @@ -350,7 +560,7 @@ public async Task UpdateVersionAttribute_InProjectFile_ForPackageReferenceUpdate netstandard2.0 - + @@ -370,7 +580,7 @@ public async Task UpdateVersionAttribute_InDirectoryPackages_ForPackageVersion() netstandard2.0 - + @@ -383,7 +593,7 @@ public async Task UpdateVersionAttribute_InDirectoryPackages_ForPackageVersion() true - + @@ -396,7 +606,7 @@ public async Task UpdateVersionAttribute_InDirectoryPackages_ForPackageVersion() netstandard2.0 - + @@ -409,7 +619,7 @@ public async Task UpdateVersionAttribute_InDirectoryPackages_ForPackageVersion() true - + @@ -429,7 +639,7 @@ public async Task UpdateExactMatchVersionAttribute_InDirectoryPackages_ForPackag netstandard2.0 - + @@ -442,7 +652,7 @@ public async Task UpdateExactMatchVersionAttribute_InDirectoryPackages_ForPackag true - + @@ -455,7 +665,7 @@ public async Task UpdateExactMatchVersionAttribute_InDirectoryPackages_ForPackag netstandard2.0 - + @@ -468,7 +678,7 @@ public async Task UpdateExactMatchVersionAttribute_InDirectoryPackages_ForPackag true - + @@ -488,7 +698,7 @@ public async Task UpdatePropertyValue_InProjectFile_ForPackageReferenceIncludeWi netstandard2.0 9.0.1 - + @@ -501,7 +711,7 @@ public async Task UpdatePropertyValue_InProjectFile_ForPackageReferenceIncludeWi netstandard2.0 13.0.1 - + @@ -520,7 +730,7 @@ public async Task UpdateDifferentCasedPropertyValue_InProjectFile_ForPackageRefe netstandard2.0 9.0.1 - + @@ -533,7 +743,7 @@ public async Task UpdateDifferentCasedPropertyValue_InProjectFile_ForPackageRefe netstandard2.0 13.0.1 - + @@ -552,7 +762,7 @@ public async Task UpdatePropertyValue_InProjectFile_ForPackageReferenceInclude() netstandard2.0 9.0.1 - + @@ -565,7 +775,7 @@ public async Task UpdatePropertyValue_InProjectFile_ForPackageReferenceInclude() netstandard2.0 13.0.1 - + @@ -584,7 +794,7 @@ public async Task UpdateExactMatchPropertyValue_InProjectFile_ForPackageReferenc netstandard2.0 [9.0.1] - + @@ -597,7 +807,7 @@ public async Task UpdateExactMatchPropertyValue_InProjectFile_ForPackageReferenc netstandard2.0 [13.0.1] - + @@ -616,7 +826,7 @@ public async Task UpdateVersionAttributeAndPropertyValue_InProjectFile_ForMultip netstandard2.0 9.0.1 - + @@ -630,7 +840,7 @@ public async Task UpdateVersionAttributeAndPropertyValue_InProjectFile_ForMultip netstandard2.0 13.0.1 - + @@ -650,7 +860,7 @@ public async Task UpdatePropertyValue_InProjectFile_ForPackageReferenceUpdate() netstandard2.0 9.0.1 - + @@ -664,7 +874,7 @@ public async Task UpdatePropertyValue_InProjectFile_ForPackageReferenceUpdate() netstandard2.0 13.0.1 - + @@ -684,7 +894,7 @@ public async Task UpdatePropertyValue_InDirectoryProps_ForPackageVersion() netstandard2.0 - + @@ -698,7 +908,7 @@ public async Task UpdatePropertyValue_InDirectoryProps_ForPackageVersion() true 9.0.1 - + @@ -711,7 +921,7 @@ public async Task UpdatePropertyValue_InDirectoryProps_ForPackageVersion() netstandard2.0 - + @@ -725,7 +935,7 @@ public async Task UpdatePropertyValue_InDirectoryProps_ForPackageVersion() true 13.0.1 - + @@ -745,7 +955,7 @@ public async Task UpdateExactMatchPropertyValue_InDirectoryProps_ForPackageVersi netstandard2.0 - + @@ -759,7 +969,7 @@ public async Task UpdateExactMatchPropertyValue_InDirectoryProps_ForPackageVersi true [9.0.1] - + @@ -772,7 +982,7 @@ public async Task UpdateExactMatchPropertyValue_InDirectoryProps_ForPackageVersi netstandard2.0 - + @@ -786,7 +996,7 @@ public async Task UpdateExactMatchPropertyValue_InDirectoryProps_ForPackageVersi true [13.0.1] - + @@ -806,7 +1016,7 @@ public async Task UpdateVersionOverrideAttributeAndPropertyValue_InProjectFileAn netstandard2.0 - + @@ -820,7 +1030,7 @@ public async Task UpdateVersionOverrideAttributeAndPropertyValue_InProjectFileAn true 9.0.1 - + @@ -833,7 +1043,7 @@ public async Task UpdateVersionOverrideAttributeAndPropertyValue_InProjectFileAn netstandard2.0 - + @@ -847,7 +1057,7 @@ public async Task UpdateVersionOverrideAttributeAndPropertyValue_InProjectFileAn true 13.0.1 - + @@ -876,7 +1086,7 @@ public async Task UpdateVersionAttribute_InDirectoryProps_ForGlobalPackageRefere true - + @@ -898,7 +1108,7 @@ public async Task UpdateVersionAttribute_InDirectoryProps_ForGlobalPackageRefere true - + @@ -928,7 +1138,7 @@ public async Task UpdatePropertyValue_InDirectoryProps_ForGlobalPackageReference true 9.0.1 - + @@ -951,7 +1161,7 @@ public async Task UpdatePropertyValue_InDirectoryProps_ForGlobalPackageReference true 13.0.1 - + @@ -970,7 +1180,7 @@ public async Task UpdatePropertyValue_InDirectoryProps_ForPackageReferenceInclud netstandard2.0 - + @@ -993,7 +1203,7 @@ public async Task UpdatePropertyValue_InDirectoryProps_ForPackageReferenceInclud netstandard2.0 - + @@ -1020,11 +1230,11 @@ public async Task UpdatePropertyValue_InProps_ForPackageReferenceInclude() projectContents: """ - + netstandard2.0 - + @@ -1045,11 +1255,11 @@ public async Task UpdatePropertyValue_InProps_ForPackageReferenceInclude() expectedProjectContents: """ - + netstandard2.0 - + @@ -1079,7 +1289,7 @@ public async Task UpdatePropertyValue_InProps_ForPackageVersion() netstandard2.0 - + @@ -1094,7 +1304,7 @@ public async Task UpdatePropertyValue_InProps_ForPackageVersion() true - + @@ -1114,7 +1324,7 @@ public async Task UpdatePropertyValue_InProps_ForPackageVersion() netstandard2.0 - + @@ -1129,7 +1339,7 @@ public async Task UpdatePropertyValue_InProps_ForPackageVersion() true - + @@ -1156,7 +1366,7 @@ public async Task UpdatePropertyValue_InProps_ThenSubstituted_ForPackageVersion( netstandard2.0 - + @@ -1172,7 +1382,7 @@ public async Task UpdatePropertyValue_InProps_ThenSubstituted_ForPackageVersion( true $(NewtonsoftJsonVersion) - + @@ -1192,7 +1402,7 @@ public async Task UpdatePropertyValue_InProps_ThenSubstituted_ForPackageVersion( netstandard2.0 - + @@ -1208,7 +1418,7 @@ public async Task UpdatePropertyValue_InProps_ThenSubstituted_ForPackageVersion( true $(NewtonsoftJsonVersion) - + @@ -1235,7 +1445,7 @@ public async Task UpdatePropertyValues_InProps_ThenRedefinedAndSubstituted_ForPa netstandard2.0 - + @@ -1251,7 +1461,7 @@ public async Task UpdatePropertyValues_InProps_ThenRedefinedAndSubstituted_ForPa true $(NewtonsoftJsonVersion) - + @@ -1272,7 +1482,7 @@ public async Task UpdatePropertyValues_InProps_ThenRedefinedAndSubstituted_ForPa netstandard2.0 - + @@ -1288,7 +1498,7 @@ public async Task UpdatePropertyValues_InProps_ThenRedefinedAndSubstituted_ForPa true $(NewtonsoftJsonVersion) - + @@ -1597,13 +1807,13 @@ public async Task AvoidPackageDowngradeWhenUpdatingDependency() await TestUpdateForProject("Microsoft.VisualStudio.Sdk.TestFramework.Xunit", "17.2.7", "17.6.16", projectContents: """ - + $(PreferredTargetFramework) false - + @@ -1645,13 +1855,13 @@ public async Task AvoidPackageDowngradeWhenUpdatingDependency() ], expectedProjectContents: """ - + $(PreferredTargetFramework) false - + @@ -1700,11 +1910,11 @@ public async Task AddTransitiveDependencyByAddingPackageReferenceAndVersion() // initial projectContents: """ - + net5.0 - + @@ -1728,11 +1938,11 @@ public async Task AddTransitiveDependencyByAddingPackageReferenceAndVersion() // expected expectedProjectContents: """ - + net5.0 - + @@ -1764,12 +1974,12 @@ public async Task PinTransitiveDependencyByAddingPackageVersion() // initial projectContents: """ - + $(NoWarn);NETSDK1138 net5.0 - + @@ -1794,12 +2004,12 @@ public async Task PinTransitiveDependencyByAddingPackageVersion() // expected expectedProjectContents: """ - + $(NoWarn);NETSDK1138 net5.0 - + @@ -2207,5 +2417,38 @@ public async Task UpdatePackageVersionFromPropertyWithConditionCheckingForEmptyS """ ); } + + [Fact] + public async Task NoChange_IfThereAreIncoherentVersions() + { + // Make sure we don't update if there are incoherent versions + await TestNoChangeforProject("Microsoft.EntityFrameworkCore.SqlServer", "2.1.0", "2.2.0", + projectContents: """ + + + netcoreapp2.1 + + + + + + + + + + + + + + + + + + + + + + """); + } } } diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/SdkPackageUpdaterTests.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/SdkPackageUpdaterTests.cs deleted file mode 100644 index c0f2048995b..00000000000 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/SdkPackageUpdaterTests.cs +++ /dev/null @@ -1,317 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; - -using Xunit; - -namespace NuGetUpdater.Core.Test.Utilities; - -public class SdkPackageUpdaterTests -{ - [Theory] - [MemberData(nameof(GetDependencyUpdates))] - public async Task UpdateDependency_UpdatesDependencies((string Path, string Contents)[] startingContents, (string Path, string Contents)[] expectedContents, - string dependencyName, string previousVersion, string newDependencyVersion, bool isTransitive) - { - // Arrange - using var directory = TemporaryDirectory.CreateWithContents(startingContents); - var projectPath = Path.Combine(directory.DirectoryPath, startingContents.First().Path); - var logger = new Logger(verbose: false); - - // Act - await SdkPackageUpdater.UpdateDependencyAsync(directory.DirectoryPath, projectPath, dependencyName, previousVersion, newDependencyVersion, isTransitive, logger); - - // Assert - AssertContentsEqual(expectedContents, directory); - } - - public static IEnumerable GetDependencyUpdates() - { - // Simple case - yield return new object[] - { - new[] - { - (Path: "src/Project.csproj", Content: """ - - - netstandard2.0 - - - - - - """) - }, // starting contents - new[] - { - (Path: "src/Project.csproj", Content: """ - - - netstandard2.0 - - - - - - """) - }, // expected contents - "Newtonsoft.Json", "12.0.1", "13.0.1", false // isTransitive - }; - - // Dependency package has version constraint - yield return - [ - new[] - { - (Path: "src/Project/Project.csproj", Content: """ - - - netstandard2.0 - - - - - - - """), - }, // starting contents - new[] - { - // If a dependency has a version constraint outside of our new-version, we don't update anything - (Path: "src/Project/Project.csproj", Content: """ - - - netstandard2.0 - - - - - - - """), - }, // expected contents - "AWSSDK.Core", - "3.3.21.19", - "3.7.300.20", - false // isTransitive - ]; - - // Dependency project has version constraint - yield return - [ - new[] - { - (Path: "src/Project2/Project2.csproj", Content: """ - - - netstandard2.0 - - - - - - - """), - (Path: "src/Project/Project.csproj", Content: """ - - - netstandard2.0 - - - - - - """), - }, // starting contents - new[] - { - (Path: "src/Project2/Project2.csproj", Content: """ - - - netstandard2.0 - - - - - - - """), // starting contents - (Path: "src/Project/Project.csproj", Content: """ - - - netstandard2.0 - - - - - - """), - }, // expected contents - "Newtonsoft.Json", - "12.0.1", - "13.0.1", - false // isTransitive - ]; - - // Multiple references - yield return - [ - new[] - { - (Path: "src/Project.csproj", Content: """ - - - netstandard2.0 - - - - - 12.0.1 - - - - """) - }, // starting contents - new[] - { - (Path: "src/Project.csproj", Content: """ - - - netstandard2.0 - - - - - 13.0.1 - - - - """) - }, // expected contents - "Newtonsoft.Json", - "12.0.1", - "13.0.1", - false // isTransitive - ]; - - // Make sure we don't update if there are incoherent versions - yield return - [ - new[] - { - (Path: "src/Project.csproj", Content: """ - - - netcoreapp2.1 - - - - - - - - - - - - - - - - - - - - - - """) - }, // starting contents - new[] - { - (Path: "src/Project.csproj", Content: """ - - - netcoreapp2.1 - - - - - - - - - - - - - - - - - - - - - - """) - }, // expected contents - "Microsoft.EntityFrameworkCore.SqlServer", - "2.1.0", - "2.2.0", - false // isTransitive - ]; - - // PackageReference with Version as child element - yield return - [ - new[] - { - (Path: "src/Project.csproj", Content: """ - - - netstandard2.0 - - - - 12.0.1 - - - - """) - }, // starting contents - new[] - { - (Path: "src/Project.csproj", Content: """ - - - netstandard2.0 - - - - 13.0.1 - - - - """) - }, // expected contents - "Newtonsoft.Json", - "12.0.1", - "13.0.1", - false // isTransitive - ]; - } - - private static void AssertContentsEqual((string Path, string Contents)[] expectedContents, TemporaryDirectory directory) - { - var actualFiles = Directory.GetFiles(directory.DirectoryPath, "*", SearchOption.AllDirectories); - Assert.Equal(expectedContents.Length, actualFiles.Length); - foreach (var (path, contents) in expectedContents) - { - var fullPath = Path.Combine(directory.DirectoryPath, path); - Assert.True(File.Exists(fullPath)); - Assert.Equal(contents, File.ReadAllText(fullPath)); - } - } -} diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs index fe51270c32f..6f7f21e7635 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs @@ -20,132 +20,124 @@ internal static class SdkPackageUpdater string previousDependencyVersion, string newDependencyVersion, bool isTransitive, - Logger logger - ) + Logger logger) { // SDK-style project, modify the XML directly logger.Log(" Running for SDK-style project"); - var buildFiles = await MSBuildHelper.LoadBuildFiles(repoRootPath, projectPath); - - var newDependencyNuGetVersion = NuGetVersion.Parse(newDependencyVersion); - // update all dependencies, including transitive + var buildFiles = await MSBuildHelper.LoadBuildFiles(repoRootPath, projectPath); var tfms = MSBuildHelper.GetTargetFrameworkMonikers(buildFiles); // Get the set of all top-level dependencies in the current project var topLevelDependencies = MSBuildHelper.GetTopLevelPackageDependencyInfos(buildFiles).ToArray(); + if (!await DoesDependencyRequireUpdateAsync(repoRootPath, projectPath, tfms, topLevelDependencies, dependencyName, newDependencyVersion, logger)) + { + return; + } - var packageFoundInDependencies = false; - var packageNeedsUpdating = false; - - foreach (var tfm in tfms) + if (isTransitive) { - var dependencies = await MSBuildHelper.GetAllPackageDependenciesAsync(repoRootPath, projectPath, tfm, topLevelDependencies, logger); - foreach (var (packageName, packageVersion, _, _, _, _) in dependencies) + await UpdateTransitiveDependencyAsnyc(projectPath, dependencyName, newDependencyVersion, buildFiles, logger); + } + else + { + var peerDependencies = await GetUpdatedPeerDependenciesAsync(repoRootPath, projectPath, tfms, dependencyName, newDependencyVersion, logger); + if (peerDependencies is null) { - if (packageName.Equals(dependencyName, StringComparison.OrdinalIgnoreCase)) - { - packageFoundInDependencies = true; - - var nugetVersion = NuGetVersion.Parse(packageVersion); - if (nugetVersion < newDependencyNuGetVersion) - { - packageNeedsUpdating = true; - } - } + return; } - } - // Skip updating the project if the dependency does not exist in the graph - if (!packageFoundInDependencies) - { - logger.Log($" Package [{dependencyName}] Does not exist as a dependency in [{projectPath}]."); - return; + UpdateTopLevelDepdendency(buildFiles, dependencyName, previousDependencyVersion, newDependencyVersion, peerDependencies, logger); } - // Skip updating the project if the dependency version meets or exceeds the newDependencyVersion - if (!packageNeedsUpdating) + if (!await AreDependenciesCoherentAsync(repoRootPath, projectPath, dependencyName, logger, buildFiles, tfms)) { - logger.Log($" Package [{dependencyName}] already meets the requested dependency version in [{projectPath}]."); return; } - var newDependency = new[] { new Dependency(dependencyName, newDependencyVersion, DependencyType.Unknown) }; - var tfmsAndDependencies = new Dictionary(); - foreach (var tfm in tfms) - { - var dependencies = await MSBuildHelper.GetAllPackageDependenciesAsync(repoRootPath, projectPath, tfm, newDependency, logger); - tfmsAndDependencies[tfm] = dependencies; - } + await SaveBuildFilesAsync(buildFiles, logger); + } - // stop update process if we find conflicting package versions - var conflictingPackageVersionsFound = false; - var packagesAndVersions = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var (_, dependencies) in tfmsAndDependencies) + /// + /// Verifies that the package does not already satisfy the requested dependency version. + /// + /// Returns false if the package is not found or does not need to be updated. + private static async Task DoesDependencyRequireUpdateAsync( + string repoRootPath, + string projectPath, + string[] tfms, + Dependency[] topLevelDependencies, + string dependencyName, + string newDependencyVersion, + Logger logger) + { + var newDependencyNuGetVersion = NuGetVersion.Parse(newDependencyVersion); + + bool packageFound = false; + bool needsUpdate = false; + + foreach (var tfm in tfms) { + var dependencies = await MSBuildHelper.GetAllPackageDependenciesAsync( + repoRootPath, + projectPath, + tfm, + topLevelDependencies, + logger); foreach (var (packageName, packageVersion, _, _, _, _) in dependencies) { - if (packagesAndVersions.TryGetValue(packageName, out var existingVersion) && - existingVersion != packageVersion) + if (packageVersion is null) { - logger.Log($" Package [{packageName}] tried to update to version [{packageVersion}], but found conflicting package version of [{existingVersion}]."); - conflictingPackageVersionsFound = true; + continue; } - else + + if (packageName.Equals(dependencyName, StringComparison.OrdinalIgnoreCase)) { - packagesAndVersions[packageName] = packageVersion!; + packageFound = true; + + var nugetVersion = NuGetVersion.Parse(packageVersion); + if (nugetVersion < newDependencyNuGetVersion) + { + needsUpdate = true; + break; + } } } - } - if (conflictingPackageVersionsFound) - { - return; + if (packageFound && needsUpdate) + { + break; + } } - var unupgradableTfms = tfmsAndDependencies.Where(kvp => !kvp.Value.Any()).Select(kvp => kvp.Key); - if (unupgradableTfms.Any()) + // Skip updating the project if the dependency does not exist in the graph + if (!packageFound) { - logger.Log($" The following target frameworks could not find packages to upgrade: {string.Join(", ", unupgradableTfms)}"); - return; + logger.Log($" Package [{dependencyName}] Does not exist as a dependency in [{projectPath}]."); + return false; } - if (isTransitive) - { - var directoryPackagesWithPinning = buildFiles.OfType() - .FirstOrDefault(bf => IsCpmTransitivePinningEnabled(bf)); - if (directoryPackagesWithPinning is not null) - { - PinTransitiveDependency(directoryPackagesWithPinning, dependencyName, newDependencyVersion, logger); - } - else - { - await AddTransitiveDependencyAsync(projectPath, dependencyName, newDependencyVersion, logger); - } - } - else + // Skip updating the project if the dependency version meets or exceeds the newDependencyVersion + if (!needsUpdate) { - UpdateTopLevelDepdendency(buildFiles, dependencyName, previousDependencyVersion, newDependencyVersion, packagesAndVersions, logger); + logger.Log($" Package [{dependencyName}] already meets the requested dependency version in [{projectPath}]."); + return false; } - var updatedTopLevelDependencies = MSBuildHelper.GetTopLevelPackageDependencyInfos(buildFiles); - foreach (var tfm in tfms) + return true; + } + + private static async Task UpdateTransitiveDependencyAsnyc(string projectPath, string dependencyName, string newDependencyVersion, ImmutableArray buildFiles, Logger logger) + { + var directoryPackagesWithPinning = buildFiles.OfType() + .FirstOrDefault(bf => IsCpmTransitivePinningEnabled(bf)); + if (directoryPackagesWithPinning is not null) { - var updatedPackages = await MSBuildHelper.GetAllPackageDependenciesAsync(repoRootPath, projectPath, tfm, updatedTopLevelDependencies.ToArray(), logger); - var dependenciesAreCoherent = await MSBuildHelper.DependenciesAreCoherentAsync(repoRootPath, projectPath, tfm, updatedPackages, logger); - if (!dependenciesAreCoherent) - { - logger.Log($" Package [{dependencyName}] could not be updated in [{projectPath}] because it would cause a dependency conflict."); - return; - } + PinTransitiveDependency(directoryPackagesWithPinning, dependencyName, newDependencyVersion, logger); } - - foreach (var buildFile in buildFiles) + else { - if (await buildFile.SaveAsync()) - { - logger.Log($" Saved [{buildFile.RepoRelativePath}]."); - } + await AddTransitiveDependencyAsync(projectPath, dependencyName, newDependencyVersion, logger); } } @@ -246,14 +238,68 @@ private static async Task AddTransitiveDependencyAsync(string projectPath, strin } } + /// + /// Gets the set of peer dependencies that need to be updated. + /// + /// Returns null if there are conflicting versions. + private static async Task?> GetUpdatedPeerDependenciesAsync( + string repoRootPath, + string projectPath, + string[] tfms, + string dependencyName, + string newDependencyVersion, + Logger logger) + { + var newDependency = new[] { new Dependency(dependencyName, newDependencyVersion, DependencyType.Unknown) }; + var tfmsAndDependencies = new Dictionary(); + foreach (var tfm in tfms) + { + var dependencies = await MSBuildHelper.GetAllPackageDependenciesAsync(repoRootPath, projectPath, tfm, newDependency, logger); + tfmsAndDependencies[tfm] = dependencies; + } + + var unupgradableTfms = tfmsAndDependencies.Where(kvp => !kvp.Value.Any()).Select(kvp => kvp.Key); + if (unupgradableTfms.Any()) + { + logger.Log($" The following target frameworks could not find packages to upgrade: {string.Join(", ", unupgradableTfms)}"); + return null; + } + + var conflictingPackageVersionsFound = false; + var packagesAndVersions = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var (_, dependencies) in tfmsAndDependencies) + { + foreach (var (packageName, packageVersion, _, _, _, _) in dependencies) + { + if (packagesAndVersions.TryGetValue(packageName, out var existingVersion) && + existingVersion != packageVersion) + { + logger.Log($" Package [{packageName}] tried to update to version [{packageVersion}], but found conflicting package version of [{existingVersion}]."); + conflictingPackageVersionsFound = true; + } + else + { + packagesAndVersions[packageName] = packageVersion!; + } + } + } + + // stop update process if we find conflicting package versions + if (conflictingPackageVersionsFound) + { + return null; + } + + return packagesAndVersions; + } + private static void UpdateTopLevelDepdendency( ImmutableArray buildFiles, string dependencyName, string previousDependencyVersion, string newDependencyVersion, - IDictionary packagesAndVersions, - Logger logger - ) + IDictionary peerDependencies, + Logger logger) { var result = TryUpdateDependencyVersion(buildFiles, dependencyName, previousDependencyVersion, newDependencyVersion, logger); if (result == UpdateResult.NotFound) @@ -262,7 +308,7 @@ Logger logger return; } - foreach (var (packageName, packageVersion) in packagesAndVersions.Where(kvp => string.Compare(kvp.Key, dependencyName, StringComparison.OrdinalIgnoreCase) != 0)) + foreach (var (packageName, packageVersion) in peerDependencies.Where(kvp => string.Compare(kvp.Key, dependencyName, StringComparison.OrdinalIgnoreCase) != 0)) { TryUpdateDependencyVersion(buildFiles, packageName, previousDependencyVersion: null, newDependencyVersion: packageVersion, logger); } @@ -515,4 +561,32 @@ Logger logger packageName, StringComparison.OrdinalIgnoreCase) && (e.GetAttributeOrSubElementValue("Version", StringComparison.OrdinalIgnoreCase) ?? e.GetAttributeOrSubElementValue("VersionOverride", StringComparison.OrdinalIgnoreCase)) is not null); + + private static async Task AreDependenciesCoherentAsync(string repoRootPath, string projectPath, string dependencyName, Logger logger, ImmutableArray buildFiles, string[] tfms) + { + var updatedTopLevelDependencies = MSBuildHelper.GetTopLevelPackageDependencyInfos(buildFiles).ToArray(); + foreach (var tfm in tfms) + { + var updatedPackages = await MSBuildHelper.GetAllPackageDependenciesAsync(repoRootPath, projectPath, tfm, updatedTopLevelDependencies, logger); + var dependenciesAreCoherent = await MSBuildHelper.DependenciesAreCoherentAsync(repoRootPath, projectPath, tfm, updatedPackages, logger); + if (!dependenciesAreCoherent) + { + logger.Log($" Package [{dependencyName}] could not be updated in [{projectPath}] because it would cause a dependency conflict."); + return false; + } + } + + return true; + } + + private static async Task SaveBuildFilesAsync(ImmutableArray buildFiles, Logger logger) + { + foreach (var buildFile in buildFiles) + { + if (await buildFile.SaveAsync()) + { + logger.Log($" Saved [{buildFile.RepoRelativePath}]."); + } + } + } } diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs index 76d4ac32572..af613e6b22d 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; namespace NuGetUpdater.Core; @@ -9,6 +10,7 @@ public class UpdaterWorker { private readonly Logger _logger; private readonly HashSet _processedGlobalJsonPaths = new(StringComparer.OrdinalIgnoreCase); + private readonly HashSet _processedProjectPaths = new(StringComparer.OrdinalIgnoreCase); public UpdaterWorker(Logger logger) { @@ -49,6 +51,7 @@ public async Task RunAsync(string repoRootPath, string workspacePath, string dep } _processedGlobalJsonPaths.Clear(); + _processedProjectPaths.Clear(); } private async Task RunForSolutionAsync( @@ -101,7 +104,40 @@ public async Task RunAsync(string repoRootPath, string workspacePath, string dep string newDependencyVersion, bool isTransitive) { - _logger.Log($"Running for project [{projectPath}]"); + _logger.Log($"Running for project file [{Path.GetRelativePath(repoRootPath, projectPath)}]"); + if (!File.Exists(projectPath)) + { + _logger.Log($"File [{projectPath}] does not exist."); + return; + } + + var projectFilePaths = MSBuildHelper.GetProjectPathsFromProject(projectPath); + foreach (var projectFullPath in projectFilePaths.Concat([projectPath])) + { + // If there is some MSBuild logic that needs to run to fully resolve the path skip the project + if (File.Exists(projectFullPath)) + { + await RunUpdaterAsync(repoRootPath, projectFullPath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive); + } + } + } + + private async Task RunUpdaterAsync( + string repoRootPath, + string projectPath, + string dependencyName, + string previousDependencyVersion, + string newDependencyVersion, + bool isTransitive) + { + if (_processedProjectPaths.Contains(projectPath)) + { + return; + } + + _processedProjectPaths.Add(projectPath); + + _logger.Log($"Updating project [{projectPath}]"); if (!isTransitive && MSBuildHelper.GetGlobalJsonPath(repoRootPath, projectPath) is { } globalJsonPath @@ -111,7 +147,7 @@ public async Task RunAsync(string repoRootPath, string workspacePath, string dep await GlobalJsonUpdater.UpdateDependencyAsync(repoRootPath, globalJsonPath, dependencyName, previousDependencyVersion, newDependencyVersion, _logger); } - if (NuGetHelper.HasProjectConfigFile(projectPath)) + if (NuGetHelper.HasPackagesConfigFile(projectPath)) { await PackagesConfigUpdater.UpdateDependencyAsync(repoRootPath, projectPath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive, _logger); } diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs index e6e0fd241c5..23fcb0c6aaa 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs @@ -101,10 +101,18 @@ public static IEnumerable GetProjectPathsFromSolution(string solutionPat public static IEnumerable GetProjectPathsFromProject(string projFilePath) { var projectStack = new Stack<(string folderPath, ProjectRootElement)>(); - var projectRootElement = ProjectRootElement.Open(projFilePath); var processedProjectFiles = new HashSet(StringComparer.OrdinalIgnoreCase); + using var projectCollection = new ProjectCollection(); - projectStack.Push((Path.GetFullPath(Path.GetDirectoryName(projFilePath)!), projectRootElement)); + try + { + var projectRootElement = ProjectRootElement.Open(projFilePath, projectCollection); + projectStack.Push((Path.GetFullPath(Path.GetDirectoryName(projFilePath)!), projectRootElement)); + } + catch (InvalidProjectFileException) + { + yield break; // Skip invalid project files + } while (projectStack.Count > 0) { @@ -137,7 +145,7 @@ public static IEnumerable GetProjectPathsFromProject(string projFilePath // If there is some MSBuild logic that needs to run to fully resolve the path skip the project if (File.Exists(file)) { - var additionalProjectRootElement = ProjectRootElement.Open(file); + var additionalProjectRootElement = ProjectRootElement.Open(file, projectCollection); projectStack.Push((Path.GetFullPath(Path.GetDirectoryName(file)!), additionalProjectRootElement)); processedProjectFiles.Add(file); } diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs index 4f49635a464..dd3e568edf6 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs @@ -6,7 +6,7 @@ internal static class NuGetHelper { internal const string PackagesConfigFileName = "packages.config"; - public static bool HasProjectConfigFile(string projectPath) + public static bool HasPackagesConfigFile(string projectPath) { var projectDirectory = Path.GetDirectoryName(projectPath); var packagesConfigPath = PathHelper.JoinPath(projectDirectory, PackagesConfigFileName);