diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndXprojRefThatRefsCsprojWhereSlnDoesNotRefCsproj/TestApp/src/subdir/subdir.csproj b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndXprojRefThatRefsCsprojWhereSlnDoesNotRefCsproj/TestApp/src/subdir/subdir.csproj index cec816e3f..731464ac2 100644 --- a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndXprojRefThatRefsCsprojWhereSlnDoesNotRefCsproj/TestApp/src/subdir/subdir.csproj +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndXprojRefThatRefsCsprojWhereSlnDoesNotRefCsproj/TestApp/src/subdir/subdir.csproj @@ -8,12 +8,6 @@ F8F96F4A-F10C-4C54-867C-A9EFF55494C8 - - - - - - 1.6.0 diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndXprojRefs/TestApp/TestAssets/TestAsset/Program.cs b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndXprojRefs/TestApp/TestAssets/TestAsset/Program.cs index c56978bf5..2906f8bbf 100644 --- a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndXprojRefs/TestApp/TestAssets/TestAsset/Program.cs +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndXprojRefs/TestApp/TestAssets/TestAsset/Program.cs @@ -2,9 +2,9 @@ using System; namespace App.Tests { - public class Program + public class TestAssetProgram { - public static void Main(string[] args) + public static void TestAssetMain(string[] args) { Console.WriteLine("Hello World!"); } diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs index 380a9a435..d8332258a 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs @@ -314,7 +314,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration } foreach (var projectDirectory in - Enumerable.Repeat(directory, 1).Union(directory.GetDirectories())) + Enumerable.Repeat(directory, 1).Union(directory.GetDirectories("*", SearchOption.AllDirectories))) { AddIfProjectExists(projects, projectDirectory); } diff --git a/src/Microsoft.DotNet.TestFramework/TestAssetInstance.cs b/src/Microsoft.DotNet.TestFramework/TestAssetInstance.cs index ea942eb65..3fc98f0a4 100644 --- a/src/Microsoft.DotNet.TestFramework/TestAssetInstance.cs +++ b/src/Microsoft.DotNet.TestFramework/TestAssetInstance.cs @@ -104,6 +104,15 @@ namespace Microsoft.DotNet.TestFramework return this; } + public TestAssetInstance WithEmptyGlobalJson() + { + var file = Root.Parent.GetFile("global.json"); + + File.WriteAllText(file.FullName, @"{}"); + + return this; + } + private void CopyFiles(IEnumerable filesToCopy) { foreach (var file in filesToCopy) diff --git a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs index b50aca8d1..ea66ed320 100644 --- a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs +++ b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs @@ -103,7 +103,24 @@ namespace Microsoft.DotNet.Tools.Migrate private void UpdateSolutionFile(MigrationReport migrationReport) { - if (_slnFile == null) + if(_slnFile != null) + { + UpdateSolutionFile(migrationReport, _slnFile); + } + else + { + foreach (var slnPath in _workspaceDirectory.EnumerateFiles("*.sln")) + { + var slnFile = SlnFile.Read(slnPath.FullName); + + UpdateSolutionFile(migrationReport, slnFile); + } + } + } + + private void UpdateSolutionFile(MigrationReport migrationReport, SlnFile slnFile) + { + if (slnFile == null) { return; } @@ -115,7 +132,7 @@ namespace Microsoft.DotNet.Tools.Migrate var csprojFilesToAdd = new HashSet(); - var slnPathWithTrailingSlash = PathUtility.EnsureTrailingSlash(_slnFile.BaseDirectory); + var slnPathWithTrailingSlash = PathUtility.EnsureTrailingSlash(slnFile.BaseDirectory); foreach (var report in migrationReport.ProjectMigrationReports) { var reportPathWithTrailingSlash = PathUtility.EnsureTrailingSlash(report.ProjectDirectory); @@ -124,7 +141,7 @@ namespace Microsoft.DotNet.Tools.Migrate reportPathWithTrailingSlash); var xprojPath = Path.Combine(relativeReportPath, report.ProjectName + ".xproj"); - var xprojProjectsReferencedBySolution = _slnFile.Projects.Where(p => p.FilePath == xprojPath); + var xprojProjectsReferencedBySolution = slnFile.Projects.Where(p => p.FilePath == xprojPath); var migratedProjectName = report.ProjectName + ".csproj"; if (xprojProjectsReferencedBySolution.Count() == 1) @@ -138,7 +155,7 @@ namespace Microsoft.DotNet.Tools.Migrate else { var csprojPath = Path.Combine(relativeReportPath, migratedProjectName); - var solutionContainsCsprojPriorToMigration = _slnFile.Projects + var solutionContainsCsprojPriorToMigration = slnFile.Projects .Where(p => p.FilePath == csprojPath) .Any(); @@ -155,20 +172,20 @@ namespace Microsoft.DotNet.Tools.Migrate } Version version; - if (!Version.TryParse(_slnFile.VisualStudioVersion, out version) || version.Major < 15) + if (!Version.TryParse(slnFile.VisualStudioVersion, out version) || version.Major < 15) { - _slnFile.ProductDescription = ProductDescription; - _slnFile.VisualStudioVersion = VisualStudioVersion; - _slnFile.MinimumVisualStudioVersion = MinimumVisualStudioVersion; + slnFile.ProductDescription = ProductDescription; + slnFile.VisualStudioVersion = VisualStudioVersion; + slnFile.MinimumVisualStudioVersion = MinimumVisualStudioVersion; } - RemoveReferencesToMigratedFiles(_slnFile); + RemoveReferencesToMigratedFiles(slnFile); - _slnFile.Write(); + slnFile.Write(); foreach (var csprojFile in csprojFilesToAdd) { - AddProject(_slnFile.FullPath, csprojFile); + AddProject(slnFile.FullPath, csprojFile); } } diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackageDependencies.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackageDependencies.cs index 3067b567a..755abacde 100644 --- a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackageDependencies.cs +++ b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackageDependencies.cs @@ -435,50 +435,5 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests mockProj.Items.Should().ContainSingle( i => (i.Include == "NETStandard.Library" && i.ItemType == "PackageReference")); } - - new private void EmitsPackageReferences(ProjectRootElement mockProj, params Tuple[] packageSpecs) - { - foreach (var packageSpec in packageSpecs) - { - var packageName = packageSpec.Item1; - var packageVersion = packageSpec.Item2; - var packageTFM = packageSpec.Item3; - - var items = mockProj.Items - .Where(i => i.ItemType == "PackageReference") - .Where(i => string.IsNullOrEmpty(packageTFM) || i.ConditionChain().Any(c => c.Contains(packageTFM))) - .Where(i => i.Include == packageName) - .Where(i => i.GetMetadataWithName("Version").Value == packageVersion && - i.GetMetadataWithName("Version").ExpressedAsAttribute); - - items.Should().HaveCount(1); - } - } - - new private void EmitsToolReferences(ProjectRootElement mockProj, params Tuple[] toolSpecs) - { - foreach (var toolSpec in toolSpecs) - { - var packageName = toolSpec.Item1; - var packageVersion = toolSpec.Item2; - - var items = mockProj.Items - .Where(i => i.ItemType == "DotNetCliToolReference") - .Where(i => i.Include == packageName) - .Where(i => i.GetMetadataWithName("Version").Value == packageVersion && - i.GetMetadataWithName("Version").ExpressedAsAttribute); - - items.Should().HaveCount(1); - } - } - - new private ProjectRootElement RunPackageDependenciesRuleOnPj(string s, string testDirectory = null) - { - testDirectory = testDirectory ?? Temp.CreateDirectory().Path; - return TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[] - { - new MigratePackageDependenciesAndToolsRule() - }, s, testDirectory); - } } } \ No newline at end of file diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/PackageDependenciesTestBase.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/PackageDependenciesTestBase.cs index e0eb3a99e..9a5526646 100644 --- a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/PackageDependenciesTestBase.cs +++ b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/PackageDependenciesTestBase.cs @@ -24,7 +24,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests .Where(i => i.ItemType == "PackageReference") .Where(i => string.IsNullOrEmpty(packageTFM) || i.ConditionChain().Any(c => c.Contains(packageTFM))) .Where(i => i.Include == packageName) - .Where(i => i.GetMetadataWithName("Version").Value == packageVersion); + .Where(i => i.GetMetadataWithName("Version").Value == packageVersion && + i.GetMetadataWithName("Version").ExpressedAsAttribute); items.Should().HaveCount(1); } @@ -40,7 +41,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests var items = mockProj.Items .Where(i => i.ItemType == "DotNetCliToolReference") .Where(i => i.Include == packageName) - .Where(i => i.GetMetadataWithName("Version").Value == packageVersion); + .Where(i => i.GetMetadataWithName("Version").Value == packageVersion && + i.GetMetadataWithName("Version").ExpressedAsAttribute); items.Should().HaveCount(1); } @@ -48,7 +50,10 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests protected ProjectRootElement RunPackageDependenciesRuleOnPj(string s, string testDirectory = null) { - testDirectory = testDirectory ?? Temp.CreateDirectory().Path; + testDirectory = + testDirectory ?? + Temp.CreateDirectory().DirectoryInfo.CreateSubdirectory("project").FullName; + return TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[] { new MigratePackageDependenciesAndToolsRule() diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/TemporaryProjectFileRuleRunner.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/TemporaryProjectFileRuleRunner.cs index f574e26a6..e8b7484ed 100644 --- a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/TemporaryProjectFileRuleRunner.cs +++ b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/TemporaryProjectFileRuleRunner.cs @@ -3,7 +3,9 @@ using System.Linq; using Microsoft.Build.Construction; using Microsoft.DotNet.ProjectJsonMigration.Rules; using Microsoft.DotNet.Internal.ProjectModel; +using Microsoft.DotNet.TestFramework; using NuGet.Frameworks; +using System.IO; namespace Microsoft.DotNet.ProjectJsonMigration.Tests { @@ -23,6 +25,21 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests string projectDirectory, string json) { + + var globalJson = Path.Combine(new DirectoryInfo(projectDirectory).Parent.FullName, "global.json"); + if (!File.Exists(globalJson)) + { + var file = new FileInfo(globalJson); + try + { + File.WriteAllText(file.FullName, @"{}"); + } + catch (IOException) + { + //this means there is someone else writing to the file already. So, just ignore it. + } + } + var testPj = new ProjectJsonBuilder(null) .FromStringBase(json) .SaveToDisk(projectDirectory); diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs index cbfa8ba50..330baa6e0 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs @@ -28,6 +28,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, projectName) .CreateInstance(identifier: projectName) .WithSourceFiles() + .WithEmptyGlobalJson() .Root; var solutionRelPath = "TestApp.sln"; @@ -58,6 +59,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, "PJAppWithSlnAndXprojRefs") .CreateInstance() .WithSourceFiles() + .WithEmptyGlobalJson() .Root; var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); @@ -103,6 +105,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson("NonRestoredTestProjects", "PJAppWithSlnAndOneAlreadyMigratedCsproj") .CreateInstance() .WithSourceFiles() + .WithEmptyGlobalJson() .Root; var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); @@ -136,6 +139,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, "PJAppWithSlnAndOneAlreadyMigratedCsproj") .CreateInstance() .WithSourceFiles() + .WithEmptyGlobalJson() .Root; var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); @@ -184,12 +188,61 @@ namespace Microsoft.DotNet.Migration.Tests } } + [Fact] + public void ItMigratesSolutionInTheFolderWhenWeRunMigrationInThatFolder() + { + var projectDirectory = TestAssets + .Get("NonRestoredTestProjects", "PJAppWithSlnAndXprojRefs") + .CreateInstance() + .WithSourceFiles() + .WithEmptyGlobalJson() + .Root; + + var workingDirectory = new DirectoryInfo(Path.Combine(projectDirectory.FullName, "TestApp")); + var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); + + new DotnetCommand() + .WithWorkingDirectory(workingDirectory) + .Execute($"migrate") + .Should().Pass(); + + SlnFile slnFile = SlnFile.Read(Path.Combine(projectDirectory.FullName, solutionRelPath)); + + var nonSolutionFolderProjects = slnFile.Projects + .Where(p => p.TypeGuid != ProjectTypeGuids.SolutionFolderGuid); + + nonSolutionFolderProjects.Count().Should().Be(4); + + var slnProject = nonSolutionFolderProjects.Where((p) => p.Name == "TestApp").Single(); + slnProject.TypeGuid.Should().Be(ProjectTypeGuids.CSharpProjectTypeGuid); + slnProject.FilePath.Should().Be("TestApp.csproj"); + + slnProject = nonSolutionFolderProjects.Where((p) => p.Name == "TestLibrary").Single(); + slnProject.TypeGuid.Should().Be(ProjectTypeGuids.CSharpProjectTypeGuid); + slnProject.FilePath.Should().Be(Path.Combine("..", "TestLibrary", "TestLibrary.csproj")); + + slnProject = nonSolutionFolderProjects.Where((p) => p.Name == "subdir").Single(); + slnProject.FilePath.Should().Be(Path.Combine("src", "subdir", "subdir.csproj")); + + new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .Execute($"restore \"{solutionRelPath}\"") + .Should().Pass(); + + //ISSUE: https://github.com/dotnet/cli/issues/5205 + //new DotnetCommand() + // .WithWorkingDirectory(projectDirectory) + // .Execute($"build \"{solutionRelPath}\"") + // .Should().Pass(); + } + private void MigrateAndBuild(string groupName, string projectName, [CallerMemberName] string callingMethod = "", string identifier = "") { var projectDirectory = TestAssets .Get(groupName, projectName) .CreateInstance(callingMethod: callingMethod, identifier: identifier) .WithSourceFiles() + .WithEmptyGlobalJson() .Root; var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs index f9ced890b..b2a51bf2b 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs @@ -34,6 +34,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance(identifier: projectName) .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; CleanBinObj(projectDirectory); @@ -68,6 +69,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance(identifier: projectName) .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; CleanBinObj(projectDirectory); @@ -87,6 +89,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance() .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; CleanBinObj(projectDirectory); @@ -115,6 +118,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson("ProjectJsonConsoleTemplate") .CreateInstance() .WithSourceFiles() + .WithEmptyGlobalJson() .Root; var outputComparisonData = GetComparisonData(projectDirectory); @@ -140,6 +144,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance() .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; var globalDirectory = projectDirectory.Parent; @@ -168,6 +173,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson(projectName) .CreateInstance() .WithSourceFiles() + .WithEmptyGlobalJson() .Root; File.Copy("NuGet.tempaspnetpatch.config", projectDirectory.GetFile("NuGet.Config").FullName); @@ -185,6 +191,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson("AppWithPackageNamedAfterFolder") .CreateInstance() .WithSourceFiles() + .WithEmptyGlobalJson() .Root; var appProject = solutionDirectory @@ -209,6 +216,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson("TestAppDependencyGraph") .CreateInstance() .WithSourceFiles() + .WithEmptyGlobalJson() .Root; MigrateProject(projectDirectory.GetDirectory(dependencyProject).FullName); @@ -224,6 +232,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance() .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; var globalDirectory = projectDirectory.Parent; @@ -245,6 +254,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance(identifier: projectName) .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName); @@ -270,6 +280,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance(identifier: projectName) .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName); @@ -296,6 +307,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance(identifier: projectName) .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild( @@ -326,6 +338,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson("TestAppDependencyGraph") .CreateInstance(identifier: $"{projectName}.RefsTest") .WithSourceFiles() + .WithEmptyGlobalJson() .Root; MigrateProject(new [] { projectDirectory.GetDirectory(projectName).FullName }); @@ -347,6 +360,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson("TestAppDependencyGraph") .CreateInstance($"{projectName}.SkipRefsTest") .WithSourceFiles() + .WithEmptyGlobalJson() .Root; MigrateProject(new [] { projectDirectory.GetDirectory(projectName).FullName, "--skip-project-references" }); @@ -363,6 +377,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson("TestAppDependencyGraph") .CreateInstance(callingMethod: $"MigrateDirectory.SkipRefs.{skipRefs}") .WithSourceFiles() + .WithEmptyGlobalJson() .Root; if (skipRefs) @@ -386,6 +401,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson("TestAppDependencyGraph") .CreateInstance() .WithSourceFiles() + .WithEmptyGlobalJson() .Root; var project = projectDirectory @@ -408,6 +424,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance() .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; var projectDirectory = assetsDir.GetDirectory("ProjectF"); @@ -443,6 +460,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance(identifier: projectNameSuffix) .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; var projectName = $"Project{projectNameSuffix}"; @@ -532,6 +550,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance() .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; CleanBinObj(projectDirectory); @@ -551,6 +570,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance() .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; CleanBinObj(projectDirectory); @@ -570,6 +590,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson("TestAppDependencyGraph") .CreateInstance() .WithSourceFiles() + .WithEmptyGlobalJson() .Root; var projectDirectory = solutionDirectory.GetDirectory(projectName); @@ -594,6 +615,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateInstance() .WithSourceFiles() .WithRestoreFiles() + .WithEmptyGlobalJson() .Root; var expectedCsprojPath = projectDirectory.GetFile($"{projectName}.csproj"); @@ -634,6 +656,7 @@ namespace Microsoft.DotNet.Migration.Tests .GetProjectJson(projectName) .CreateInstance(identifier: projectName) .WithSourceFiles() + .WithEmptyGlobalJson() .Root; MigrateProject(projectDirectory.FullName);