diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/Program.cs b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/Program.cs new file mode 100644 index 000000000..7937a9ba0 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/Program.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace TestApp +{ + public class Program + { + public static int Main(string[] args) + { + Console.WriteLine(TestLibrary.Helper.GetMessage()); + return 0; + } + } +} diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.sln b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.sln new file mode 100644 index 000000000..0935de81a --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestApp", "TestApp.xproj", "{0138CB8F-4AA9-4029-A21E-C07C30F425BA}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestLibrary", "..\TestLibrary\TestLibrary.csproj", "{DC0B35D0-8A36-4B52-8A11-B86739F055D2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0138CB8F-4AA9-4029-A21E-C07C30F425BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0138CB8F-4AA9-4029-A21E-C07C30F425BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0138CB8F-4AA9-4029-A21E-C07C30F425BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0138CB8F-4AA9-4029-A21E-C07C30F425BA}.Release|Any CPU.Build.0 = Release|Any CPU + {DC0B35D0-8A36-4B52-8A11-B86739F055D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DC0B35D0-8A36-4B52-8A11-B86739F055D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DC0B35D0-8A36-4B52-8A11-B86739F055D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DC0B35D0-8A36-4B52-8A11-B86739F055D2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.xproj b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.xproj new file mode 100644 index 000000000..d18702195 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.xproj @@ -0,0 +1,18 @@ + + + + 14.0.23107 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 0138cb8f-4aa9-4029-a21e-c07c30f425ba + TestAppWithContents + ..\..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\..\artifacts\ + + + 2.0 + + + diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/project.json b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/project.json new file mode 100644 index 000000000..666d644b9 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/project.json @@ -0,0 +1,30 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "TestLibrary": { + "target": "project", + "version": "1.0.0-*" + }, + "Microsoft.NETCore.App": "1.0.1" + }, + "frameworks": { + "netcoreapp1.0": {} + }, + "runtimes": { + "win7-x64": {}, + "win7-x86": {}, + "osx.10.10-x64": {}, + "osx.10.11-x64": {}, + "ubuntu.14.04-x64": {}, + "ubuntu.16.04-x64": {}, + "centos.7-x64": {}, + "rhel.7.2-x64": {}, + "debian.8-x64": {}, + "fedora.23-x64": {}, + "opensuse.13.2-x64": {} + } +} diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/Helper.cs b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/Helper.cs new file mode 100644 index 000000000..6c3bc0e53 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/Helper.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace TestLibrary +{ + public static class Helper + { + public static string GetMessage() + { + return "This string came from the test library!"; + } + } +} diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.csproj b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.csproj new file mode 100644 index 000000000..2debc348d --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.csproj @@ -0,0 +1,13 @@ + + + + netstandard1.5 + TestLibrary + TestLibrary + + + + + + + diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.xproj b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.xproj new file mode 100644 index 000000000..dc8eb7060 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.xproj @@ -0,0 +1,18 @@ + + + + 14.0.23107 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + dc0b35d0-8a36-4b52-8a11-b86739f055d2 + TestAppWithContents + ..\..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\..\artifacts\ + + + 2.0 + + + diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/project.json b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/project.json new file mode 100644 index 000000000..032754312 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/project.json @@ -0,0 +1,9 @@ +{ + "version": "1.0.0-*", + "dependencies": { + "NETStandard.Library": "1.6.0" + }, + "frameworks": { + "netstandard1.5": {} + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/global.json b/TestAssets/TestProjects/ProjectsWithGlobalJson/global.json new file mode 100644 index 000000000..2b2293b26 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/global.json @@ -0,0 +1,4 @@ + +{ + "projects": [ "src", "src with spaces", "src without projects" ] +} \ No newline at end of file diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/.noautobuild b/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/Program.cs b/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/Program.cs new file mode 100644 index 000000000..db2c801fd --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/Program.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; + +namespace TestApp +{ + public class Program + { + public static int Main(string[] args) + { + Console.WriteLine("This string came from ProjectJ"); + string helperStr = TestLibrary.ProjectI.GetMessage(); + Console.WriteLine(helperStr); + return 0; + } + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/project.json b/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/project.json new file mode 100644 index 000000000..7952dd345 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/project.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "ProjectI": { + "target": "project", + "version": "1.0.0-*" + }, + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.1" + } + }, + "frameworks": { + "netcoreapp1.0": {} + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/.noautobuild b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/Program.cs b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/Program.cs new file mode 100644 index 000000000..27e455e98 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/Program.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; + +namespace TestApp +{ + public class Program + { + public static int Main(string[] args) + { + Console.WriteLine("This string came from ProjectH"); + string helperStr = TestLibrary.ProjectI.GetMessage(); + Console.WriteLine(helperStr); + return 0; + } + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/project.json b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/project.json new file mode 100644 index 000000000..7952dd345 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/project.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "ProjectI": { + "target": "project", + "version": "1.0.0-*" + }, + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.1" + } + }, + "frameworks": { + "netcoreapp1.0": {} + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/.noautobuild b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/Helper.cs b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/Helper.cs new file mode 100644 index 000000000..d92100c45 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/Helper.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace TestLibrary +{ + public static class ProjectI + { + public static string GetMessage() + { + return "This string came from ProjectI"; + } + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/project.json b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/project.json new file mode 100644 index 000000000..48bc772d8 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/project.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "nowarn": [ + "CS1591" + ], + "xmlDoc": true, + "additionalArguments": [ + "-highentropyva+" + ] + }, + "dependencies": { + "NETStandard.Library": "1.6.0" + }, + "frameworks": { + "netstandard1.5": {} + } +} diff --git a/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/App.sln b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/App.sln new file mode 100644 index 000000000..6b63b4437 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/App.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26006.2 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "src\App\App.csproj", "{DDF3765C-59FB-4AA6-BE83-779ED13AA64A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{72BFCA87-B033-4721-8712-4D12166B4A39}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|x64.ActiveCfg = Debug|x64 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|x64.Build.0 = Debug|x64 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|x86.ActiveCfg = Debug|x86 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|x86.Build.0 = Debug|x86 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|Any CPU.Build.0 = Release|Any CPU + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|x64.ActiveCfg = Release|x64 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|x64.Build.0 = Release|x64 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|x86.ActiveCfg = Release|x86 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A} = {72BFCA87-B033-4721-8712-4D12166B4A39} + EndGlobalSection +EndGlobal diff --git a/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/App.csproj b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/App.csproj new file mode 100644 index 000000000..b38669c62 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/App.csproj @@ -0,0 +1,15 @@ + + + Exe + netcoreapp1.0 + + + + + + + + + + + diff --git a/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/Program.cs b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/Program.cs new file mode 100644 index 000000000..abb853a4a --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/Program.cs @@ -0,0 +1,10 @@ +using System; + +class Program +{ + static void Main(string[] args) + { + Console.WriteLine("Hello from the main app"); + Console.WriteLine(Lib.Library.GetMessage()); + } +} diff --git a/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Lib.csproj b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Lib.csproj new file mode 100644 index 000000000..9f8bcbb51 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Lib.csproj @@ -0,0 +1,11 @@ + + + + netstandard1.4 + + + + + + + diff --git a/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Library.cs b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Library.cs new file mode 100644 index 000000000..205c42a01 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Library.cs @@ -0,0 +1,12 @@ +using System; + +namespace Lib +{ + public class Library + { + public static string GetMessage() + { + return "Message from Lib"; + } + } +} diff --git a/build/Microsoft.DotNet.Cli.DependencyVersions.props b/build/Microsoft.DotNet.Cli.DependencyVersions.props index 86351a0f6..bc2c3ca66 100644 --- a/build/Microsoft.DotNet.Cli.DependencyVersions.props +++ b/build/Microsoft.DotNet.Cli.DependencyVersions.props @@ -5,7 +5,7 @@ 2.0.0-rc3-61212-03 1.0.0-alpha-20170117-4 4.0.0-rc3 - 1.0.0-alpha-20170114-1-223 + 1.0.0-alpha-20170120-3-249 15.0.0-preview-20170106-08 1.0.0-beta1-20170108-83 diff --git a/build/Microsoft.DotNet.Cli.Test.targets b/build/Microsoft.DotNet.Cli.Test.targets index 410cd753d..59ec2aae9 100644 --- a/build/Microsoft.DotNet.Cli.Test.targets +++ b/build/Microsoft.DotNet.Cli.Test.targets @@ -1,5 +1,5 @@ - - + + / @@ -7,14 +7,11 @@ - + DependsOnTargets="BuildTests;"> : @@ -39,11 +36,10 @@ CLIBuildDll=$(CLIBuildDll); Configuration=$(Configuration); EnvironmentVariables=$(RunTestEnvironmentVariables); - TestProject=%(TestProjects.ProjectPath); - TestProjectName=%(TestProjects.OutputName); + TestProject=%(TestProjects.Identity); TestResultXmlDir=$(TestResultXmlDir); ToolPath=$(Stage0Directory); - WorkingDirectory=%(TestProjects.ProjectDir) + WorkingDirectory=$([System.IO.Directory]::GetParent(%(TestProjects.Identity))) @@ -59,7 +55,8 @@ + DependsOnTargets="Init; + SetupTestProjectData"> $(CommitCount) $(RepoRoot)/artifacts/testpackages/ @@ -74,113 +71,21 @@ - - - - - - + DependsOnTargets="PrepareTests; + CreateTestAssetPackageNuPkgs;"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/build/test/TestProjects.targets b/build/test/TestProjects.targets index 6ac27eaf9..846c7be22 100644 --- a/build/test/TestProjects.targets +++ b/build/test/TestProjects.targets @@ -1,32 +1,7 @@ - - - - - %(TestProjects.ProjectPath) - - - - - @(TestProjectInputs) - - - - - - - - %(TestProjects.ProjectPath) - - + DependsOnTargets="SetupBuildTestProjectInputs"> @@ -37,53 +12,21 @@ --> - - + test$(PathSeparator)Msbuild.Tests.Utilities$(PathSeparator)Msbuild.Tests.Utilities.csproj; + test$(PathSeparator)Performance$(PathSeparator)Performance.csproj" /> - - - - - - + - - - %(RelativeDir)**/*.* - %(RelativeDir)bin/**/*.*;%(RelativeDir)obj/**/*.* - $([System.IO.Directory]::GetParent(%(Identity))) - %(Identity) - netcoreapp1.0 - - - - $([System.IO.Path]::GetFileName(%(ProjectDir))) - - - - $(RepoRoot)%(TestProjects.RelativeDir)bin/$(Configuration)/%(TestProjects.Framework)/%(TestProjects.OutputName).dll - - - - net46 - - - - \ No newline at end of file + diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs index c0423293f..9224dfaa2 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs @@ -5,86 +5,217 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using Microsoft.DotNet.Internal.ProjectModel.Utilities; namespace Microsoft.DotNet.ProjectJsonMigration { internal class MigrationBackupPlan { + private const string TempCsprojExtention = ".migration_in_place_backup"; + private readonly FileInfo globalJson; + private readonly Dictionary> mapOfProjectBackupDirectoryToFilesToMove; + + public DirectoryInfo RootBackupDirectory { get; } + public DirectoryInfo[] ProjectBackupDirectories { get; } + + public IEnumerable FilesToMove(DirectoryInfo projectBackupDirectory) + => mapOfProjectBackupDirectoryToFilesToMove[projectBackupDirectory]; public MigrationBackupPlan( - DirectoryInfo projectDirectory, + IEnumerable projectDirectories, DirectoryInfo workspaceDirectory, Func> getFiles = null) { - if (projectDirectory == null) + if (projectDirectories == null) { - throw new ArgumentNullException(nameof(projectDirectory)); + throw new ArgumentNullException(nameof(projectDirectories)); } + + if (!projectDirectories.Any()) + { + throw new ArgumentException("No project directories provided.", nameof(projectDirectories)); + } + if (workspaceDirectory == null) { throw new ArgumentNullException(nameof(workspaceDirectory)); } - globalJson = new FileInfo(Path.Combine( - workspaceDirectory.FullName, - "global.json")); + MigrationTrace.Instance.WriteLine("Computing migration backup plan..."); - projectDirectory = new DirectoryInfo(projectDirectory.FullName.EnsureTrailingSlash()); + projectDirectories = projectDirectories.Select(pd => new DirectoryInfo(pd.FullName.EnsureTrailingSlash())); workspaceDirectory = new DirectoryInfo(workspaceDirectory.FullName.EnsureTrailingSlash()); + MigrationTrace.Instance.WriteLine($" Workspace: {workspaceDirectory.FullName}"); + foreach (var projectDirectory in projectDirectories) + { + MigrationTrace.Instance.WriteLine($" Project: {projectDirectory.FullName}"); + } + + var rootDirectory = FindCommonRootPath(projectDirectories.ToArray()) ?? workspaceDirectory; + rootDirectory = new DirectoryInfo(rootDirectory.FullName.EnsureTrailingSlash()); + + MigrationTrace.Instance.WriteLine($" Root: {rootDirectory.FullName}"); + + globalJson = new FileInfo( + Path.Combine( + workspaceDirectory.FullName, + "global.json")); + RootBackupDirectory = new DirectoryInfo( - Path.Combine( - workspaceDirectory.Parent.FullName, - "backup") + GetUniqueDirectoryPath( + Path.Combine( + rootDirectory.FullName, + "backup")) .EnsureTrailingSlash()); - ProjectBackupDirectory = new DirectoryInfo( - Path.Combine( - RootBackupDirectory.FullName, - projectDirectory.Name) - .EnsureTrailingSlash()); + MigrationTrace.Instance.WriteLine($" Root Backup: {RootBackupDirectory.FullName}"); - var relativeDirectory = PathUtility.GetRelativePath( - workspaceDirectory.FullName, - projectDirectory.FullName); + var projectBackupDirectories = new List(); + mapOfProjectBackupDirectoryToFilesToMove = new Dictionary>(); + getFiles = getFiles ?? (dir => dir.EnumerateFiles()); - getFiles = getFiles ?? - (dir => dir.EnumerateFiles()); + foreach (var projectDirectory in projectDirectories) + { + var projectBackupDirectory = ComputeProjectBackupDirectoryPath(rootDirectory, projectDirectory, RootBackupDirectory); + var filesToMove = getFiles(projectDirectory).Where(NeedsBackup); - FilesToMove = getFiles(projectDirectory) - .Where(f => f.Name == "project.json" - || f.Extension == ".xproj" - || f.FullName.EndsWith(".xproj.user") - || f.FullName.EndsWith(".lock.json")); + projectBackupDirectories.Add(projectBackupDirectory); + mapOfProjectBackupDirectoryToFilesToMove.Add(projectBackupDirectory, filesToMove); + } + + ProjectBackupDirectories = projectBackupDirectories.ToArray(); } - public DirectoryInfo ProjectBackupDirectory { get; } - - public DirectoryInfo RootBackupDirectory { get; } - - public IEnumerable FilesToMove { get; } - public void PerformBackup() { if (globalJson.Exists) { PathUtility.EnsureDirectoryExists(RootBackupDirectory.FullName); - globalJson.MoveTo(Path.Combine( - ProjectBackupDirectory.Parent.FullName, - globalJson.Name)); - } - - PathUtility.EnsureDirectoryExists(ProjectBackupDirectory.FullName); - - foreach (var file in FilesToMove) - { - file.MoveTo( + globalJson.MoveTo( Path.Combine( - ProjectBackupDirectory.FullName, file.Name)); + RootBackupDirectory.FullName, + globalJson.Name)); } + + foreach (var kvp in mapOfProjectBackupDirectoryToFilesToMove) + { + var projectBackupDirectory = kvp.Key; + var filesToMove = kvp.Value; + + PathUtility.EnsureDirectoryExists(projectBackupDirectory.FullName); + + foreach (var file in filesToMove) + { + var fileName = file.Name.EndsWith(TempCsprojExtention) + ? Path.GetFileNameWithoutExtension(file.Name) + : file.Name; + + file.MoveTo( + Path.Combine( + projectBackupDirectory.FullName, + fileName)); + } + } + } + + private static DirectoryInfo ComputeProjectBackupDirectoryPath( + DirectoryInfo rootDirectory, DirectoryInfo projectDirectory, DirectoryInfo rootBackupDirectory) + { + if (PathUtility.IsChildOfDirectory(rootDirectory.FullName, projectDirectory.FullName)) + { + var relativePath = PathUtility.GetRelativePath( + rootDirectory.FullName, + projectDirectory.FullName); + + return new DirectoryInfo( + Path.Combine( + rootBackupDirectory.FullName, + relativePath) + .EnsureTrailingSlash()); + } + + // Ensure that we use a unique name to avoid collisions as a fallback. + return new DirectoryInfo( + GetUniqueDirectoryPath( + Path.Combine( + rootBackupDirectory.FullName, + projectDirectory.Name) + .EnsureTrailingSlash())); + } + + private static bool NeedsBackup(FileInfo file) + => file.Name == "project.json" + || file.Extension == ".xproj" + || file.FullName.EndsWith(".xproj.user") + || file.FullName.EndsWith(".lock.json") + || file.FullName.EndsWith(TempCsprojExtention); + + private static string GetUniqueDirectoryPath(string directoryPath) + { + var candidatePath = directoryPath; + + var suffix = 1; + while (Directory.Exists(candidatePath)) + { + candidatePath = $"{directoryPath}_{suffix++}"; + } + + return candidatePath; + } + + private static DirectoryInfo FindCommonRootPath(DirectoryInfo[] paths) + { + var pathSplits = new string[paths.Length][]; + var shortestLength = int.MaxValue; + for (int i = 0; i < paths.Length; i++) + { + pathSplits[i] = paths[i].FullName.Split(new[] { Path.DirectorySeparatorChar }); + shortestLength = Math.Min(shortestLength, pathSplits[i].Length); + } + + var builder = new StringBuilder(); + var splitIndex = 0; + while (splitIndex < shortestLength) + { + var split = pathSplits[0][splitIndex]; + + var done = false; + for (int i = 1; i < pathSplits.Length; i++) + { + if (pathSplits[i][splitIndex] != split) + { + done = true; + break; + } + } + + if (done) + { + break; + } + + builder.Append(split); + builder.Append(Path.DirectorySeparatorChar); + splitIndex++; + } + + return new DirectoryInfo(builder.ToString().EnsureTrailingSlash()); + } + + public static void RenameCsprojFromMigrationOutputNameToTempName(string outputProject) + { + var backupFileName = $"{outputProject}{TempCsprojExtention}"; + + if (File.Exists(backupFileName)) + { + File.Delete(backupFileName); + } + + File.Move(outputProject, backupFileName); } } } diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs index 3aaeebda5..2596d8f2f 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs @@ -20,6 +20,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration { private readonly IMigrationRule _ruleSet; private readonly ProjectDependencyFinder _projectDependencyFinder = new ProjectDependencyFinder(); + private HashSet _migratedProjects = new HashSet(); public ProjectMigrator() : this(new DefaultMigrationRuleSet()) { } @@ -76,7 +77,6 @@ namespace Microsoft.DotNet.ProjectJsonMigration var settings = new MigrationSettings(projectDir, projectDir, rootSettings.MSBuildProjectTemplatePath); - MigrateProject(settings); projectMigrationReports.Add(MigrateProject(settings)); } @@ -141,13 +141,28 @@ namespace Microsoft.DotNet.ProjectJsonMigration { var migrationRuleInputs = ComputeMigrationRuleInputs(migrationSettings); var projectName = migrationRuleInputs.DefaultProjectContext.GetProjectName(); + var outputProject = Path.Combine(migrationSettings.OutputDirectory, projectName + ".csproj"); try { - if (IsMigrated(migrationSettings, migrationRuleInputs)) + if (File.Exists(outputProject)) { - MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.SkipMigrationAlreadyMigrated, nameof(ProjectMigrator), migrationSettings.ProjectDirectory)); - return new ProjectMigrationReport(migrationSettings.ProjectDirectory, projectName, skipped: true); + if (_migratedProjects.Contains(outputProject)) + { + MigrationTrace.Instance.WriteLine(String.Format( + LocalizableStrings.SkipMigrationAlreadyMigrated, + nameof(ProjectMigrator), + migrationSettings.ProjectDirectory)); + + return new ProjectMigrationReport( + migrationSettings.ProjectDirectory, + projectName, + skipped: true); + } + else + { + MigrationBackupPlan.RenameCsprojFromMigrationOutputNameToTempName(outputProject); + } } VerifyInputs(migrationRuleInputs, migrationSettings); @@ -185,7 +200,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration } } - var outputProject = Path.Combine(migrationSettings.OutputDirectory, projectName + ".csproj"); + _migratedProjects.Add(outputProject); + return new ProjectMigrationReport( migrationSettings.ProjectDirectory, projectName, @@ -286,14 +302,5 @@ namespace Microsoft.DotNet.ProjectJsonMigration File.Copy(sourceFilePath, destinationFilePath); } } - - public bool IsMigrated(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs) - { - var outputName = migrationRuleInputs.DefaultProjectContext.GetProjectName(); - - var outputProject = Path.Combine(migrationSettings.OutputDirectory, outputName + ".csproj"); - return File.Exists(outputProject); - } - } } diff --git a/src/Microsoft.DotNet.TestFramework/TestAssetInfo.cs b/src/Microsoft.DotNet.TestFramework/TestAssetInfo.cs index e1bcbcbf8..760c33ec4 100644 --- a/src/Microsoft.DotNet.TestFramework/TestAssetInfo.cs +++ b/src/Microsoft.DotNet.TestFramework/TestAssetInfo.cs @@ -346,7 +346,7 @@ namespace Microsoft.DotNet.TestFramework file.Refresh(); if (!file.Exists) { - throw new ArgumentException("Inventory file should exist."); + return Enumerable.Empty(); } var inventory = new List(); diff --git a/src/Microsoft.DotNet.TestFramework/TestDirectory.cs b/src/Microsoft.DotNet.TestFramework/TestDirectory.cs index 9705b9569..78c577f1d 100644 --- a/src/Microsoft.DotNet.TestFramework/TestDirectory.cs +++ b/src/Microsoft.DotNet.TestFramework/TestDirectory.cs @@ -30,7 +30,7 @@ namespace Microsoft.DotNet.TestFramework var testDirectory = new DirectoryInfo(path); var migrationBackupDirectory = new DirectoryInfo( - System.IO.Path.Combine(testDirectory.Parent.FullName, "backup")); + System.IO.Path.Combine(testDirectory.FullName, "backup")); if (testDirectory.Exists) { diff --git a/src/dotnet/SlnProjectCollectionExtensions.cs b/src/dotnet/SlnProjectCollectionExtensions.cs index 1e964f775..d99b34eee 100644 --- a/src/dotnet/SlnProjectCollectionExtensions.cs +++ b/src/dotnet/SlnProjectCollectionExtensions.cs @@ -10,34 +10,18 @@ namespace Microsoft.DotNet.Tools.Common { public static class SlnProjectCollectionExtensions { - public static HashSet GetReferencedSolutionFolders(this SlnProjectCollection projects) + public static IEnumerable GetProjectsByType( + this SlnProjectCollection projects, + string typeGuid) { - var referencedSolutionFolders = new HashSet(); + return projects.Where(p => p.TypeGuid == typeGuid); + } - var solutionFolderProjects = projects - .Where(p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid) - .ToList(); - - if (solutionFolderProjects.Any()) - { - var nonSolutionFolderProjects = projects - .Where(p => p.TypeGuid != ProjectTypeGuids.SolutionFolderGuid) - .ToList(); - - foreach (var project in nonSolutionFolderProjects) - { - var solutionFolders = project.GetSolutionFoldersFromProject(); - foreach (var solutionFolder in solutionFolders) - { - if (!referencedSolutionFolders.Contains(solutionFolder)) - { - referencedSolutionFolders.Add(solutionFolder); - } - } - } - } - - return referencedSolutionFolders; + public static IEnumerable GetProjectsNotOfType( + this SlnProjectCollection projects, + string typeGuid) + { + return projects.Where(p => p.TypeGuid != typeGuid); } } } diff --git a/src/dotnet/SlnProjectExtensions.cs b/src/dotnet/SlnProjectExtensions.cs index 14f730329..925089beb 100644 --- a/src/dotnet/SlnProjectExtensions.cs +++ b/src/dotnet/SlnProjectExtensions.cs @@ -12,17 +12,44 @@ namespace Microsoft.DotNet.Tools.Common { public static IList GetSolutionFoldersFromProject(this SlnProject project) { - var currentDirString = $".{Path.DirectorySeparatorChar}"; + var solutionFolders = new List(); - var directoryPath = Path.GetDirectoryName(project.FilePath); - if (directoryPath.StartsWith(currentDirString)) + var projectFilePath = project.FilePath; + if (IsPathInTreeRootedAtSolutionDirectory(projectFilePath)) { - directoryPath = directoryPath.Substring(currentDirString.Length); + var currentDirString = $".{Path.DirectorySeparatorChar}"; + if (projectFilePath.StartsWith(currentDirString)) + { + projectFilePath = projectFilePath.Substring(currentDirString.Length); + } + + var projectDirectoryPath = TrimProject(projectFilePath); + if (!string.IsNullOrEmpty(projectDirectoryPath)) + { + var solutionFoldersPath = TrimProjectDirectory(projectDirectoryPath); + if (!string.IsNullOrEmpty(solutionFoldersPath)) + { + solutionFolders.AddRange(solutionFoldersPath.Split(Path.DirectorySeparatorChar)); + } + } } - return directoryPath.StartsWith("..") - ? new List() - : new List(directoryPath.Split(Path.DirectorySeparatorChar)); + return solutionFolders; + } + + private static bool IsPathInTreeRootedAtSolutionDirectory(string path) + { + return !path.StartsWith(".."); + } + + private static string TrimProject(string path) + { + return Path.GetDirectoryName(path); + } + + private static string TrimProjectDirectory(string path) + { + return Path.GetDirectoryName(path); } } } diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-package/LocalizableStrings.cs b/src/dotnet/commands/dotnet-add/dotnet-add-package/LocalizableStrings.cs index 1290883a3..21f84fe76 100644 --- a/src/dotnet/commands/dotnet-add/dotnet-add-package/LocalizableStrings.cs +++ b/src/dotnet/commands/dotnet-add/dotnet-add-package/LocalizableStrings.cs @@ -9,7 +9,7 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference public const string AppDescription = "Command to add package reference"; - public const string AppHelpText = "Package references to add"; + public const string CmdPackageDescription = "Package references to add"; public const string SpecifyExactlyOnePackageReference = "Please specify one package reference to add."; @@ -25,6 +25,8 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference public const string CmdDGFileException = "Unable to Create Dependency graph file for project '{0}'. Cannot add package reference."; + public const string CmdPackage = "PACKAGE_NAME"; + public const string CmdVersion = "VERSION"; public const string CmdFramework = "FRAMEWORK"; diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-package/Program.cs b/src/dotnet/commands/dotnet-add/dotnet-add-package/Program.cs index 1394638e8..4f7d4f594 100644 --- a/src/dotnet/commands/dotnet-add/dotnet-add-package/Program.cs +++ b/src/dotnet/commands/dotnet-add/dotnet-add-package/Program.cs @@ -1,12 +1,6 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; using Microsoft.Build.Evaluation; using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.CommandLine; @@ -15,6 +9,12 @@ using Microsoft.DotNet.Tools.Common; using Microsoft.DotNet.Tools.MSBuild; using Microsoft.DotNet.Tools.NuGet; using NuGet.Frameworks; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; namespace Microsoft.DotNet.Tools.Add.PackageReference { @@ -25,6 +25,7 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference private CommandOption _noRestoreOption; private CommandOption _sourceOption; private CommandOption _packageDirectoryOption; + private CommandArgument _packageNameArgument; public static DotNetSubCommandBase Create() { @@ -33,12 +34,16 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference Name = "package", FullName = LocalizableStrings.AppFullName, Description = LocalizableStrings.AppDescription, - HandleRemainingArguments = true, - ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText, + HandleRemainingArguments = false }; command.HelpOption("-h|--help"); + command._packageNameArgument = command.Argument( + $"<{LocalizableStrings.CmdPackage}>", + LocalizableStrings.CmdPackageDescription, + multipleValues: false); + command._versionOption = command.Option( $"-v|--version <{LocalizableStrings.CmdVersion}>", LocalizableStrings.CmdVersionDescription, @@ -69,7 +74,7 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference public override int Run(string fileOrDirectory) { - if (RemainingArguments.Count != 1) + if (_packageNameArgument.Values.Count != 1 || string.IsNullOrWhiteSpace(_packageNameArgument.Value) || RemainingArguments.Count > 0) { throw new GracefulException(LocalizableStrings.SpecifyExactlyOnePackageReference); } @@ -94,7 +99,7 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference GetProjectDependencyGraph(projectFilePath, tempDgFilePath); } - var result = NuGetCommand.Run(TransformArgs(RemainingArguments.First(), tempDgFilePath, projectFilePath)); + var result = NuGetCommand.Run(TransformArgs(_packageNameArgument.Value, tempDgFilePath, projectFilePath)); DisposeTemporaryFile(tempDgFilePath); return result; diff --git a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs index 00c620819..70c9cd68d 100644 --- a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs +++ b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs @@ -113,22 +113,23 @@ namespace Microsoft.DotNet.Tools.Migrate return; } - List csprojFilesToAdd = new List(); + var csprojFilesToAdd = new HashSet(); var slnPathWithTrailingSlash = PathUtility.EnsureTrailingSlash(_slnFile.BaseDirectory); foreach (var report in migrationReport.ProjectMigrationReports) { var reportPathWithTrailingSlash = PathUtility.EnsureTrailingSlash(report.ProjectDirectory); - var reportRelPath = Path.Combine( - PathUtility.GetRelativePath(slnPathWithTrailingSlash, reportPathWithTrailingSlash), - report.ProjectName + ".xproj"); + var relativeReportPath = PathUtility.GetRelativePath( + slnPathWithTrailingSlash, + reportPathWithTrailingSlash); - var projects = _slnFile.Projects.Where(p => p.FilePath == reportRelPath); + var xprojPath = Path.Combine(relativeReportPath, report.ProjectName + ".xproj"); + var xprojProjectsReferencedBySolution = _slnFile.Projects.Where(p => p.FilePath == xprojPath); var migratedProjectName = report.ProjectName + ".csproj"; - if (projects.Count() == 1) + if (xprojProjectsReferencedBySolution.Count() == 1) { - var slnProject = projects.Single(); + var slnProject = xprojProjectsReferencedBySolution.Single(); slnProject.FilePath = Path.Combine( Path.GetDirectoryName(slnProject.FilePath), migratedProjectName); @@ -136,7 +137,15 @@ namespace Microsoft.DotNet.Tools.Migrate } else { - csprojFilesToAdd.Add(Path.Combine(report.ProjectDirectory, migratedProjectName)); + var csprojPath = Path.Combine(relativeReportPath, migratedProjectName); + var solutionContainsCsprojPriorToMigration = _slnFile.Projects + .Where(p => p.FilePath == csprojPath) + .Any(); + + if (!solutionContainsCsprojPriorToMigration) + { + csprojFilesToAdd.Add(Path.Combine(report.ProjectDirectory, migratedProjectName)); + } } foreach (var preExisting in report.PreExistingCsprojDependencies) @@ -211,14 +220,19 @@ namespace Microsoft.DotNet.Tools.Migrate private void BackupProjects(MigrationReport migrationReport) { + var projectDirectories = new List(); foreach (var report in migrationReport.ProjectMigrationReports) { - var backupPlan = new MigrationBackupPlan( - new DirectoryInfo(report.ProjectDirectory), - _workspaceDirectory); - - backupPlan.PerformBackup(); + projectDirectories.Add(new DirectoryInfo(report.ProjectDirectory)); } + + var backupPlan = new MigrationBackupPlan( + projectDirectories, + _workspaceDirectory); + + backupPlan.PerformBackup(); + + Reporter.Output.WriteLine($"Files backed up to {backupPlan.RootBackupDirectory.FullName}"); } private void WriteReport(MigrationReport migrationReport) @@ -310,7 +324,6 @@ namespace Microsoft.DotNet.Tools.Migrate if (projectMigrationReport.Errors.Any()) { - sb.AppendLine(RedIfColored($"Project {projectMigrationReport.ProjectName} migration failed ({projectMigrationReport.ProjectDirectory})")); foreach (var error in projectMigrationReport.Errors.Select(e => e.GetFormattedErrorMessage())) diff --git a/src/dotnet/commands/dotnet-sln/add/Program.cs b/src/dotnet/commands/dotnet-sln/add/Program.cs index 5cb8869ce..889506662 100644 --- a/src/dotnet/commands/dotnet-sln/add/Program.cs +++ b/src/dotnet/commands/dotnet-sln/add/Program.cs @@ -163,28 +163,61 @@ namespace Microsoft.DotNet.Tools.Sln.Add "NestedProjects", SlnSectionType.PreProcess); + var pathToGuidMap = GetSolutionFolderPaths(slnFile, nestedProjectsSection.Properties); + string parentDirGuid = null; + var solutionFolderHierarchy = string.Empty; foreach (var dir in solutionFolders) { - var solutionFolder = new SlnProject + solutionFolderHierarchy = Path.Combine(solutionFolderHierarchy, dir); + if (pathToGuidMap.ContainsKey(solutionFolderHierarchy)) { - Id = Guid.NewGuid().ToString("B").ToUpper(), - TypeGuid = ProjectTypeGuids.SolutionFolderGuid, - Name = dir, - FilePath = dir - }; - - slnFile.Projects.Add(solutionFolder); - - if (parentDirGuid != null) - { - nestedProjectsSection.Properties[solutionFolder.Id] = parentDirGuid; + parentDirGuid = pathToGuidMap[solutionFolderHierarchy]; + } + else + { + var solutionFolder = new SlnProject + { + Id = Guid.NewGuid().ToString("B").ToUpper(), + TypeGuid = ProjectTypeGuids.SolutionFolderGuid, + Name = dir, + FilePath = dir + }; + + slnFile.Projects.Add(solutionFolder); + + if (parentDirGuid != null) + { + nestedProjectsSection.Properties[solutionFolder.Id] = parentDirGuid; + } + parentDirGuid = solutionFolder.Id; } - parentDirGuid = solutionFolder.Id; } nestedProjectsSection.Properties[slnProject.Id] = parentDirGuid; } } + + private IDictionary GetSolutionFolderPaths(SlnFile slnFile, SlnPropertySet nestedProjects) + { + var solutionFolderPaths = new Dictionary(); + + var solutionFolderProjects = slnFile.Projects.GetProjectsByType(ProjectTypeGuids.SolutionFolderGuid); + foreach (var slnProject in solutionFolderProjects) + { + var path = slnProject.FilePath; + var id = slnProject.Id; + while (nestedProjects.ContainsKey(id)) + { + id = nestedProjects[id]; + var parentSlnProject = solutionFolderProjects.Where(p => p.Id == id).Single(); + path = Path.Combine(parentSlnProject.FilePath, path); + } + + solutionFolderPaths[path] = slnProject.Id; + } + + return solutionFolderPaths; + } } } diff --git a/src/dotnet/commands/dotnet-sln/remove/Program.cs b/src/dotnet/commands/dotnet-sln/remove/Program.cs index deb9ea72a..18f3866e5 100644 --- a/src/dotnet/commands/dotnet-sln/remove/Program.cs +++ b/src/dotnet/commands/dotnet-sln/remove/Program.cs @@ -126,10 +126,8 @@ namespace Microsoft.DotNet.Tools.Sln.Remove private void RemoveEmptySolutionFolders(SlnFile slnFile) { - var referencedSolutionFolders = slnFile.Projects.GetReferencedSolutionFolders(); - var solutionFolderProjects = slnFile.Projects - .Where(p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid) + .GetProjectsByType(ProjectTypeGuids.SolutionFolderGuid) .ToList(); if (solutionFolderProjects.Any()) @@ -138,9 +136,13 @@ namespace Microsoft.DotNet.Tools.Sln.Remove "NestedProjects", SlnSectionType.PreProcess); + var solutionFoldersInUse = GetSolutionFoldersThatContainProjectsInItsHierarchy( + slnFile, + nestedProjectsSection.Properties); + foreach (var solutionFolderProject in solutionFolderProjects) { - if (!referencedSolutionFolders.Contains(solutionFolderProject.Name)) + if (!solutionFoldersInUse.Contains(solutionFolderProject.Id)) { slnFile.Projects.Remove(solutionFolderProject); nestedProjectsSection.Properties.Remove(solutionFolderProject.Id); @@ -153,5 +155,27 @@ namespace Microsoft.DotNet.Tools.Sln.Remove } } } + + private HashSet GetSolutionFoldersThatContainProjectsInItsHierarchy( + SlnFile slnFile, + SlnPropertySet nestedProjects) + { + var solutionFoldersInUse = new HashSet(); + + var nonSolutionFolderProjects = slnFile.Projects.GetProjectsNotOfType( + ProjectTypeGuids.SolutionFolderGuid); + + foreach (var nonSolutionFolderProject in nonSolutionFolderProjects) + { + var id = nonSolutionFolderProject.Id; + while (nestedProjects.ContainsKey(id)) + { + id = nestedProjects[id]; + solutionFoldersInUse.Add(id); + } + } + + return solutionFoldersInUse; + } } } diff --git a/src/dotnet/commands/dotnet-test/LocalizableStrings.cs b/src/dotnet/commands/dotnet-test/LocalizableStrings.cs index 0f69a5cc8..af567dceb 100644 --- a/src/dotnet/commands/dotnet-test/LocalizableStrings.cs +++ b/src/dotnet/commands/dotnet-test/LocalizableStrings.cs @@ -55,5 +55,7 @@ public const string RunSettingsArgsHelpText = @"Any extra commandline runsettings arguments that should be passed to vstest. See 'dotnet vstest --help' for available options. Example: -- RunConfiguration.ResultsDirectory=""C:\users\user\desktop\Results Directory"" MSTest.DeploymentEnabled=false"; + public const string CmdResultsDirectoryDescription = @"Test results directory will be created in specified path if not exists. + Example: --results-directory "; } } diff --git a/src/dotnet/commands/dotnet-test/Program.cs b/src/dotnet/commands/dotnet-test/Program.cs index 89d0c3595..26a57f494 100644 --- a/src/dotnet/commands/dotnet-test/Program.cs +++ b/src/dotnet/commands/dotnet-test/Program.cs @@ -83,6 +83,11 @@ namespace Microsoft.DotNet.Tools.Test LocalizableStrings.CmdNoBuildDescription, CommandOptionType.NoValue); + var resultsDirectoryOption = cmd.Option( + "-r|--results-directory", + LocalizableStrings.CmdResultsDirectoryDescription, + CommandOptionType.SingleValue); + CommandOption verbosityOption = MSBuildForwardingApp.AddVerbosityOption(cmd); cmd.OnExecute(() => @@ -129,6 +134,11 @@ namespace Microsoft.DotNet.Tools.Test msbuildArgs.Add($"/p:TargetFramework={frameworkOption.Value()}"); } + if (resultsDirectoryOption.HasValue()) + { + msbuildArgs.Add($"/p:VSTestResultsDirectory={resultsDirectoryOption.Value()}"); + } + if (outputOption.HasValue()) { msbuildArgs.Add($"/p:OutputPath={outputOption.Value()}"); diff --git a/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.csproj b/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.csproj index e444481b1..b24cec34e 100644 --- a/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.csproj +++ b/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.csproj @@ -1,4 +1,4 @@ - + @@ -35,8 +35,4 @@ - - - $(DefineConstants);RELEASE - diff --git a/test/Kestrel.Tests/DotnetBuildTest.cs b/test/Kestrel.Tests/DotnetBuildTest.cs deleted file mode 100644 index fb4fc8a54..000000000 --- a/test/Kestrel.Tests/DotnetBuildTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.IO; -using Microsoft.DotNet.Tools.Test.Utilities; -using Xunit; -using Microsoft.DotNet.TestFramework; - -namespace Microsoft.DotNet.Kestrel.Tests -{ - public class DotnetBuildTest : TestBase - { - public static string KestrelPortableApp { get; } = "KestrelPortable"; - - [Fact] - public void BuildingKestrelPortableFatAppProducesExpectedArtifacts() - { - var testInstance = TestAssetsManager.CreateTestInstance("KestrelSample") - .WithLockFiles(); - - BuildAndTest(Path.Combine(testInstance.TestRoot, KestrelPortableApp)); - } - - private static void BuildAndTest(string testRoot) - { - string appName = Path.GetFileName(testRoot); - - - var result = new BuildCommand( - projectPath: testRoot) - .ExecuteWithCapturedOutput(); - - result.Should().Pass(); - - var outputBase = new DirectoryInfo(Path.Combine(testRoot, "bin", "Debug")); - - var netcoreAppOutput = outputBase.Sub("netcoreapp1.0"); - - netcoreAppOutput.Should() - .Exist().And - .OnlyHaveFiles(new[] - { - $"{appName}.deps.json", - $"{appName}.dll", - $"{appName}.pdb", - $"{appName}.runtimeconfig.json", - $"{appName}.runtimeconfig.dev.json" - }); - } - } -} diff --git a/test/Kestrel.Tests/DotnetRunTest.cs b/test/Kestrel.Tests/DotnetRunTest.cs deleted file mode 100644 index 121c97a05..000000000 --- a/test/Kestrel.Tests/DotnetRunTest.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.IO; -using Microsoft.DotNet.TestFramework; -using Microsoft.DotNet.Tools.Test.Utilities; -using Xunit; -using System.Net.Http; -using System.Threading.Tasks; -using FluentAssertions; - -namespace Microsoft.DotNet.Kestrel.Tests -{ - public class DotnetRunTest : TestBase - { - private const string KestrelSampleBase = "KestrelSample"; - private const string KestrelPortable = "KestrelPortable"; - private const string KestrelStandalone = "KestrelStandalone"; - - [Fact] - public void ItRunsKestrelPortableApp() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var runCommand = new RunCommand(Path.Combine(instance.TestRoot, KestrelPortable)); - - try - { - runCommand.ExecuteAsync(args); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelPortable} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - runCommand.KillTree(); - } - } - - [Fact] - public void ItRunsKestrelStandaloneApp() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var runCommand = new RunCommand(Path.Combine(instance.TestRoot, KestrelStandalone)); - - try - { - runCommand.ExecuteAsync(args); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelStandalone} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - runCommand.KillTree(); - } - } - } -} diff --git a/test/Kestrel.Tests/DotnetTest.cs b/test/Kestrel.Tests/DotnetTest.cs deleted file mode 100644 index 4953e89fa..000000000 --- a/test/Kestrel.Tests/DotnetTest.cs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.DotNet.TestFramework; -using Microsoft.DotNet.Tools.Test.Utilities; -using Xunit; -using System.Threading.Tasks; -using FluentAssertions; - -namespace Microsoft.DotNet.Kestrel.Tests -{ - public class DotnetTest : TestBase - { - private const string KestrelSampleBase = "KestrelSample"; - private const string KestrelPortable = "KestrelPortable"; - private const string KestrelStandalone = "KestrelStandalone"; - - [Fact] - public void ItRunsKestrelPortableAfterBuild() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var dotnetCommand = new DotnetCommand(); - var output = Build(Path.Combine(instance.TestRoot, KestrelPortable)); - - try - { - dotnetCommand.ExecuteAsync($"{output} {args}"); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelPortable} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - dotnetCommand.KillTree(); - } - } - - [Fact] - public void ItRunsKestrelStandaloneAfterBuild() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var dotnetCommand = new DotnetCommand(); - var output = Build(Path.Combine(instance.TestRoot, KestrelStandalone)); - - try - { - dotnetCommand.ExecuteAsync($"{output} {args}"); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelStandalone} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - dotnetCommand.KillTree(); - } - } - - [Fact] - public void ItRunsKestrelPortableAfterPublish() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var dotnetCommand = new DotnetCommand(); - var output = Publish(Path.Combine(instance.TestRoot, KestrelPortable), true); - - try - { - dotnetCommand.ExecuteAsync($"{output} {args}"); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelPortable} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - dotnetCommand.KillTree(); - } - } - - [Fact] - public void ItRunsKestrelStandaloneAfterPublish() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var output = Publish(Path.Combine(instance.TestRoot, KestrelStandalone), false); - var command = new TestCommand(output); - - try - { - command.ExecuteAsync($"{args}"); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelStandalone} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - command.KillTree(); - } - } - - private static string Build(string testRoot) - { - string appName = Path.GetFileName(testRoot); - - var result = new BuildCommand( - projectPath: testRoot) - .ExecuteWithCapturedOutput(); - - result.Should().Pass(); - - // the correct build assembly is next to its deps.json file - var depsJsonFile = Directory.EnumerateFiles(testRoot, appName + FileNameSuffixes.DepsJson, SearchOption.AllDirectories).First(); - return Path.Combine(Path.GetDirectoryName(depsJsonFile), appName + ".dll"); - } - - private static string Publish(string testRoot, bool isPortable) - { - string appName = Path.GetFileName(testRoot); - - var publishCmd = new PublishCommand(projectPath: testRoot, output: Path.Combine(testRoot, "bin")); - var result = publishCmd.ExecuteWithCapturedOutput(); - result.Should().Pass(); - - var publishDir = publishCmd.GetOutputDirectory(portable: isPortable).FullName; - return Path.Combine(publishDir, appName + (isPortable ? ".dll" : FileNameSuffixes.CurrentPlatform.Exe)); - } - } -} diff --git a/test/Kestrel.Tests/Kestrel.Tests.csproj b/test/Kestrel.Tests/Kestrel.Tests.csproj deleted file mode 100644 index 7542b751f..000000000 --- a/test/Kestrel.Tests/Kestrel.Tests.csproj +++ /dev/null @@ -1,49 +0,0 @@ - - - - - netcoreapp1.0 - true - Kestrel.Tests - $(PackageTargetFallback);dotnet5.4;portable-net451+win8 - - - - - - - true - - - true - - - - - - true - - - - - - 15.0.0-preview-20161024-02 - - - 2.2.0-beta4-build1194 - - - 1.0.3 - - - 4.1.1 - - - 2.2.0-beta4-build3444 - - - - - $(DefineConstants);RELEASE - - diff --git a/test/Microsoft.DotNet.Cli.Tests.sln b/test/Microsoft.DotNet.Cli.Tests.sln index 8d1578038..dd933551d 100644 --- a/test/Microsoft.DotNet.Cli.Tests.sln +++ b/test/Microsoft.DotNet.Cli.Tests.sln @@ -38,10 +38,6 @@ Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "crossgen.Tests", "crossgen. EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "binding-redirects.Tests", "binding-redirects.Tests\binding-redirects.Tests.csproj", "{18702FC5-7B1A-49B7-A335-A926064D577A}" EndProject -Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Microsoft.DotNet.Cli.Msi.Tests", "Installer\Microsoft.DotNet.Cli.Msi.Tests\Microsoft.DotNet.Cli.Msi.Tests.csproj", "{2867CE61-92A5-49EC-B9F5-424655257069}" -EndProject -Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Kestrel.Tests", "Kestrel.Tests\Kestrel.Tests.csproj", "{642A0997-86E6-40E6-8E74-BFE2DC7C4A58}" -EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "ArgumentForwardingTests", "ArgumentForwardingTests\ArgumentForwardingTests.csproj", "{67418187-0CF6-4213-87D0-5B9B841FD755}" EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "ArgumentsReflector", "ArgumentsReflector\ArgumentsReflector.csproj", "{8818FEBB-7243-4AB5-9E1C-179F5189FBD7}" @@ -62,8 +58,6 @@ Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "EndToEnd", "EndToEnd\EndToE EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "dotnet.Tests", "dotnet.Tests\dotnet.Tests.csproj", "{B4B5DA8E-E2EA-49CB-8B8C-4E157D42E710}" EndProject -Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Performance", "Performance\Performance.csproj", "{2CD55F27-3755-4E7D-8524-81B0BBCB93A4}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet-sln-add.Tests", "dotnet-sln-add.Tests", "{5FF48976-B083-4E3B-A8E7-6FCD225D5C8E}" EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "dotnet-sln-add.Tests", "dotnet-sln-add.Tests\dotnet-sln-add.Tests.csproj", "{FC849626-89C9-4F50-A2CA-53C4315A87F8}" @@ -76,6 +70,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet-sln-remove.Tests", " EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "dotnet-sln-remove.Tests", "dotnet-sln-remove.Tests\dotnet-sln-remove.Tests.csproj", "{92BA9F90-E25B-4A1C-9598-2295D3DFC12F}" EndProject +Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "dotnet-add-package.Tests", "dotnet-add-package.Tests\dotnet-add-package.Tests.csproj", "{3501AB72-3E05-45EE-9000-9515F5A139AC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -158,14 +154,6 @@ Global {18702FC5-7B1A-49B7-A335-A926064D577A}.Debug|Any CPU.Build.0 = Debug|Any CPU {18702FC5-7B1A-49B7-A335-A926064D577A}.Release|Any CPU.ActiveCfg = Release|Any CPU {18702FC5-7B1A-49B7-A335-A926064D577A}.Release|Any CPU.Build.0 = Release|Any CPU - {2867CE61-92A5-49EC-B9F5-424655257069}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2867CE61-92A5-49EC-B9F5-424655257069}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2867CE61-92A5-49EC-B9F5-424655257069}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2867CE61-92A5-49EC-B9F5-424655257069}.Release|Any CPU.Build.0 = Release|Any CPU - {642A0997-86E6-40E6-8E74-BFE2DC7C4A58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {642A0997-86E6-40E6-8E74-BFE2DC7C4A58}.Debug|Any CPU.Build.0 = Debug|Any CPU - {642A0997-86E6-40E6-8E74-BFE2DC7C4A58}.Release|Any CPU.ActiveCfg = Release|Any CPU - {642A0997-86E6-40E6-8E74-BFE2DC7C4A58}.Release|Any CPU.Build.0 = Release|Any CPU {67418187-0CF6-4213-87D0-5B9B841FD755}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {67418187-0CF6-4213-87D0-5B9B841FD755}.Debug|Any CPU.Build.0 = Debug|Any CPU {67418187-0CF6-4213-87D0-5B9B841FD755}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -206,10 +194,6 @@ Global {B4B5DA8E-E2EA-49CB-8B8C-4E157D42E710}.Debug|Any CPU.Build.0 = Debug|Any CPU {B4B5DA8E-E2EA-49CB-8B8C-4E157D42E710}.Release|Any CPU.ActiveCfg = Release|Any CPU {B4B5DA8E-E2EA-49CB-8B8C-4E157D42E710}.Release|Any CPU.Build.0 = Release|Any CPU - {2CD55F27-3755-4E7D-8524-81B0BBCB93A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2CD55F27-3755-4E7D-8524-81B0BBCB93A4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2CD55F27-3755-4E7D-8524-81B0BBCB93A4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2CD55F27-3755-4E7D-8524-81B0BBCB93A4}.Release|Any CPU.Build.0 = Release|Any CPU {FC849626-89C9-4F50-A2CA-53C4315A87F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FC849626-89C9-4F50-A2CA-53C4315A87F8}.Debug|Any CPU.Build.0 = Debug|Any CPU {FC849626-89C9-4F50-A2CA-53C4315A87F8}.Debug|x64.ActiveCfg = Debug|x64 @@ -246,6 +230,18 @@ Global {92BA9F90-E25B-4A1C-9598-2295D3DFC12F}.Release|x64.Build.0 = Release|x64 {92BA9F90-E25B-4A1C-9598-2295D3DFC12F}.Release|x86.ActiveCfg = Release|x86 {92BA9F90-E25B-4A1C-9598-2295D3DFC12F}.Release|x86.Build.0 = Release|x86 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|x64.ActiveCfg = Debug|x64 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|x64.Build.0 = Debug|x64 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|x86.ActiveCfg = Debug|x86 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|x86.Build.0 = Debug|x86 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|Any CPU.Build.0 = Release|Any CPU + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|x64.ActiveCfg = Release|x64 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|x64.Build.0 = Release|x64 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|x86.ActiveCfg = Release|x86 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/MigrationBackupPlanTests.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/MigrationBackupPlanTests.cs index b54f265b0..227cef562 100644 --- a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/MigrationBackupPlanTests.cs +++ b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/MigrationBackupPlanTests.cs @@ -5,6 +5,7 @@ using FluentAssertions; using Microsoft.DotNet.Internal.ProjectModel.Utilities; using Microsoft.DotNet.ProjectJsonMigration; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Xunit; @@ -14,81 +15,123 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests public partial class MigrationBackupPlanTests { [Fact] - public void TheRootBackupDirectoryIsASiblingOfTheRootProject() + public void TheBackupDirectoryIsASubfolderOfTheMigratedProject() { - var dir = new DirectoryInfo(Path.Combine("src", "some-proj")); + var workspaceDirectory = Path.Combine("src", "root"); + var projectDirectory = Path.Combine("src", "project1"); - System.Console.WriteLine(dir.FullName); - - WhenMigrating( - projectDirectory: dir.FullName, - workspaceDirectory: Path.Combine("src", "RootProject")) - .RootBackupDirectory - .FullName - .Should() - .Be(new DirectoryInfo(Path.Combine("src", "backup")).FullName.EnsureTrailingSlash()); + WhenMigrating(projectDirectory, workspaceDirectory) + .RootBackupDirectory + .FullName + .Should() + .Be(new DirectoryInfo(Path.Combine("src", "project1", "backup")).FullName.EnsureTrailingSlash()); } [Fact] - public void TheRootProjectsBackupDirectoryIsASubfolderOfTheRootBackupDirectory() + public void TheBackupDirectoryIsASubfolderOfTheMigratedProjectWhenInitiatedFromProjectFolder() { - WhenMigrating( - projectDirectory: Path.Combine("src", "RootProject"), - workspaceDirectory: Path.Combine("src", "RootProject")) - .ProjectBackupDirectory - .FullName - .Should() - .Be(new DirectoryInfo(Path.Combine("src", "backup", "RootProject")).FullName.EnsureTrailingSlash()); + var workspaceDirectory = Path.Combine("src", "root"); + var projectDirectory = Path.Combine("src", "root"); + + WhenMigrating(projectDirectory, workspaceDirectory) + .ProjectBackupDirectories.Single() + .FullName + .Should() + .Be(new DirectoryInfo(Path.Combine("src", "root", "backup")).FullName.EnsureTrailingSlash()); } [Fact] - public void ADependentProjectsMigrationBackupDirectoryIsASubfolderOfTheRootBackupDirectory() + public void TheBackupDirectoryIsInTheCommonRootOfTwoProjectFoldersWhenInitiatedFromProjectFolder() { - WhenMigrating( - projectDirectory: Path.Combine("src", "Dependency"), - workspaceDirectory: Path.Combine("src", "RootProject")) - .ProjectBackupDirectory - .FullName - .Should() - .Be(new DirectoryInfo(Path.Combine("src", "backup", "Dependency")).FullName.EnsureTrailingSlash()); + var projectDirectories = new [] + { + Path.Combine("root", "project1"), + Path.Combine("root", "project2") + }; + + var workspaceDirectory = Path.Combine("root", "project1"); + + WhenMigrating(projectDirectories, workspaceDirectory) + .RootBackupDirectory + .FullName + .Should() + .Be(new DirectoryInfo(Path.Combine("root", "backup")).FullName.EnsureTrailingSlash()); } [Fact] - public void FilesToBackUpAreIdentifiedInTheTheRootProjectDirectory() + public void TheBackupDirectoryIsInTheCommonRootOfTwoProjectFoldersWhenInitiatedFromCommonRoot() { - var root = new DirectoryInfo(Path.Combine("src", "RootProject")); + var projectDirectories = new [] + { + Path.Combine("root", "project1"), + Path.Combine("root", "project2") + }; - WhenMigrating( - projectDirectory: root.FullName, - workspaceDirectory: root.FullName) - .FilesToMove - .Should() - .Contain(_ => _.FullName == Path.Combine(root.FullName, "project.json")); + var workspaceDirectory = Path.Combine("root"); + WhenMigrating(projectDirectories, workspaceDirectory) + .RootBackupDirectory + .FullName + .Should() + .Be(new DirectoryInfo(Path.Combine("root", "backup")).FullName.EnsureTrailingSlash()); } [Fact] - public void FilesToBackUpAreIdentifiedInTheTheDependencyProjectDirectory() + public void TheBackupDirectoryIsInTheCommonRootOfTwoProjectFoldersAtDifferentLevelsWhenInitiatedFromProjectFolder() { - var root = new DirectoryInfo(Path.Combine("src", "RootProject")); - var dependency = new DirectoryInfo(Path.Combine("src", "RootProject")); + var projectDirectories = new [] + { + Path.Combine("root", "tests", "inner", "project1"), + Path.Combine("root", "src", "project2") + }; - WhenMigrating( - projectDirectory: dependency.FullName, - workspaceDirectory: root.FullName) - .FilesToMove - .Should() - .Contain(_ => _.FullName == Path.Combine(dependency.FullName, "project.json")); + var workspaceDirectory = Path.Combine("root", "tests", "inner"); + WhenMigrating(projectDirectories, workspaceDirectory) + .RootBackupDirectory + .FullName + .Should() + .Be(new DirectoryInfo(Path.Combine("root", "backup")).FullName.EnsureTrailingSlash()); } - private MigrationBackupPlan WhenMigrating( - string projectDirectory, - string workspaceDirectory) => + [Fact] + public void FilesToBackUpAreIdentifiedInTheRootProjectDirectory() + { + var workspaceDirectory = Path.Combine("src", "root"); + var projectDirectory = Path.Combine("src", "root"); + + var whenMigrating = WhenMigrating(projectDirectory, workspaceDirectory); + + whenMigrating + .FilesToMove(whenMigrating.ProjectBackupDirectories.Single()) + .Should() + .Contain(_ => _.FullName == Path.Combine(new DirectoryInfo(workspaceDirectory).FullName, "project.json")); + } + + [Fact] + public void FilesToBackUpAreIdentifiedInTheDependencyProjectDirectory() + { + var workspaceDirectory = Path.Combine("src", "root"); + var projectDirectory = Path.Combine("src", "root"); + + var whenMigrating = WhenMigrating(projectDirectory, workspaceDirectory); + + whenMigrating + .FilesToMove(whenMigrating.ProjectBackupDirectories.Single()) + .Should() + .Contain(_ => _.FullName == Path.Combine(new DirectoryInfo(projectDirectory).FullName, "project.json")); + } + + private MigrationBackupPlan WhenMigrating(string projectDirectory, string workspaceDirectory) => new MigrationBackupPlan( - new DirectoryInfo(projectDirectory), + new [] { new DirectoryInfo(projectDirectory) }, new DirectoryInfo(workspaceDirectory), - dir => new[] { new FileInfo(Path.Combine(dir.FullName, "project.json")) }); + dir => new [] { new FileInfo(Path.Combine(dir.FullName, "project.json")) }); + private MigrationBackupPlan WhenMigrating(string[] projectDirectories, string workspaceDirectory) => + new MigrationBackupPlan( + projectDirectories.Select(p => new DirectoryInfo(p)), + new DirectoryInfo(workspaceDirectory), + dir => new [] { new FileInfo(Path.Combine(dir.FullName, "project.json")) }); } } diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Tests.Utilities.csproj b/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Tests.Utilities.csproj index e353bcbfe..32a322248 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Tests.Utilities.csproj +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Tests.Utilities.csproj @@ -3,7 +3,7 @@ Microsoft.DotNet.Tools.Tests.Utilities Class Library - netcoreapp1.0;net46 + netcoreapp1.0 true Microsoft.DotNet.Tools.Tests.Utilities ../../tools/Key.snk diff --git a/test/Performance/.gitignore b/test/Performance/.gitignore deleted file mode 100644 index c52d34fee..000000000 --- a/test/Performance/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/*.html -/*.csv -/*.xml -/*.xml.bak diff --git a/test/Performance/BuildPerformanceTest.cs b/test/Performance/BuildPerformanceTest.cs deleted file mode 100644 index b3e649a72..000000000 --- a/test/Performance/BuildPerformanceTest.cs +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Microsoft.DotNet.Tools.Test.Utilities; -using Microsoft.Xunit.Performance; -using Microsoft.DotNet.TestFramework; -using System.IO; -using System.Runtime.CompilerServices; -using System; -using System.Collections.Generic; - -namespace Microsoft.DotNet.Tools.Builder.Tests -{ - public class BuildPerformanceTest : TestBase - { - private static string SingleTargetApp = "SingleTargetApp"; - private static string TwoTargetApp = "TwoTargetApp"; - - private static string[] SingleTargetGraph = new[] - { - "SingleTargetGraph/SingleTargetP0", - "SingleTargetGraph/SingleTargetP1", - "SingleTargetGraph/SingleTargetP2" - }; - - private static string[] TwoTargetGraph = new[] - { - "TwoTargetGraph/TwoTargetP0", - "TwoTargetGraph/TwoTargetP1", - "TwoTargetGraph/TwoTargetP2" - }; - - private static string[] TwoTargetGraphLarge = new[] - { - "TwoTargetGraphLarge/TwoTargetLargeP0", - "TwoTargetGraphLarge/TwoTargetLargeP1", - "TwoTargetGraphLarge/TwoTargetLargeP2", - "TwoTargetGraphLarge/TwoTargetLargeP3", - "TwoTargetGraphLarge/TwoTargetLargeP4", - "TwoTargetGraphLarge/TwoTargetLargeP5", - "TwoTargetGraphLarge/TwoTargetLargeP6" - }; - - [Benchmark] - public void BuildSingleProject_SingleTargetApp() => BuildSingleProject(CreateTestInstance(SingleTargetApp)); - - [Benchmark] - public void BuildSingleProject_TwoTargetApp() => BuildSingleProject(CreateTestInstance(TwoTargetApp)); - - public void BuildSingleProject(TestAssetInstance instance) - { - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand.Execute() - .Should().Pass(); - } - - TouchSource(instance.Root); - } - } - - [Benchmark] - public void IncrementalSkipSingleProject_SingleTargetApp() => IncrementalSkipSingleProject(CreateTestInstance(SingleTargetApp)); - - [Benchmark] - public void IncrementalSkipSingleProject_TwoTargetApp() => IncrementalSkipSingleProject(CreateTestInstance(TwoTargetApp)); - - public void IncrementalSkipSingleProject(TestAssetInstance instance) - { - new BuildCommand() - .WithProjectDirectory(instance.Root) - .Execute() - .Should().Pass(); - - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand - .Execute() - .Should().Pass(); - } - } - } - - [Benchmark] - public void BuildAllInGraph_SingleTargetGraph() => BuildAllInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void BuildAllInGraph_TwoTargetGraph() => BuildAllInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void BuildAllInGraph_TwoTargetGraphLarge() => BuildAllInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void BuildAllInGraph(TestAssetInstance[] instances) - { - var instance = instances[0]; - - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand - .Execute() - .Should().Pass(); - } - - foreach (var i in instances) - { - TouchSource(i.Root); - } - } - } - - [Benchmark] - public void IncrementalSkipAllInGraph_SingleTargetGraph() => - IncrementalSkipAllInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void IncrementalSkipAllInGraph_TwoTargetGraph() => - IncrementalSkipAllInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void IncrementalSkipAllInGraphh_TwoTargetGraphLarge() => - IncrementalSkipAllInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void IncrementalSkipAllInGraph(TestAssetInstance[] instances) - { - var instance = instances[0]; - - new BuildCommand() - .WithProjectDirectory(instance.Root) - .Execute() - .Should().Pass(); - - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand - .Execute() - .Should().Pass(); - } - } - } - - [Benchmark] - public void IncrementalRebuildWithRootChangedInGraph_SingleTargetGraph() => - IncrementalRebuildWithRootChangedInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void IncrementalRebuildWithRootChangedInGraph_TwoTargetGraph() => - IncrementalRebuildWithRootChangedInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void IncrementalRebuildWithRootChangedInGraph_TwoTargetGraphLarge() => - IncrementalRebuildWithRootChangedInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void IncrementalRebuildWithRootChangedInGraph(TestAssetInstance[] instances) - { - var instance = instances[0]; - new BuildCommand() - .WithProjectDirectory(instance.Root) - .Execute() - .Should().Pass(); - - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand - .Execute() - .Should().Pass(); - } - - TouchSource(instance.Root); - } - } - - [Benchmark] - public void IncrementalRebuildWithLastChangedInGraph_SingleTargetGraph() => - IncrementalRebuildWithLastChangedInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void IncrementalRebuildWithLastChangedInGraph_TwoTargetGraph() => - IncrementalRebuildWithLastChangedInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void IncrementalRebuildWithLastChangedInGraph_TwoTargetGraphLarge() => - IncrementalRebuildWithLastChangedInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void IncrementalRebuildWithLastChangedInGraph(TestAssetInstance[] instances) - { - var instance = instances[0]; - - new BuildCommand() - .WithProjectDirectory(instance.Root) - .Execute() - .Should().Pass(); - - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand - .Execute() - .Should().Pass(); - } - - TouchSource(instances.Last().Root); - } - } - - - [Benchmark] - public void IncrementalSkipAllNoDependenciesInGraph_SingleTargetGraph() => - IncrementalSkipAllNoDependenciesInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void IncrementalSkipAllNoDependenciesInGraph_TwoTargetGraph() => - IncrementalSkipAllNoDependenciesInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void IncrementalSkipAllNoDependenciesInGraph_TwoTargetGraphLarge() => - IncrementalSkipAllNoDependenciesInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void IncrementalSkipAllNoDependenciesInGraph(TestAssetInstance[] instances) - { - var instance = instances[0]; - - new BuildCommand() - .WithProjectDirectory(instance.Root) - .Execute() - .Should().Pass(); - - foreach (var iteration in Benchmark.Iterations) - { - var commands = new List(); - - foreach (var i in instances.Reverse()) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root) - .WithFramework(NuGet.Frameworks.FrameworkConstants.CommonFrameworks.NetCoreApp10) - .WithNoDependencies(); - - commands.Add(buildCommand); - } - - using (iteration.StartMeasurement()) - { - foreach (var buildCommand in commands) - { - buildCommand - .Execute() - .Should().Pass(); - } - } - } - } - [Benchmark] - public void BuildAllNoDependenciesInGraph_SingleTargetGraph() => - BuildAllNoDependenciesInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void BuildAllNoDependenciesInGraph_TwoTargetGraph() => - BuildAllNoDependenciesInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void BuildAllNoDependenciesInGraph_TwoTargetGraphLarge() => - BuildAllNoDependenciesInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void BuildAllNoDependenciesInGraph(TestAssetInstance[] instances) - { - foreach (var iteration in Benchmark.Iterations) - { - var commands = new List(); - - foreach (var i in instances.Reverse()) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(i.Root) - .WithFramework(NuGet.Frameworks.FrameworkConstants.CommonFrameworks.NetCoreApp10) - .WithNoDependencies(); - - commands.Add(buildCommand); - } - - using (iteration.StartMeasurement()) - { - foreach (var buildCommand in commands) - { - buildCommand.Execute().Should().Pass(); - } - } - - foreach (var instance in instances) - { - TouchSource(instance.Root); - } - } - } - - protected void TouchSource(DirectoryInfo projectDir) - { - var sourceFile = projectDir.GetFiles("*.cs", SearchOption.AllDirectories).FirstOrDefault(); - - if (sourceFile == null) - { - throw new InvalidOperationException($"'.cs' files not found in {projectDir.FullName}"); - } - - sourceFile.LastWriteTime = DateTime.Now; - } - - protected TestAssetInstance[] CreateTestInstances(string[] testProjectNames, [CallerMemberName] string callingMethod = "") - { - return testProjectNames.Select(testProjectName => - { - return CreateTestInstance(testProjectName, callingMethod); - }).ToArray(); - } - - protected TestAssetInstance CreateTestInstance(string testProjectName, [CallerMemberName] string callingMethod = "") - { - return TestAssets.Get(Path.Combine("PerformanceTestProjects", testProjectName)) - .CreateInstance(callingMethod) - .WithSourceFiles() - .WithRestoreFiles(); - } - } -} diff --git a/test/Performance/HelloWorld.cs b/test/Performance/HelloWorld.cs deleted file mode 100644 index 4ff927437..000000000 --- a/test/Performance/HelloWorld.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.IO; -using Microsoft.DotNet.Tools.Test.Utilities; -using Microsoft.Xunit.Performance; - -namespace Microsoft.DotNet.Tests.Performance -{ - public class HelloWorld : TestBase - { - private static readonly string s_testdirName = "helloworldtestroot"; - private static readonly string s_testProject = $"{s_testdirName}.csproj"; - private static readonly string s_outputdirName = "test space/bin"; - - private static string AssetsRoot { get; set; } - private static string RestoredTestProjectDirectory { get; set; } - - private string ProjectPath { get; set; } - private string TestDirectory { get; set; } - private string OutputDirectory { get; set; } - - static HelloWorld() - { - HelloWorld.SetupStaticTestProject(); - } - - public HelloWorld() - { - } - - [Benchmark] - public void MeasureDotNetBuild() - { - foreach (var iter in Benchmark.Iterations) - { - // Setup a new instance of the test project. - TestInstanceSetup(); - - // Setup the build command. - var buildCommand = new BuildCommand(); - using (iter.StartMeasurement()) - { - // Execute the build command. - buildCommand.Execute($"{ProjectPath} --output \"{OutputDirectory}\" --framework {DefaultFramework}"); - } - } - } - - private void TestInstanceSetup() - { - var root = Temp.CreateDirectory(); - - var testInstanceDir = root.CopyDirectory(RestoredTestProjectDirectory); - - TestDirectory = testInstanceDir.Path; - OutputDirectory = Path.Combine(TestDirectory, s_outputdirName); - ProjectPath = Path.Combine(TestDirectory, s_testProject); - } - - private static void SetupStaticTestProject() - { - AssetsRoot = Path.Combine(AppContext.BaseDirectory, "bin"); - RestoredTestProjectDirectory = Path.Combine(AssetsRoot, s_testdirName); - - // Ignore Delete Failure - try - { - Directory.Delete(RestoredTestProjectDirectory, true); - } - catch (Exception) { } - - Directory.CreateDirectory(RestoredTestProjectDirectory); - - // Todo: this is a hack until corefx is on nuget.org remove this After RC 2 Release - NuGetConfig.Write(RestoredTestProjectDirectory); - - var newCommand = new NewCommand(); - newCommand.WorkingDirectory = RestoredTestProjectDirectory; - newCommand.Execute().Should().Pass(); - - var restoreCommand = new RestoreCommand(); - restoreCommand.WorkingDirectory = RestoredTestProjectDirectory; - restoreCommand.Execute("/p:SkipInvalidConfigurations=true") - .Should().Pass(); - } - } -} diff --git a/test/Performance/Performance.csproj b/test/Performance/Performance.csproj deleted file mode 100644 index 71c2123ca..000000000 --- a/test/Performance/Performance.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - - netcoreapp1.0 - true - Performance - $(PackageTargetFallback);dotnet5.4;portable-net451+win8 - - - - - - - true - - - true - - - - - - true - - - - - - 15.0.0-preview-20161024-02 - - - 2.2.0-beta4-build1194 - - - 1.0.3 - - - 4.1.1 - - - 2.2.0-beta4-build3444 - - - 1.0.0-prerelease-00206 - - - 1.0.0-alpha-build0028 - - - - - $(DefineConstants);RELEASE - - diff --git a/test/Performance/README.md b/test/Performance/README.md deleted file mode 100644 index 7a23147a9..000000000 --- a/test/Performance/README.md +++ /dev/null @@ -1,54 +0,0 @@ -Running Performance Tests -========================= - -Pre-Requisites --------------- - -* Python 2.7+ or 3.5+ -* msbuild.exe (must be on `PATH`) - -Single Perf Run ---------------- - -1. Build the CLI repo to get dotnet.exe, or otherwise source the CLI. For - meaningful perf results, be sure to use release mode. - -2. `cd /test/Performance` - -3. `python run-perftests.py --name - --xunit-perf-path ` - where: - * `` is the path to the dotnet binary whose perf you want to - measure. - * `` should point either to an non-existent directory, or to - the root of a local clone of xunit-performance. If a non-existent - directory is specified, the repo will automatically be cloned. - - NOTE: You can also set the environment variable - `XUNIT_PERFORMANCE_PATH` to avoid having to pass this variable every - time. - -4. View the `*.csv` / `*.xml` results in the current directory. - -Comparison Run --------------- - -In general, follow the same steps as for a single perf run. The following -additional steps are required: - -1. In addition to the dotnet.exe that you're testing, be sure to also build or - otherwise source the baseline dotnet.exe. This could be the "stage0" exe, or - the exe from the last nightly build, or the exe built from sources prior to - changes you made, etc. - -2. When invoking `run-perftests.py`, add an additional parameter: `--base - `, which points to the baseline dotnet.exe mentioned in step 1. - -3. View the `*.html` file generated for the perf comparison analysis. - -Debugging Issues ----------------- - -The output of commands invoked by `run-perftests` is hidden by default. You can -see the output after an error by looking in the `logs/run-perftests` directory. -Alternatively, you can rerun `run-perftests` with `--verbose`, which will print -all output to the console instead of piping it to log files. diff --git a/test/Performance/run-perftests.py b/test/Performance/run-perftests.py deleted file mode 100644 index c19c2cd1c..000000000 --- a/test/Performance/run-perftests.py +++ /dev/null @@ -1,249 +0,0 @@ -#!/usr/bin/env python - -import argparse -import glob -import os -import re -import subprocess -import sys - -SCRIPT_ROOT_PATH = os.path.dirname(os.path.realpath(__file__)) -PERFTEST_JSON_PATH = os.path.join(SCRIPT_ROOT_PATH, 'project.json') -XUNITPERF_REPO_URL = 'https://github.com/microsoft/xunit-performance.git' - -script_args = None - -class FatalError(Exception): - def __init__(self, message): - self.message = message - -def check_requirements(): - try: - run_command('git', '--version', quiet = True) - except: - raise FatalError("git not found, please make sure that it's installed and on path.") - - try: - run_command('msbuild', '-version', quiet = True) - except: - raise FatalError("msbuild not found, please make sure that it's installed and on path.") - - if script_args.xunit_perf_path == None: - raise FatalError("Don't know where to clone xunit-performance. Please specify --xunit-perf-path . " + - "You can also set/export XUNIT_PERFORMANCE_PATH to not have to set the value every time.") - -def process_arguments(): - parser = argparse.ArgumentParser( - description = "Runs CLI perf tests. Requires 'git' and 'msbuild' to be on the PATH.", - ) - - parser.add_argument( - 'test_cli', - help = "full path to the dotnet.exe under test", - ) - parser.add_argument( - '--runid', '--name', '-n', - help = "unique ID for this run", - required = True, - ) - parser.add_argument( - '--base', '--baseline', '-b', - help = "full path to the baseline dotnet.exe", - metavar = 'baseline_cli', - dest = 'base_cli', - ) - parser.add_argument( - '--xunit-perf-path', '-x', - help = """Path to local copy of the xunit-performance repository. - Required unless the environment variable XUNIT_PERFORMANCE_PATH is defined.""", - default = os.environ.get('XUNIT_PERFORMANCE_PATH'), - metavar = 'path', - ) - parser.add_argument( - '--rebuild', '--rebuild-tools', '-r', - help = "Rebuilds the test tools from scratch.", - action = 'store_true', - ) - parser.add_argument( - '--verbose', '-v', - help = "Shows the output of all commands run by this script", - action = 'store_true', - ) - - global script_args - script_args = parser.parse_args() - -def run_command(*vargs, **kwargs): - title = kwargs['title'] if 'title' in kwargs else None - from_dir = kwargs['from_dir'] if 'from_dir' in kwargs else None - quiet = kwargs['quiet'] if 'quiet' in kwargs else False - - quoted_args = map(lambda x: '"{x}"'.format(x=x) if ' ' in x else x, vargs) - cmd_line = ' '.join(quoted_args) - should_log = not script_args.verbose and title != None - redirect_args = { 'stderr': subprocess.STDOUT } - - nullfile = None - logfile = None - cwd = None - - try: - if should_log: - log_name = '-'.join(re.sub(r'\W', ' ', title).lower().split()) + '.log' - log_path = os.path.join(SCRIPT_ROOT_PATH, 'logs', 'run-perftests', log_name) - log_dir = os.path.dirname(log_path) - if not os.path.exists(log_dir): - os.makedirs(log_dir) - cmd_line += ' > "{log}"'.format(log = log_path) - logfile = open(log_path, 'w') - redirect_args['stdout'] = logfile - - elif quiet or not script_args.verbose: - nullfile = open(os.devnull, 'w') - redirect_args['stdout'] = nullfile - - prefix = '' - if not quiet and title != None: - print('# {msg}...'.format(msg = title)) - prefix = ' $ ' - - if from_dir != None: - cwd = os.getcwd() - if not quiet: print('{pref}cd "{dir}"'.format(pref = prefix, dir = from_dir)) - os.chdir(from_dir) - - if not quiet: print(prefix + cmd_line) - returncode = subprocess.call(vargs, **redirect_args) - - if returncode != 0: - logmsg = " See '{log}' for details.".format(log = log_path) if should_log else '' - raise FatalError("Command `{cmd}` returned with error code {e}.{log}".format(cmd = cmd_line, e = returncode, log = logmsg)) - - finally: - if logfile != None: logfile.close() - if nullfile != None: nullfile.close() - if cwd != None: os.chdir(cwd) - -def clone_repo(repo_url, local_path): - if os.path.exists(local_path): - # For now, we just assume that if the path exists, it's already the correct repo - print("# xunit-performance repo was detected at '{path}', skipping git clone".format(path = local_path)) - return - run_command( - 'git', 'clone', repo_url, local_path, - title = "Clone the xunit-performance repo", - ) - -def get_xunitperf_dotnet_path(xunitperf_src_path): - return os.path.join(xunitperf_src_path, 'tools', 'bin', 'dotnet') - -def get_xunitperf_runner_src_path(xunitperf_src_path): - return os.path.join(xunitperf_src_path, 'src', 'cli', 'Microsoft.DotNet.xunit.performance.runner.cli') - -def get_xunitperf_analyzer_path(xunitperf_src_path): - return os.path.join(xunitperf_src_path, 'src', 'xunit.performance.analysis', 'bin', 'Release', 'xunit.performance.analysis') - -def make_xunit_perf(xunitperf_src_path): - dotnet_path = get_xunitperf_dotnet_path(xunitperf_src_path) - dotnet_base_path = os.path.dirname(dotnet_path) - analyzer_base_path = os.path.dirname(get_xunitperf_analyzer_path(xunitperf_src_path)) - runner_src_path = get_xunitperf_runner_src_path(xunitperf_src_path) - - if script_args.rebuild or not os.path.exists(dotnet_base_path) or not os.path.exists(analyzer_base_path): - run_command( - 'CiBuild.cmd', '/release', - title = "Build xunit-performance", - from_dir = xunitperf_src_path, - ) - run_command( - dotnet_path, 'publish', '-c', 'Release', runner_src_path, - title = "Build Microsoft.DotNet.xunit.performance.runner.cli", - ) - else: - print("# xunit-performance at '{path}' was already built, skipping CiBuild. Use --rebuild to force rebuild.".format(path = xunitperf_src_path)) - -def run_perf_test(runid, cli_path, xunitperf_src_path): - cli_path = os.path.realpath(cli_path) - dotnet_path = get_xunitperf_dotnet_path(xunitperf_src_path) - runner_src_path = get_xunitperf_runner_src_path(xunitperf_src_path) - result_xml_path = os.path.join(SCRIPT_ROOT_PATH, '{}.xml'.format(runid)) - project_lock_path = os.path.join(SCRIPT_ROOT_PATH, 'project.lock.json') - - saved_path = os.environ.get('PATH') - print("# Prepending {dir} to PATH".format(dir = os.path.dirname(cli_path))) - os.environ['PATH'] = os.path.dirname(cli_path) + ';' + os.environ.get('PATH') - try: - if os.path.exists(project_lock_path): - print("# Deleting {file}".format(file = project_lock_path)) - os.remove(project_lock_path) - run_command( - cli_path, 'restore', '-f', 'https://dotnet.myget.org/f/dotnet-core', - title = "Dotnet restore using \"{cli}\"".format(cli = cli_path), - from_dir = SCRIPT_ROOT_PATH, - ) - run_command( - dotnet_path, 'run', '-p', runner_src_path, '-c', 'Release', '--', - '-runner', cli_path, '-runid', runid, - '-runnerargs', 'test {json} -c Release'.format(json = PERFTEST_JSON_PATH), - title = "Run {id}".format(id = runid), - from_dir = SCRIPT_ROOT_PATH, - ) - if not os.path.exists(result_xml_path): - raise FatalError("Running {id} seems to have failed: {xml} was not generated".format( - id = runid, xml = result_xml_path - )) - finally: - print("# Reverting PATH") - os.environ['PATH'] = saved_path - -def compare_results(base_id, test_id, out_html, xunitperf_src_path): - analyzer_path = get_xunitperf_analyzer_path(xunitperf_src_path) - - # Make sure there aren't any stale XMLs in the target dir - for xml in glob.glob(os.path.join(SCRIPT_ROOT_PATH, '*.xml')): - if not os.path.basename(xml) in [base_id + '.xml', test_id + '.xml']: - os.rename(xml, xml + '.bak') - - try: - run_command( - analyzer_path, SCRIPT_ROOT_PATH, '-compare', base_id, test_id, '-html', out_html, - title = "Generate comparison report", - from_dir = SCRIPT_ROOT_PATH, - ) - if os.path.exists(out_html): - print("# Comparison finished, please see \"{report}\" for details.".format(report = out_html)) - else: - raise FatalError("Failed to genererate comparison report: \"{report}\" not found.".format(report = out_html)) - - finally: - # Revert the renamed XMLs - for xml in glob.glob(os.path.join(SCRIPT_ROOT_PATH, '*.xml.bak')): - os.rename(xml, xml[0:-4]) - -def main(): - try: - process_arguments() - check_requirements() - - script_args.xunit_perf_path = os.path.realpath(script_args.xunit_perf_path) - - clone_repo(XUNITPERF_REPO_URL, script_args.xunit_perf_path) - make_xunit_perf(script_args.xunit_perf_path) - - base_runid = script_args.runid + '.base' - test_runid = script_args.runid + '.test' - out_html = os.path.join(SCRIPT_ROOT_PATH, script_args.runid + '.html') - - run_perf_test(test_runid, script_args.test_cli, script_args.xunit_perf_path) - if script_args.base_cli != None: - run_perf_test(base_runid, script_args.base_cli, script_args.xunit_perf_path) - compare_results(base_runid, test_runid, out_html, script_args.xunit_perf_path) - - return 0 - - except FatalError as error: - print("! ERROR: {msg}".format(msg = error.message)) - return 1 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/test/binding-redirects.Tests/binding-redirects.Tests.csproj b/test/binding-redirects.Tests/binding-redirects.Tests.csproj index fd3d71cc1..9b619c83f 100644 --- a/test/binding-redirects.Tests/binding-redirects.Tests.csproj +++ b/test/binding-redirects.Tests/binding-redirects.Tests.csproj @@ -1,57 +1,22 @@ - + - net46 + netcoreapp1.0 true binding-redirects.Tests - win7-x64;win7-x86 + $(PackageTargetFallback);dotnet5.4;portable-net451+win8 - - true - - - true - - - true - - - - - - true - - - 4.0.0 - - - - - - 15.0.0-preview-20161024-02 - - - 2.2.0-beta4-build1194 - - - 2.2.0-beta4-build3444 - - - 1.0.1 - - - 1.0.1-beta-000933 - + + + + + - - - $(DefineConstants);RELEASE - diff --git a/test/dotnet-add-package.Tests/GivenDotnetPackageAdd.cs b/test/dotnet-add-package.Tests/GivenDotnetPackageAdd.cs new file mode 100644 index 000000000..def951aec --- /dev/null +++ b/test/dotnet-add-package.Tests/GivenDotnetPackageAdd.cs @@ -0,0 +1,119 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using FluentAssertions; +using Microsoft.Build.Construction; +using Microsoft.DotNet.Cli.Sln.Internal; +using Microsoft.DotNet.Tools.Test.Utilities; +using System; +using System.IO; +using System.Linq; +using Xunit; + +namespace Microsoft.DotNet.Cli.Package.Add.Tests +{ + public class GivenDotnetPackageAdd : TestBase + { + + [Fact] + public void WhenValidPackageIsPassedBeforeVersionItGetsAdded() + { + var testAsset = "TestAppSimple"; + var projectDirectory = TestAssets + .Get(testAsset) + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var packageName = "Newtonsoft.Json"; + var packageVersion = "9.0.1"; + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"add package {packageName} --version {packageVersion}"); + cmd.Should().Pass(); + cmd.StdOut.Should().Contain($"PackageReference for package '{packageName}' version '{packageVersion}' " + + $"added to file '{projectDirectory + Path.DirectorySeparatorChar + testAsset}.csproj'."); + cmd.StdErr.Should().BeEmpty(); + } + + [Fact] + public void WhenValidPackageIsPassedAfterVersionItGetsAdded() + { + var testAsset = "TestAppSimple"; + var projectDirectory = TestAssets + .Get(testAsset) + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var packageName = "Newtonsoft.Json"; + var packageVersion = "9.0.1"; + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"add package --version {packageVersion} {packageName}"); + cmd.Should().Pass(); + cmd.StdOut.Should().Contain($"PackageReference for package '{packageName}' version '{packageVersion}' " + + $"added to file '{projectDirectory + Path.DirectorySeparatorChar + testAsset}.csproj'."); + cmd.StdErr.Should().BeEmpty(); + } + + [Fact] + public void WhenValidPackageIsPassedWithFrameworkItGetsAdded() + { + var testAsset = "TestAppSimple"; + var projectDirectory = TestAssets + .Get(testAsset) + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var packageName = "Newtonsoft.Json"; + var packageVersion = "9.0.1"; + var framework = "netcoreapp1.0"; + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"add package {packageName} --version {packageVersion} --framework {framework}"); + cmd.Should().Pass(); + cmd.StdOut.Should().Contain($"PackageReference for package '{packageName}' version '{packageVersion}' " + + $"added to file '{projectDirectory + Path.DirectorySeparatorChar + testAsset}.csproj'."); + cmd.StdErr.Should().BeEmpty(); + } + + [Fact] + public void WhenMultiplePackagesArePassedCommandFails() + { + var projectDirectory = TestAssets + .Get("TestAppSimple") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"add package package1 package2 package3"); + cmd.Should().Fail(); + cmd.StdErr.Should().Contain("Please specify one package reference to add."); + } + + [Fact] + public void WhenNoPackageisPassedCommandFails() + { + var projectDirectory = TestAssets + .Get("TestAppSimple") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"add package"); + cmd.Should().Fail(); + cmd.StdErr.Should().Contain("Please specify one package reference to add."); + } + } +} diff --git a/test/dotnet-add-package.Tests/MSBuild.exe b/test/dotnet-add-package.Tests/MSBuild.exe new file mode 100644 index 000000000..9bda258ef --- /dev/null +++ b/test/dotnet-add-package.Tests/MSBuild.exe @@ -0,0 +1 @@ +https://github.com/Microsoft/msbuild/issues/927 diff --git a/test/dotnet-add-package.Tests/MSBuild.exe.config b/test/dotnet-add-package.Tests/MSBuild.exe.config new file mode 100644 index 000000000..9bda258ef --- /dev/null +++ b/test/dotnet-add-package.Tests/MSBuild.exe.config @@ -0,0 +1 @@ +https://github.com/Microsoft/msbuild/issues/927 diff --git a/test/dotnet-add-package.Tests/dotnet-add-package.Tests.csproj b/test/dotnet-add-package.Tests/dotnet-add-package.Tests.csproj new file mode 100644 index 000000000..6a052db05 --- /dev/null +++ b/test/dotnet-add-package.Tests/dotnet-add-package.Tests.csproj @@ -0,0 +1,26 @@ + + + + + netcoreapp1.0 + true + dotnet-add-package.Tests + $(PackageTargetFallback);dotnet5.4;portable-net451+win8 + + + + + + + + + + + + + + + + + + diff --git a/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs b/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs index bab4f3358..a76e765bc 100644 --- a/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs +++ b/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs @@ -15,13 +15,13 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("TestAppWithLibrary")] public void WhenProjectMigrationSucceedsThenProjectJsonArtifactsGetMovedToBackup(string testProjectName) { - var testRoot = TestAssetsManager - .CreateTestInstance(testProjectName) - .Path; + var testRoot = TestAssets + .GetProjectJson(testProjectName) + .CreateInstance() + .WithSourceFiles() + .Root; - var testRootParent = new DirectoryInfo(testRoot).Parent.FullName; - - var backupRoot = Path.Combine(testRootParent, "backup"); + var backupRoot = testRoot.GetDirectory("backup"); var migratableArtifacts = GetProjectJsonArtifacts(testRoot); @@ -34,22 +34,22 @@ namespace Microsoft.DotNet.Migration.Tests backupArtifacts.Should().Equal(migratableArtifacts, "Because all of and only these artifacts should have been moved"); - new DirectoryInfo(testRoot).Should().NotHaveFiles(backupArtifacts.Keys); + testRoot.Should().NotHaveFiles(backupArtifacts.Keys); - new DirectoryInfo(backupRoot).Should().HaveTextFiles(backupArtifacts); + backupRoot.Should().HaveTextFiles(backupArtifacts); } [Theory] [InlineData("PJTestAppSimple")] public void WhenFolderMigrationSucceedsThenProjectJsonArtifactsGetMovedToBackup(string testProjectName) { - var testRoot = TestAssetsManager - .CreateTestInstance(testProjectName) - .Path; + var testRoot = TestAssets + .GetProjectJson(testProjectName) + .CreateInstance() + .WithSourceFiles() + .Root; - var testRootParent = new DirectoryInfo(testRoot).Parent.FullName; - - var backupRoot = Path.Combine(testRootParent, "backup", testProjectName); + var backupRoot = testRoot.GetDirectory("backup"); var migratableArtifacts = GetProjectJsonArtifacts(testRoot); @@ -62,20 +62,22 @@ namespace Microsoft.DotNet.Migration.Tests backupArtifacts.Should().Equal(migratableArtifacts, "Because all of and only these artifacts should have been moved"); - new DirectoryInfo(testRoot).Should().NotHaveFiles(backupArtifacts.Keys); + testRoot.Should().NotHaveFiles(backupArtifacts.Keys); - new DirectoryInfo(backupRoot).Should().HaveTextFiles(backupArtifacts); + backupRoot.Should().HaveTextFiles(backupArtifacts); } [Theory] [InlineData("TestAppWithLibraryAndMissingP2P")] public void WhenMigrationFailsThenProjectJsonArtifactsDoNotGetMovedToBackup(string testProjectName) { - var testRoot = new TestAssetsManager(Path.Combine(RepoRoot, "TestAssets", "NonRestoredTestProjects")) - .CreateTestInstance(testProjectName, identifier: testProjectName) - .Path; + var testRoot = TestAssets + .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, testProjectName) + .CreateInstance(identifier: testProjectName) + .WithSourceFiles() + .Root; - var backupRoot = Path.Combine(testRoot, "backup"); + var backupRoot = testRoot.GetDirectory("backup"); var migratableArtifacts = GetProjectJsonArtifacts(testRoot); @@ -84,19 +86,23 @@ namespace Microsoft.DotNet.Migration.Tests .Execute() .Should().Fail(); - new DirectoryInfo(backupRoot).Should().NotExist("Because migration failed and therefore no backup is needed."); + backupRoot.Should().NotExist("Because migration failed and therefore no backup is needed."); - new DirectoryInfo(testRoot).Should().HaveTextFiles(migratableArtifacts, "Because migration failed so nothing was moved to backup."); + testRoot.Should().HaveTextFiles(migratableArtifacts, "Because migration failed so nothing was moved to backup."); } [Theory] [InlineData("PJTestAppSimple")] public void WhenSkipbackupSpecifiedThenProjectJsonArtifactsDoNotGetMovedToBackup(string testProjectName) { - var testRoot = TestAssetsManager.CreateTestInstance(testProjectName, identifier: testProjectName).Path; - - var backupRoot = Path.Combine(testRoot, "backup"); - + var testRoot = TestAssets + .GetProjectJson(testProjectName) + .CreateInstance(identifier: testProjectName) + .WithSourceFiles() + .Root; + + var backupRoot = testRoot.GetDirectory("backup"); + var migratableArtifacts = GetProjectJsonArtifacts(testRoot); new MigrateCommand() @@ -104,12 +110,12 @@ namespace Microsoft.DotNet.Migration.Tests .Execute("--skip-backup") .Should().Pass(); - new DirectoryInfo(backupRoot).Should().NotExist("Because --skip-backup was specified."); + backupRoot.Should().NotExist("Because --skip-backup was specified."); - new DirectoryInfo(testRoot).Should().HaveTextFiles(migratableArtifacts, "Because --skip-backup was specified."); + testRoot.Should().HaveTextFiles(migratableArtifacts, "Because --skip-backup was specified."); } - private Dictionary GetProjectJsonArtifacts(string rootPath) + private Dictionary GetProjectJsonArtifacts(DirectoryInfo root) { var catalog = new Dictionary(); @@ -117,23 +123,19 @@ namespace Microsoft.DotNet.Migration.Tests foreach (var pattern in patterns) { - AddArtifactsToCatalog(catalog, rootPath, pattern); + AddArtifactsToCatalog(catalog, root, pattern); } return catalog; } - private void AddArtifactsToCatalog(Dictionary catalog, string basePath, string pattern) + private void AddArtifactsToCatalog(Dictionary catalog, DirectoryInfo root, string pattern) { - basePath = PathUtility.EnsureTrailingSlash(basePath); - - var baseDirectory = new DirectoryInfo(basePath); - - var files = baseDirectory.GetFiles(pattern, SearchOption.AllDirectories); + var files = root.GetFiles(pattern, SearchOption.AllDirectories); foreach (var file in files) { - var key = PathUtility.GetRelativePath(basePath, file.FullName); + var key = PathUtility.GetRelativePath(root, file); catalog.Add(key, File.ReadAllText(file.FullName)); } } diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateAppsUsingGlobalJson.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateAppsUsingGlobalJson.cs index dc6652124..3f7fea788 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateAppsUsingGlobalJson.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateAppsUsingGlobalJson.cs @@ -14,13 +14,17 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesWhenBeingPassedAFullPathToGlobalJson() { - var solutionDirectory = - TestAssetsManager.CreateTestInstance("AppWithPackageNamedAfterFolder").Path; - var globalJsonPath = Path.Combine(solutionDirectory, "global.json"); + var solutionDirectory = TestAssets + .GetProjectJson("AppWithPackageNamedAfterFolder") + .CreateInstance() + .WithSourceFiles() + .Root; + + var globalJsonPath = solutionDirectory.GetFile("global.json"); new TestCommand("dotnet") .WithForwardingToConsole() - .Execute($"migrate {globalJsonPath}") + .Execute($"migrate {globalJsonPath.FullName}") .Should() .Pass(); } @@ -28,17 +32,21 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void WhenUsingGlobalJsonItOnlyMigratesProjectsInTheGlobalJsonNode() { - var solutionDirectory = - TestAssetsManager.CreateTestInstance("AppWithPackageNamedAfterFolder").Path; - var globalJsonPath = Path.Combine(solutionDirectory, "global.json"); + var solutionDirectory = TestAssets + .GetProjectJson("AppWithPackageNamedAfterFolder") + .CreateInstance() + .WithSourceFiles() + .Root; + + var globalJsonPath = solutionDirectory.GetFile("global.json"); new TestCommand("dotnet") .WithForwardingToConsole() - .Execute($"migrate {globalJsonPath}") + .Execute($"migrate {globalJsonPath.FullName}") .Should() .Pass(); - new DirectoryInfo(solutionDirectory) + solutionDirectory .Should().HaveFiles(new [] { Path.Combine("src", "App", "App.csproj"), @@ -46,15 +54,20 @@ namespace Microsoft.DotNet.Migration.Tests Path.Combine("TestAssets", "TestAsset", "project.json") }); - new DirectoryInfo(solutionDirectory) + solutionDirectory .Should().NotHaveFile(Path.Combine("TestAssets", "TestAsset", "TestAsset.csproj")); } [Fact] public void ItMigratesWhenBeingPassedJustGlobalJson() { - var solutionDirectory = - TestAssetsManager.CreateTestInstance("AppWithPackageNamedAfterFolder").Path; + var solutionDirectory = TestAssets + .GetProjectJson("AppWithPackageNamedAfterFolder") + .CreateInstance() + .WithSourceFiles() + .Root; + + var globalJsonPath = solutionDirectory.GetFile("global.json"); new TestCommand("dotnet") .WithWorkingDirectory(solutionDirectory) diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs index b93690e94..f70ce7c08 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs @@ -102,8 +102,8 @@ EndGlobal string minVisualStudioVersion) { var projectDirectory = TestAssets - .Get("NonRestoredTestProjects", projectName) - .CreateInstance() + .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, projectName) + .CreateInstance(identifier: projectName) .WithSourceFiles() .Root; @@ -132,7 +132,7 @@ EndGlobal public void ItOnlyMigratesProjectsInTheSlnFile() { var projectDirectory = TestAssets - .Get("NonRestoredTestProjects", "PJAppWithSlnAndXprojRefs") + .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, "PJAppWithSlnAndXprojRefs") .CreateInstance() .WithSourceFiles() .Root; @@ -144,7 +144,7 @@ EndGlobal .Execute($"migrate \"{solutionRelPath}\"") .Should().Pass(); - new DirectoryInfo(projectDirectory.FullName) + projectDirectory .Should().HaveFiles(new [] { Path.Combine("TestApp", "TestApp.csproj"), @@ -153,7 +153,7 @@ EndGlobal Path.Combine("TestApp", "TestAssets", "TestAsset", "project.json") }); - new DirectoryInfo(projectDirectory.FullName) + projectDirectory .Should().NotHaveFile(Path.Combine("TestApp", "TestAssets", "TestAsset", "TestAsset.csproj")); } @@ -173,6 +173,59 @@ EndGlobal "PJAppWithSlnAndXprojRefThatRefsCsprojWhereSlnDoesNotRefCsproj"); } + [Fact] + public void WhenSolutionContainsACsprojFileItGetsMovedToBackup() + { + var projectDirectory = TestAssets + .GetProjectJson("NonRestoredTestProjects", "PJAppWithSlnAndOneAlreadyMigratedCsproj") + .CreateInstance() + .WithSourceFiles() + .Root; + + var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"migrate \"{solutionRelPath}\""); + + cmd.Should().Pass(); + + projectDirectory + .GetDirectory("TestLibrary") + .GetFile("TestLibrary.csproj") + .Should().Exist(); + + projectDirectory + .GetDirectory("TestLibrary") + .GetFile("TestLibrary.csproj.migration_in_place_backup") + .Should().NotExist(); + + projectDirectory + .GetDirectory("backup", "TestLibrary") + .GetFile("TestLibrary.csproj") + .Should().Exist(); + } + + [Fact] + public void WhenSolutionContainsACsprojFileItDoesNotTryToAddItAgain() + { + var projectDirectory = TestAssets + .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, "PJAppWithSlnAndOneAlreadyMigratedCsproj") + .CreateInstance() + .WithSourceFiles() + .Root; + + var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"migrate \"{solutionRelPath}\""); + + cmd.Should().Pass(); + cmd.StdOut.Should().NotContain("already contains project"); + cmd.StdErr.Should().BeEmpty(); + } + [Theory] [InlineData("NoSolutionItemsAfterMigration.sln", ExpectedSlnFileAfterRemovingAllSolutionItems)] [InlineData("ReadmeSolutionItemAfterMigration.sln", ExpectedSlnFileAfterRemovingAllSolutionItemsExceptReadme)] @@ -223,6 +276,7 @@ EndGlobal // .Should().Pass(); SlnFile slnFile = SlnFile.Read(Path.Combine(projectDirectory.FullName, solutionRelPath)); + var nonSolutionFolderProjects = slnFile.Projects .Where(p => p.TypeGuid != ProjectTypeGuids.SolutionFolderGuid); diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs index 1b35012cf..c569c6cc6 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs @@ -3,6 +3,7 @@ using Microsoft.Build.Construction; using Microsoft.DotNet.TestFramework; +using Microsoft.DotNet.Tools.Common; using Microsoft.DotNet.Tools.Test.Utilities; using System; using System.Collections.Generic; @@ -28,9 +29,12 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("TestAppWithEmbeddedResources")] public void ItMigratesApps(string projectName) { - var projectDirectory = TestAssetsManager.CreateTestInstance(projectName, identifier: projectName) - .WithLockFiles() - .Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .WithRestoreFiles() + .Root; CleanBinObj(projectDirectory); @@ -48,9 +52,10 @@ namespace Microsoft.DotNet.Migration.Tests VerifyAllMSBuildOutputsRunnable(projectDirectory); - var outputCsProj = Path.Combine(projectDirectory, projectName + ".csproj"); - var csproj = File.ReadAllText(outputCsProj); - csproj.EndsWith("\n").Should().Be(true); + var outputCsProj = projectDirectory.GetFile(projectName + ".csproj"); + + outputCsProj.ReadAllText() + .Should().EndWith("\n"); } [WindowsOnlyTheory] @@ -58,13 +63,16 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("TestAppWithMultipleFullFrameworksOnly", "net461")] public void ItMigratesAppsWithFullFramework(string projectName, string framework) { - var projectDirectory = TestAssetsManager.CreateTestInstance( - projectName, - identifier: projectName).WithLockFiles().Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .WithRestoreFiles() + .Root; CleanBinObj(projectDirectory); - MigrateProject(new [] { projectDirectory }); + MigrateProject(new [] { projectDirectory.FullName }); Restore(projectDirectory); @@ -74,7 +82,12 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesSignedApps() { - var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSigning").WithLockFiles().Path; + var projectDirectory = TestAssets + .GetProjectJson("TestAppWithSigning") + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; CleanBinObj(projectDirectory); @@ -98,10 +111,11 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesDotnetNewConsoleWithIdenticalOutputs() { - var testInstance = TestAssetsManager - .CreateTestInstance("ProjectJsonConsoleTemplate"); - - var projectDirectory = testInstance.Path; + var projectDirectory = TestAssets + .GetProjectJson("ProjectJsonConsoleTemplate") + .CreateInstance() + .WithSourceFiles() + .Root; var outputComparisonData = GetComparisonData(projectDirectory); @@ -121,14 +135,14 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesOldDotnetNewWebWithoutToolsWithOutputsContainingProjectJsonOutputs() { - var testInstance = TestAssetsManager - .CreateTestInstance("ProjectJsonWebTemplate") - .WithLockFiles(); + var projectDirectory = TestAssets + .GetProjectJson("ProjectJsonWebTemplate") + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; - var projectDirectory = testInstance.Path; - - var globalDirectory = Path.Combine(projectDirectory, ".."); - var projectJsonFile = Path.Combine(projectDirectory, "project.json"); + var globalDirectory = projectDirectory.Parent; WriteGlobalJson(globalDirectory); @@ -148,16 +162,17 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesAndPublishesWebApp() { - const string projectName = "WebAppWithMissingFileInPublishOptions"; - var testInstance = TestAssets.Get(projectName) - .CreateInstance() - .WithSourceFiles(); + var projectName = "WebAppWithMissingFileInPublishOptions"; - var projectDirectory = testInstance.Root.FullName; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance() + .WithSourceFiles() + .Root; - File.Copy("NuGet.tempaspnetpatch.config", Path.Combine(projectDirectory, "NuGet.Config")); + File.Copy("NuGet.tempaspnetpatch.config", projectDirectory.GetFile("NuGet.Config").FullName); - MigrateProject(new [] { projectDirectory }); + MigrateProject(new [] { projectDirectory.FullName }); Restore(projectDirectory); PublishMSBuild(projectDirectory, projectName); @@ -166,13 +181,20 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesAPackageReferenceAsSuchEvenIfAFolderWithTheSameNameExistsInTheRepo() { - var solutionDirectory = - TestAssetsManager.CreateTestInstance("AppWithPackageNamedAfterFolder").Path; - var appProject = Path.Combine(solutionDirectory, "src", "App", "App.csproj"); + var solutionDirectory = TestAssets + .GetProjectJson("AppWithPackageNamedAfterFolder") + .CreateInstance() + .WithSourceFiles() + .Root; - MigrateProject(solutionDirectory); + var appProject = solutionDirectory + .GetDirectory("src", "App") + .GetFile("App.csproj"); + + MigrateProject(solutionDirectory.FullName); + + var projectRootElement = ProjectRootElement.Open(appProject.FullName); - var projectRootElement = ProjectRootElement.Open(appProject); projectRootElement.Items.Where( i => i.Include == "EntityFramework" && i.ItemType == "PackageReference") .Should().HaveCount(2); @@ -183,38 +205,47 @@ namespace Microsoft.DotNet.Migration.Tests const string dependentProject = "ProjectA"; const string dependencyProject = "ProjectB"; - var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path; + var projectDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance() + .WithSourceFiles() + .Root; - MigrateProject(Path.Combine(projectDirectory, dependencyProject)); + MigrateProject(projectDirectory.GetDirectory(dependencyProject).FullName); - MigrateProject("--skip-project-references", Path.Combine(projectDirectory, dependentProject)); + MigrateProject("--skip-project-references", projectDirectory.GetDirectory(dependentProject).FullName); } [Fact] public void ItAddsMicrosoftNetWebSdkToTheSdkAttributeOfAWebApp() { - var testInstance = TestAssetsManager - .CreateTestInstance("ProjectJsonWebTemplate") - .WithLockFiles(); + var projectDirectory = TestAssets + .Get("ProjectJsonWebTemplate") + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; - var projectDirectory = testInstance.Path; - - var globalDirectory = Path.Combine(projectDirectory, ".."); - var projectJsonFile = Path.Combine(projectDirectory, "project.json"); + var globalDirectory = projectDirectory.Parent; + var projectJsonFile = projectDirectory.GetFile("project.json"); - MigrateProject(new [] { projectDirectory }); + MigrateProject(new [] { projectDirectory.FullName }); - var csProj = Path.Combine(projectDirectory, $"{new DirectoryInfo(projectDirectory).Name}.csproj"); + var csProj = projectDirectory.GetFile($"{projectDirectory.Name}.csproj"); - File.ReadAllText(csProj).Should().Contain(@"Sdk=""Microsoft.NET.Sdk.Web"""); + csProj.ReadAllText().Should().Contain(@"Sdk=""Microsoft.NET.Sdk.Web"""); } [Theory] [InlineData("TestLibraryWithTwoFrameworks")] public void ItMigratesProjectsWithMultipleTFMs(string projectName) { - var projectDirectory = - TestAssetsManager.CreateTestInstance(projectName, identifier: projectName).WithLockFiles().Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .WithRestoreFiles() + .Root; var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName); @@ -233,8 +264,13 @@ namespace Microsoft.DotNet.Migration.Tests public void ItMigratesLibraryWithMultipleTFMsAndFullFramework() { var projectName = "PJLibWithMultipleFrameworks"; - var projectDirectory = - TestAssetsManager.CreateTestInstance(projectName, identifier: projectName).WithLockFiles().Path; + + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .WithRestoreFiles() + .Root; var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName); @@ -255,13 +291,20 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("PJTestLibraryWithConfiguration")] public void ItMigratesALibrary(string projectName) { - var projectDirectory = - TestAssetsManager.CreateTestInstance(projectName, identifier: projectName).WithLockFiles().Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .WithRestoreFiles() + .Root; - var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectName)); + var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild( + projectDirectory, + Path.GetFileNameWithoutExtension(projectName)); - var outputsIdentical = - outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs); + var outputsIdentical = outputComparisonData + .ProjectJsonBuildOutputs + .SetEquals(outputComparisonData.MSBuildBuildOutputs); if (!outputsIdentical) { @@ -279,12 +322,13 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("ProjectE", "ProjectE")] public void ItMigratesRootProjectAndReferences(string projectName, string expectedProjects) { - var projectDirectory = - TestAssetsManager.CreateTestInstance( - "TestAppDependencyGraph", - identifier: $"{projectName}.RefsTest").Path; + var projectDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance(identifier: $"{projectName}.RefsTest") + .WithSourceFiles() + .Root; - MigrateProject(new [] { Path.Combine(projectDirectory, projectName) }); + MigrateProject(new [] { projectDirectory.GetDirectory(projectName).FullName }); string[] migratedProjects = expectedProjects.Split(new char[] { ',' }); @@ -299,10 +343,13 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("ProjectE")] public void ItMigratesRootProjectAndSkipsReferences(string projectName) { - var projectDirectory = - TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", identifier: $"{projectName}.SkipRefsTest").Path; - - MigrateProject(new [] { Path.Combine(projectDirectory, projectName), "--skip-project-references" }); + var projectDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance($"{projectName}.SkipRefsTest") + .WithSourceFiles() + .Root; + + MigrateProject(new [] { projectDirectory.GetDirectory(projectName).FullName, "--skip-project-references" }); VerifyMigration(Enumerable.Repeat(projectName, 1), projectDirectory); } @@ -312,15 +359,19 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData(false)] public void ItMigratesAllProjectsInGivenDirectory(bool skipRefs) { - var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"MigrateDirectory.SkipRefs.{skipRefs}").Path; + var projectDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance(callingMethod: $"MigrateDirectory.SkipRefs.{skipRefs}") + .WithSourceFiles() + .Root; if (skipRefs) { - MigrateProject(new [] { projectDirectory, "--skip-project-references" }); + MigrateProject(new [] { projectDirectory.FullName, "--skip-project-references" }); } else { - MigrateProject(new [] { projectDirectory }); + MigrateProject(new [] { projectDirectory.FullName }); } string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE", "ProjectF", "ProjectG", "ProjectH", "ProjectI", "ProjectJ" }; @@ -331,11 +382,17 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesGivenProjectJson() { - var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path; + var projectDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance() + .WithSourceFiles() + .Root; - var project = Path.Combine(projectDirectory, "ProjectA", "project.json"); + var project = projectDirectory + .GetDirectory("ProjectA") + .GetFile("project.json"); - MigrateProject(new [] { project }); + MigrateProject(new [] { project.FullName }); string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE" }; @@ -346,17 +403,22 @@ namespace Microsoft.DotNet.Migration.Tests // regression test for https://github.com/dotnet/cli/issues/4269 public void ItMigratesAndBuildsP2PReferences() { - var assetsDir = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").WithLockFiles().Path; + var assetsDir = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; - var projectDirectory = Path.Combine(assetsDir, "ProjectF"); + var projectDirectory = assetsDir.GetDirectory("ProjectF"); - var restoreDirectories = new string[] + var restoreDirectories = new DirectoryInfo[] { projectDirectory, - Path.Combine(assetsDir, "ProjectG") + assetsDir.GetDirectory("ProjectG") }; - var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, "ProjectF", new [] { projectDirectory }, restoreDirectories); + var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, "ProjectF", new [] { projectDirectory.FullName }, restoreDirectories); var outputsIdentical = outputComparisonData.ProjectJsonBuildOutputs .SetEquals(outputComparisonData.MSBuildBuildOutputs); @@ -372,27 +434,33 @@ namespace Microsoft.DotNet.Migration.Tests } [Theory] - [InlineData("src", "ProjectH")] - [InlineData("src with spaces", "ProjectJ")] - public void ItMigratesAndBuildsProjectsInGlobalJson(string path, string projectName) + [InlineData("src", "H")] + [InlineData("src with spaces", "J")] + public void ItMigratesAndBuildsProjectsInGlobalJson(string path, string projectNameSuffix) { - var assetsDir = TestAssetsManager.CreateTestInstance(Path.Combine("TestAppDependencyGraph", "ProjectsWithGlobalJson"), - callingMethod: $"ProjectsWithGlobalJson.{projectName}") - .WithLockFiles().Path; - var globalJson = Path.Combine(assetsDir, "global.json"); + var assetsDir = TestAssets + .GetProjectJson("ProjectsWithGlobalJson") + .CreateInstance(identifier: projectNameSuffix) + .WithSourceFiles() + .WithRestoreFiles() + .Root; - var restoreDirectories = new string[] + var projectName = $"Project{projectNameSuffix}"; + + var globalJson = assetsDir.GetFile("global.json"); + + var restoreDirectories = new DirectoryInfo[] { - Path.Combine(assetsDir, "src", "ProjectH"), - Path.Combine(assetsDir, "src", "ProjectI"), - Path.Combine(assetsDir, "src with spaces", "ProjectJ") + assetsDir.GetDirectory("src", "ProjectH"), + assetsDir.GetDirectory("src", "ProjectI"), + assetsDir.GetDirectory("src with spaces", "ProjectJ") }; - var projectDirectory = Path.Combine(assetsDir, path, projectName); + var projectDirectory = assetsDir.GetDirectory(path, projectName); var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName, - new [] { globalJson }, + new [] { globalJson.FullName }, restoreDirectories); var outputsIdentical = outputComparisonData.ProjectJsonBuildOutputs @@ -413,7 +481,7 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData(false)] public void MigrationOutputsErrorWhenNoProjectsFound(bool useGlobalJson) { - var projectDirectory = TestAssetsManager.CreateTestDirectory("Migration_outputs_error_when_no_projects_found"); + var projectDirectory = TestAssets.CreateTestDirectory("Migration_outputs_error_when_no_projects_found"); string argstr = string.Empty; @@ -421,31 +489,28 @@ namespace Microsoft.DotNet.Migration.Tests if (useGlobalJson) { - var globalJsonPath = Path.Combine(projectDirectory.Path, "global.json"); + var globalJson = projectDirectory.GetFile("global.json"); - using (FileStream fs = File.Create(globalJsonPath)) + using (StreamWriter sw = globalJson.CreateText()) { - using (StreamWriter sw = new StreamWriter(fs)) - { - sw.WriteLine("{"); - sw.WriteLine("\"projects\": [ \".\" ]"); - sw.WriteLine("}"); - } + sw.WriteLine("{"); + sw.WriteLine("\"projects\": [ \".\" ]"); + sw.WriteLine("}"); } - argstr = globalJsonPath; + argstr = globalJson.FullName; errorMessage = "Unable to find any projects in global.json"; } else { - argstr = projectDirectory.Path; + argstr = projectDirectory.FullName; - errorMessage = $"No project.json file found in '{projectDirectory.Path}'"; + errorMessage = $"No project.json file found in '{projectDirectory.FullName}'"; } var result = new TestCommand("dotnet") - .WithWorkingDirectory(projectDirectory.Path) + .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput($"migrate {argstr}"); // Expecting an error exit code. @@ -453,18 +518,21 @@ namespace Microsoft.DotNet.Migration.Tests // Verify the error messages. Note that debug builds also show the call stack, so we search // for the error strings that should be present (rather than an exact match). - result.StdErr.Should().Contain(errorMessage); - result.StdErr.Should().Contain("Migration failed."); + result.StdErr + .Should().Contain(errorMessage) + .And.Contain("Migration failed."); } [Fact] public void ItMigratesAndPublishesProjectsWithRuntimes() { var projectName = "PJTestAppSimple"; - var projectDirectory = TestAssetsManager - .CreateTestInstance(projectName) - .WithLockFiles() - .Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; CleanBinObj(projectDirectory); BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName); @@ -477,11 +545,16 @@ namespace Microsoft.DotNet.Migration.Tests public void ItAutoAddDesktopReferencesDuringMigrate(string testGroup, string projectName, bool isDesktopApp) { var runtime = DotnetLegacyRuntimeIdentifiers.InferLegacyRestoreRuntimeIdentifier(); - var testAssetManager = GetTestGroupTestAssetsManager(testGroup); - var projectDirectory = testAssetManager.CreateTestInstance(projectName).WithLockFiles().Path; - + + var projectDirectory = TestAssets + .GetProjectJson(testGroup, projectName) + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; + CleanBinObj(projectDirectory); - MigrateProject(new string[] { projectDirectory }); + MigrateProject(new string[] { projectDirectory.FullName }); Restore(projectDirectory, runtime: runtime); BuildMSBuild(projectDirectory, projectName, runtime:runtime); VerifyAutoInjectedDesktopReferences(projectDirectory, projectName, isDesktopApp); @@ -492,12 +565,19 @@ namespace Microsoft.DotNet.Migration.Tests public void ItBuildsAMigratedAppWithAnIndirectDependency() { const string projectName = "ProjectA"; - var solutionDirectory = - TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path; - var projectDirectory = Path.Combine(solutionDirectory, projectName); - MigrateProject(new string[] { projectDirectory }); + var solutionDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance() + .WithSourceFiles() + .Root; + + var projectDirectory = solutionDirectory.GetDirectory(projectName); + + MigrateProject(new string[] { projectDirectory.FullName }); + Restore(projectDirectory); + BuildMSBuild(projectDirectory, projectName); VerifyAllMSBuildOutputsRunnable(projectDirectory); @@ -506,35 +586,42 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesProjectWithOutputName() { - string projectName = "AppWithOutputAssemblyName"; - string expectedOutputName = "MyApp"; + var projectName = "AppWithOutputAssemblyName"; + var expectedOutputName = "MyApp"; - var projectDirectory = TestAssetsManager.CreateTestInstance(projectName, callingMethod: $"It_migrates_{projectName}") - .WithLockFiles() - .Path; - - string expectedCsprojPath = Path.Combine(projectDirectory, $"{projectName}.csproj"); - if (File.Exists(expectedCsprojPath)) + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; + + var expectedCsprojPath = projectDirectory.GetFile($"{projectName}.csproj"); + + if (expectedCsprojPath.Exists) { - File.Delete(expectedCsprojPath); + expectedCsprojPath.Delete(); } CleanBinObj(projectDirectory); - MigrateProject(projectDirectory); - File.Exists(expectedCsprojPath).Should().BeTrue(); + MigrateProject(projectDirectory.FullName); + + expectedCsprojPath.Refresh(); + + expectedCsprojPath.Should().Exist(); + Restore(projectDirectory, projectName); BuildMSBuild(projectDirectory, projectName); - Directory.EnumerateFiles( - Path.Combine(projectDirectory, "bin"), - $"{expectedOutputName}.pdb", - SearchOption.AllDirectories) + projectDirectory + .GetDirectory("bin") + .EnumerateFiles($"{expectedOutputName}.pdb", SearchOption.AllDirectories) .Count().Should().Be(1); PackMSBuild(projectDirectory, projectName); - Directory.EnumerateFiles( - Path.Combine(projectDirectory, "bin"), - $"{projectName}.1.0.0.nupkg", - SearchOption.AllDirectories) + + projectDirectory + .GetDirectory("bin") + .EnumerateFiles($"{projectName}.1.0.0.nupkg", SearchOption.AllDirectories) .Count().Should().Be(1); } @@ -543,24 +630,31 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("LibraryWithNetStandardLibRef")] public void ItMigratesAndBuildsLibrary(string projectName) { - var projectDirectory = TestAssetsManager.CreateTestInstance( - projectName, - identifier: $"{projectName}").Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .Root; - MigrateProject(projectDirectory); + MigrateProject(projectDirectory.FullName); Restore(projectDirectory, projectName); BuildMSBuild(projectDirectory, projectName); } - private void VerifyAutoInjectedDesktopReferences(string projectDirectory, string projectName, bool shouldBePresent) + private void VerifyAutoInjectedDesktopReferences(DirectoryInfo projectDirectory, string projectName, bool shouldBePresent) { if (projectName != null) { projectName = projectName + ".csproj"; } - var root = ProjectRootElement.Open(Path.Combine(projectDirectory, projectName)); - var autoInjectedReferences = root.Items.Where(i => i.ItemType == "Reference" && (i.Include == "System" || i.Include == "Microsoft.CSharp")); + var root = ProjectRootElement.Open(projectDirectory.GetFile(projectName).FullName); + + var autoInjectedReferences = root + .Items + .Where(i => i.ItemType == "Reference" + && (i.Include == "System" || i.Include == "Microsoft.CSharp")); + if (shouldBePresent) { autoInjectedReferences.Should().HaveCount(2); @@ -571,51 +665,56 @@ namespace Microsoft.DotNet.Migration.Tests } } - private void VerifyMigration(IEnumerable expectedProjects, string rootDir) + private void VerifyMigration(IEnumerable expectedProjects, DirectoryInfo rootDir) { - var migratedProjects = Directory.EnumerateFiles(rootDir, "*.csproj", SearchOption.AllDirectories) - .Where(s => Directory.EnumerateFiles(Path.GetDirectoryName(s), "*.csproj").Count() == 1) - .Where(s => Path.GetFileName(Path.GetDirectoryName(s)).Contains("Project")) - .Select(s => Path.GetFileName(Path.GetDirectoryName(s))); + var backupDir = rootDir.GetDirectory("backup"); + + var migratedProjects = rootDir.EnumerateFiles("*.csproj", SearchOption.AllDirectories) + .Where(s => !PathUtility.IsChildOfDirectory(backupDir.FullName, s.FullName)) + .Where(s => Directory.EnumerateFiles(Path.GetDirectoryName(s.FullName), "*.csproj").Count() == 1) + .Where(s => Path.GetFileName(Path.GetDirectoryName(s.FullName)).Contains("Project")) + .Select(s => Path.GetFileName(Path.GetDirectoryName(s.FullName))); migratedProjects.Should().BeEquivalentTo(expectedProjects); } - private MigratedBuildComparisonData GetComparisonData(string projectDirectory) + private MigratedBuildComparisonData GetComparisonData(DirectoryInfo projectDirectory) { - File.Copy("NuGet.tempaspnetpatch.config", Path.Combine(projectDirectory, "NuGet.Config")); + File.Copy("NuGet.tempaspnetpatch.config", projectDirectory.GetFile("NuGet.Config").FullName); RestoreProjectJson(projectDirectory); var outputComparisonData = - BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectDirectory)); + BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectDirectory.FullName)); return outputComparisonData; } - private void VerifyAllMSBuildOutputsRunnable(string projectDirectory) + private void VerifyAllMSBuildOutputsRunnable(DirectoryInfo projectDirectory) { - var dllFileName = Path.GetFileName(projectDirectory) + ".dll"; + var dllFileName = Path.GetFileName(projectDirectory.FullName) + ".dll"; - var runnableDlls = Directory.EnumerateFiles(Path.Combine(projectDirectory, "bin"), dllFileName, - SearchOption.AllDirectories); + var runnableDlls = projectDirectory + .GetDirectory("bin") + .GetFiles(dllFileName, SearchOption.AllDirectories); foreach (var dll in runnableDlls) { - new TestCommand("dotnet").ExecuteWithCapturedOutput($"\"{dll}\"").Should().Pass(); + new TestCommand("dotnet").ExecuteWithCapturedOutput($"\"{dll.FullName}\"").Should().Pass(); } } - private void VerifyAllMSBuildOutputsAreSigned(string projectDirectory) + private void VerifyAllMSBuildOutputsAreSigned(DirectoryInfo projectDirectory) { - var dllFileName = Path.GetFileName(projectDirectory) + ".dll"; + var dllFileName = Path.GetFileName(projectDirectory.FullName) + ".dll"; - var runnableDlls = Directory.EnumerateFiles(Path.Combine(projectDirectory, "bin"), dllFileName, - SearchOption.AllDirectories); + var runnableDlls = projectDirectory + .GetDirectory("bin") + .EnumerateFiles(dllFileName, SearchOption.AllDirectories); foreach (var dll in runnableDlls) { - var assemblyName = AssemblyLoadContext.GetAssemblyName(dll); + var assemblyName = AssemblyLoadContext.GetAssemblyName(dll.FullName); var token = assemblyName.GetPublicKeyToken(); @@ -623,30 +722,30 @@ namespace Microsoft.DotNet.Migration.Tests } } - private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, + private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(DirectoryInfo projectDirectory, string projectName) { return BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName, - new [] { projectDirectory }, + new [] { projectDirectory.FullName }, new [] { projectDirectory }); } - private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, + private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(DirectoryInfo projectDirectory, string projectName, string[] migrateArgs, - string[] restoreDirectories) + DirectoryInfo[] restoreDirectories) { BuildProjectJson(projectDirectory); - var projectJsonBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory)); + var projectJsonBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory.FullName)); CleanBinObj(projectDirectory); // Remove lock file for migration foreach(var dir in restoreDirectories) { - File.Delete(Path.Combine(dir, "project.lock.json")); + dir.GetFile("project.lock.json").Delete(); } MigrateProject(migrateArgs); @@ -660,7 +759,7 @@ namespace Microsoft.DotNet.Migration.Tests BuildMSBuild(projectDirectory, projectName); - var msbuildBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory)); + var msbuildBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory.FullName)); return new MigratedBuildComparisonData(projectJsonBuildOutputs, msbuildBuildOutputs); } @@ -673,41 +772,24 @@ namespace Microsoft.DotNet.Migration.Tests .Select(p => Path.GetFullPath(p).Substring(fullBinPath.Length)); } - private static void DeleteDirectory(string dir) + private void CleanBinObj(DirectoryInfo projectDirectory) { - foreach (string directory in Directory.EnumerateDirectories(dir)) - { - DeleteDirectory(directory); - } - - try - { - Directory.Delete(dir, true); - } - catch - { - // retry, if still doesn't delete then throw - Directory.Delete(dir, true); - } - } - - private void CleanBinObj(string projectDirectory) - { - var dirs = new string[] { Path.Combine(projectDirectory, "bin"), Path.Combine(projectDirectory, "obj") }; + var dirs = new DirectoryInfo[] { projectDirectory.GetDirectory("bin"), projectDirectory.GetDirectory("obj") }; foreach (var dir in dirs) { - if(Directory.Exists(dir)) + if(dir.Exists) { - DeleteDirectory(dir); + dir.Delete(true); } } } - private void BuildProjectJson(string projectDirectory) + private void BuildProjectJson(DirectoryInfo projectDirectory) { Console.WriteLine(projectDirectory); - var projectFile = "\"" + Path.Combine(projectDirectory, "project.json") + "\""; + + var projectFile = $"\"{projectDirectory.GetFile("project.json").FullName}\""; var result = new BuildPJCommand() .WithCapturedOutput() @@ -726,15 +808,15 @@ namespace Microsoft.DotNet.Migration.Tests .Pass(); } - private void RestoreProjectJson(string projectDirectory) + private void RestoreProjectJson(DirectoryInfo projectDirectory) { - var projectFile = "\"" + Path.Combine(projectDirectory, "project.json") + "\""; + var projectFile = $"\"{projectDirectory.GetFile("project.json").FullName}\""; new RestoreProjectJsonCommand() .Execute(projectFile) .Should().Pass(); } - private void Restore(string projectDirectory, string projectName=null, string runtime=null) + private void Restore(DirectoryInfo projectDirectory, string projectName=null, string runtime=null) { var command = new RestoreCommand() .WithWorkingDirectory(projectDirectory) @@ -757,7 +839,7 @@ namespace Microsoft.DotNet.Migration.Tests } private string BuildMSBuild( - string projectDirectory, + DirectoryInfo projectDirectory, string projectName, string configuration="Debug", string runtime=null, @@ -783,7 +865,7 @@ namespace Microsoft.DotNet.Migration.Tests } private string PublishMSBuild( - string projectDirectory, + DirectoryInfo projectDirectory, string projectName, string runtime = null, string configuration = "Debug") @@ -805,7 +887,7 @@ namespace Microsoft.DotNet.Migration.Tests return result.StdOut; } - private string PackMSBuild(string projectDirectory, string projectName) + private string PackMSBuild(DirectoryInfo projectDirectory, string projectName) { if (projectName != null && !Path.HasExtension(projectName)) { @@ -821,13 +903,13 @@ namespace Microsoft.DotNet.Migration.Tests return result.StdOut; } - private void DeleteXproj(string projectDirectory) + private void DeleteXproj(DirectoryInfo projectDirectory) { - var xprojFiles = Directory.EnumerateFiles(projectDirectory, "*.xproj"); + var xprojFiles = projectDirectory.EnumerateFiles("*.xproj"); foreach (var xprojFile in xprojFiles) { - File.Delete(xprojFile); + xprojFile.Delete(); } } @@ -864,10 +946,11 @@ namespace Microsoft.DotNet.Migration.Tests } } - private void WriteGlobalJson(string globalDirectory) + private void WriteGlobalJson(DirectoryInfo globalDirectory) { - var file = Path.Combine(globalDirectory, "global.json"); - File.WriteAllText(file, @" + var file = globalDirectory.GetFile("global.json"); + + File.WriteAllText(file.FullName, @" { ""projects"": [ ] }"); diff --git a/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs b/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs index 4a0d87381..c1ca138d5 100644 --- a/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs +++ b/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs @@ -35,8 +35,6 @@ VisualStudioVersion = 15.0.26006.2 MinimumVisualStudioVersion = 10.0.40219.1 Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""App"", ""App\App.csproj"", ""{7072A694-548F-4CAE-A58F-12D257D5F486}"" EndProject -Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""Lib"", ""Lib"", ""__LIB_FOLDER_GUID__"" -EndProject Project(""{13B669BE-BB05-4DDF-9536-439F39A36129}"") = ""Lib"", ""Lib\Lib.csproj"", ""__LIB_PROJECT_GUID__"" EndProject Global @@ -77,9 +75,6 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(NestedProjects) = preSolution - __LIB_PROJECT_GUID__ = __LIB_FOLDER_GUID__ - EndGlobalSection EndGlobal "; @@ -88,8 +83,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26006.2 MinimumVisualStudioVersion = 10.0.40219.1 -Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""Lib"", ""Lib"", ""__LIB_FOLDER_GUID__"" -EndProject Project(""{13B669BE-BB05-4DDF-9536-439F39A36129}"") = ""Lib"", ""Lib\Lib.csproj"", ""__LIB_PROJECT_GUID__"" EndProject Global @@ -115,9 +108,6 @@ Global __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|x86 __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|x86 EndGlobalSection - GlobalSection(NestedProjects) = preSolution - __LIB_PROJECT_GUID__ = __LIB_FOLDER_GUID__ - EndGlobalSection EndGlobal "; @@ -130,8 +120,6 @@ Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""App"", ""App.csproj"", " EndProject Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""src"", ""src"", ""__SRC_FOLDER_GUID__"" EndProject -Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""Lib"", ""Lib"", ""__LIB_FOLDER_GUID__"" -EndProject Project(""{13B669BE-BB05-4DDF-9536-439F39A36129}"") = ""Lib"", ""src\Lib\Lib.csproj"", ""__LIB_PROJECT_GUID__"" EndProject Global @@ -173,8 +161,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - __LIB_FOLDER_GUID__ = __SRC_FOLDER_GUID__ - __LIB_PROJECT_GUID__ = __LIB_FOLDER_GUID__ + __LIB_PROJECT_GUID__ = __SRC_FOLDER_GUID__ EndGlobalSection EndGlobal "; @@ -345,6 +332,70 @@ EndGlobal .Should().BeVisuallyEquivalentTo(expectedSlnContents); } + [Fact] + public void WhenProjectDirectoryIsAddedSolutionFoldersAreNotCreated() + { + var projectDirectory = TestAssets + .Get("TestAppWithSlnAndCsprojFiles") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var projectToAdd = Path.Combine("Lib", "Lib.csproj"); + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"sln App.sln add {projectToAdd}"); + cmd.Should().Pass(); + + var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); + var solutionFolderProjects = slnFile.Projects.Where( + p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid); + solutionFolderProjects.Count().Should().Be(0); + slnFile.Sections.GetSection("NestedProjects").Should().BeNull(); + } + + [Theory] + [InlineData(".")] + [InlineData("")] + public void WhenSolutionFolderExistsItDoesNotGetAdded(string firstComponent) + { + var projectDirectory = TestAssets + .Get("TestAppWithSlnAndSolutionFolders") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var projectToAdd = Path.Combine($"{firstComponent}", "src", "src", "Lib", "Lib.csproj"); + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"sln App.sln add {projectToAdd}"); + cmd.Should().Pass(); + + var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); + slnFile.Projects.Count().Should().Be(4); + + var solutionFolderProjects = slnFile.Projects.Where( + p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid); + solutionFolderProjects.Count().Should().Be(2); + + var solutionFolders = slnFile.Sections.GetSection("NestedProjects").Properties; + solutionFolders.Count.Should().Be(3); + + solutionFolders["{DDF3765C-59FB-4AA6-BE83-779ED13AA64A}"] + .Should().Be("{72BFCA87-B033-4721-8712-4D12166B4A39}"); + + var newlyAddedSrcFolder = solutionFolderProjects.Where( + p => p.Id != "{72BFCA87-B033-4721-8712-4D12166B4A39}").Single(); + solutionFolders[newlyAddedSrcFolder.Id] + .Should().Be("{72BFCA87-B033-4721-8712-4D12166B4A39}"); + + var libProject = slnFile.Projects.Where(p => p.Name == "Lib").Single(); + solutionFolders[libProject.Id] + .Should().Be(newlyAddedSrcFolder.Id); + } + [Theory] [InlineData("TestAppWithSlnAndCsprojFiles", ExpectedSlnFileAfterAddingLibProj, "")] [InlineData("TestAppWithSlnAndCsprojProjectGuidFiles", ExpectedSlnFileAfterAddingLibProj, "{84A45D44-B677-492D-A6DA-B3A71135AB8E}")] @@ -574,12 +625,6 @@ EndGlobal } var slnContents = slnTemplate.Replace("__LIB_PROJECT_GUID__", expectedLibProjectGuid); - var matchingLibFolder = slnFile.Projects - .Where((p) => p.FilePath == "Lib") - .ToList(); - matchingLibFolder.Count.Should().Be(1); - slnContents = slnContents.Replace("__LIB_FOLDER_GUID__", matchingLibFolder[0].Id); - var matchingSrcFolder = slnFile.Projects .Where((p) => p.FilePath == "src") .ToList(); diff --git a/test/dotnet.Tests/¬/.dotnet/optimizationdata/1.0.0-rc4-004536/osx.10.11-x64/dotnet b/test/dotnet.Tests/¬/.dotnet/optimizationdata/1.0.0-rc4-004536/osx.10.11-x64/dotnet new file mode 100644 index 000000000..30393cb6d Binary files /dev/null and b/test/dotnet.Tests/¬/.dotnet/optimizationdata/1.0.0-rc4-004536/osx.10.11-x64/dotnet differ