From 68afda8e4d13f22724a8e7ee19c60d5997f8b8a5 Mon Sep 17 00:00:00 2001 From: Justin Goshi Date: Wed, 26 Oct 2016 22:23:40 +0000 Subject: [PATCH] Handle "runtimes" section (#4503) * Migrate "runtimes" section as a RuntimeIdentifiers property in the resulting csproj file. Also do not call restore3 from publish3 anymore. * Fix up the publish3 tests to call restore3 first and the csproj files to have RuntimeIdentifiers --- .../MSBuildTestApp/MSBuildTestApp.csproj | 1 + .../DefaultMigrationRuleSet.cs | 1 + .../Rules/MigrateRuntimesRule.cs | 35 ++++++++ src/Microsoft.DotNet.ProjectModel/Project.cs | 2 + .../ProjectReader.cs | 18 +++++ .../dotnet-publish3/Publish3Command.cs | 20 ----- .../Rules/GivenThatIWantToMigrateRuntimes.cs | 79 +++++++++++++++++++ .../Commands/Publish3Command.cs | 4 +- .../GivenThatIWantToMigrateTestApps.cs | 34 +++++++- .../GivenDotnetPublish3PublishesProjects.cs | 26 +++--- 10 files changed, 183 insertions(+), 37 deletions(-) create mode 100644 src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateRuntimesRule.cs create mode 100644 test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateRuntimes.cs diff --git a/TestAssets/TestProjects/MSBuildTestApp/MSBuildTestApp.csproj b/TestAssets/TestProjects/MSBuildTestApp/MSBuildTestApp.csproj index 00f51ebb3..ec55505c2 100644 --- a/TestAssets/TestProjects/MSBuildTestApp/MSBuildTestApp.csproj +++ b/TestAssets/TestProjects/MSBuildTestApp/MSBuildTestApp.csproj @@ -4,6 +4,7 @@ Exe netcoreapp1.0 + 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/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs b/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs index f12f419c7..16fdb6b40 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs @@ -16,6 +16,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration new MigrateJsonPropertiesRule(), new MigratePackOptionsRule(), new MigrateRuntimeOptionsRule(), + new MigrateRuntimesRule(), new MigratePublishOptionsRule(), new MigrateProjectDependenciesRule(), new MigratePackageDependenciesAndToolsRule(), diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateRuntimesRule.cs b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateRuntimesRule.cs new file mode 100644 index 000000000..c0ddb8c46 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateRuntimesRule.cs @@ -0,0 +1,35 @@ +// 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 Microsoft.DotNet.ProjectJsonMigration.Transforms; + +namespace Microsoft.DotNet.ProjectJsonMigration.Rules +{ + public class MigrateRuntimesRule : IMigrationRule + { + AddPropertyTransform> RuntimeIdentifiersTransform => + new AddPropertyTransform>( + "RuntimeIdentifiers", + l => String.Join(";", l), + l => l.Count > 0); + + private readonly ITransformApplicator _transformApplicator; + + public MigrateRuntimesRule(ITransformApplicator transformApplicator = null) + { + _transformApplicator = transformApplicator ?? new TransformApplicator(); + } + + public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs) + { + var propertyGroup = migrationRuleInputs.CommonPropertyGroup; + + _transformApplicator.Execute( + RuntimeIdentifiersTransform.Transform(migrationRuleInputs.DefaultProjectContext.ProjectFile.Runtimes), + propertyGroup, + mergeExisting: true); + } + } +} diff --git a/src/Microsoft.DotNet.ProjectModel/Project.cs b/src/Microsoft.DotNet.ProjectModel/Project.cs index c174a1806..7a42b0748 100644 --- a/src/Microsoft.DotNet.ProjectModel/Project.cs +++ b/src/Microsoft.DotNet.ProjectModel/Project.cs @@ -71,6 +71,8 @@ namespace Microsoft.DotNet.ProjectModel public RuntimeOptions RuntimeOptions { get; set; } + public IList Runtimes { get; set; } + public IDictionary Commands { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public IDictionary> Scripts { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs b/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs index e65b89265..88534e11b 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs @@ -159,6 +159,7 @@ namespace Microsoft.DotNet.ProjectModel project.Dependencies = new List(); project.Tools = new List(); + project.Runtimes = new List(); // Project files project.Files = new ProjectFilesCollection(rawProject, project.ProjectDirectory, project.ProjectFilePath); @@ -224,6 +225,8 @@ namespace Microsoft.DotNet.ProjectModel "tools", isGacOrFrameworkReference: false); + PopulateRuntimes(project.Runtimes, rawProject); + JToken runtimeOptionsToken; if (rawProject.TryGetValue("runtimeOptions", out runtimeOptionsToken)) { @@ -370,6 +373,21 @@ namespace Microsoft.DotNet.ProjectModel } } + private static void PopulateRuntimes(IList results, JObject settings) + { + var runtimes = settings.Value("runtimes") as JObject; + if (runtimes != null) + { + foreach (var runtime in runtimes) + { + if (!string.IsNullOrEmpty(runtime.Key)) + { + results.Add(runtime.Key); + } + } + } + } + private void BuildTargetFrameworksAndConfigurations(Project project, JObject projectJsonObject) { // Get the shared compilationOptions diff --git a/src/dotnet/commands/dotnet-publish3/Publish3Command.cs b/src/dotnet/commands/dotnet-publish3/Publish3Command.cs index c6a4cf5f5..79366dab7 100644 --- a/src/dotnet/commands/dotnet-publish3/Publish3Command.cs +++ b/src/dotnet/commands/dotnet-publish3/Publish3Command.cs @@ -25,12 +25,6 @@ namespace Microsoft.DotNet.Tools.Publish3 public int Execute() { - int restoreResult = EnsureRestored(); - if (restoreResult != 0) - { - throw new GracefulException("Restore failed. Please fix the errors and try publishing again."); - } - List msbuildArgs = new List(); if (!string.IsNullOrEmpty(ProjectPath)) @@ -70,19 +64,5 @@ namespace Microsoft.DotNet.Tools.Publish3 return new MSBuildForwardingApp(msbuildArgs).Execute(); } - /// - /// Ensures that the project has been restored for the specified runtime. - /// - private int EnsureRestored() - { - int result = 0; - - if (!string.IsNullOrEmpty(Runtime)) - { - result = Restore3Command.Run(new[] { $"/p:RuntimeIdentifiers={Runtime}" }); - } - - return result; - } } } diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateRuntimes.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateRuntimes.cs new file mode 100644 index 000000000..a92c91754 --- /dev/null +++ b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateRuntimes.cs @@ -0,0 +1,79 @@ +using Microsoft.Build.Construction; +using Microsoft.DotNet.ProjectJsonMigration; +using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.Tools.Test.Utilities; +using NuGet.Frameworks; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using FluentAssertions; +using Microsoft.DotNet.ProjectJsonMigration.Rules; + +namespace Microsoft.DotNet.ProjectJsonMigration.Tests +{ + public class GivenThatIWantToMigrateRuntimes : TestBase + { + [Fact] + public void It_migrates_runtimes() + { + var projectJson = @" + { + ""runtimes"": { + ""win7-x64"": { }, + ""win7-x86"": { }, + ""osx.10.10-x64"": { } + } + } + "; + + var testDirectory = Temp.CreateDirectory().Path; + var migratedProj = TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[] + { + new MigrateRuntimesRule() + }, projectJson, testDirectory); + + migratedProj.Properties.Count(p => p.Name == "RuntimeIdentifiers").Should().Be(1); + migratedProj.Properties.First(p => p.Name == "RuntimeIdentifiers").Value + .Should().Be("win7-x64;win7-x86;osx.10.10-x64"); + } + + [Fact] + public void It_has_an_empty_runtime_node_to_migrate() + { + var projectJson = @" + { + ""runtimes"": { + } + } + "; + + var testDirectory = Temp.CreateDirectory().Path; + var migratedProj = TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[] + { + new MigrateRuntimesRule() + }, projectJson, testDirectory); + + migratedProj.Properties.Count(p => p.Name == "RuntimeIdentifiers").Should().Be(0); + } + + [Fact] + public void It_has_no_runtimes_to_migrate() + { + var projectJson = @" + { + } + "; + + var testDirectory = Temp.CreateDirectory().Path; + var migratedProj = TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[] + { + new MigrateRuntimesRule() + }, projectJson, testDirectory); + + migratedProj.Properties.Count(p => p.Name == "RuntimeIdentifiers").Should().Be(0); + } + } +} diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/Publish3Command.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/Publish3Command.cs index 7b0f56d06..f3a10d449 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/Publish3Command.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/Publish3Command.cs @@ -29,13 +29,13 @@ namespace Microsoft.DotNet.Tools.Test.Utilities public override CommandResult Execute(string args = "") { - args = $"publish3 {args} {BuildArgs()}"; + args = $"publish3 {BuildArgs()} {args} "; return base.Execute(args); } public override CommandResult ExecuteWithCapturedOutput(string args = "") { - args = $"publish3 {args} {BuildArgs()}"; + args = $"publish3 {BuildArgs()} {args}"; return base.ExecuteWithCapturedOutput(args); } diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs index b6496d19e..3a8514327 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs @@ -10,8 +10,8 @@ using System.IO; using Microsoft.DotNet.Tools.Migrate; using Build3Command = Microsoft.DotNet.Tools.Test.Utilities.Build3Command; using BuildCommand = Microsoft.DotNet.Tools.Test.Utilities.BuildCommand; +using Publish3Command = Microsoft.DotNet.Tools.Test.Utilities.Publish3Command; using System.Runtime.Loader; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace Microsoft.DotNet.Migration.Tests @@ -346,6 +346,19 @@ namespace Microsoft.DotNet.Migration.Tests result.StdErr.Should().Contain("Migration failed."); } + [Fact] + public void It_migrates_and_publishes_projects_with_runtimes() + { + var projectName = "TestAppSimple"; + var projectDirectory = TestAssetsManager.CreateTestInstance(projectName, callingMethod: "i") + .WithLockFiles() + .Path; + + CleanBinObj(projectDirectory); + BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName); + PublishMSBuild(projectDirectory, projectName, "win7-x64"); + } + [WindowsOnlyTheory] [InlineData("DesktopTestProjects", "AutoAddDesktopReferencesDuringMigrate", true)] [InlineData("TestProjects", "TestAppSimple", false)] @@ -558,6 +571,25 @@ namespace Microsoft.DotNet.Migration.Tests return result.StdOut; } + private string PublishMSBuild(string projectDirectory, string projectName, string runtime, string configuration = "Debug") + { + if (projectName != null) + { + projectName = projectName + ".csproj"; + } + + DeleteXproj(projectDirectory); + + var result = new Publish3Command() + .WithRuntime(runtime) + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"{projectName} /p:Configuration={configuration}"); + + result.Should().Pass(); + + return result.StdOut; + } + private void DeleteXproj(string projectDirectory) { var xprojFiles = Directory.EnumerateFiles(projectDirectory, "*.xproj"); diff --git a/test/dotnet-publish3.Tests/GivenDotnetPublish3PublishesProjects.cs b/test/dotnet-publish3.Tests/GivenDotnetPublish3PublishesProjects.cs index 55e15c862..094d42f9a 100644 --- a/test/dotnet-publish3.Tests/GivenDotnetPublish3PublishesProjects.cs +++ b/test/dotnet-publish3.Tests/GivenDotnetPublish3PublishesProjects.cs @@ -25,24 +25,20 @@ namespace Microsoft.DotNet.Cli.Publish3.Tests new Restore3Command() .WithWorkingDirectory(testProjectDirectory) .Execute() - .Should() - .Pass(); + .Should().Pass(); new Publish3Command() .WithWorkingDirectory(testProjectDirectory) .Execute("--framework netcoreapp1.0") - .Should() - .Pass(); + .Should().Pass(); var configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? "Debug"; var outputDll = Path.Combine(testProjectDirectory, "bin", configuration, "netcoreapp1.0", "publish", $"{testAppName}.dll"); new TestCommand("dotnet") .ExecuteWithCapturedOutput(outputDll) - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World"); + .Should().Pass() + .And.HaveStdOutContaining("Hello World"); } [Fact] @@ -55,23 +51,25 @@ namespace Microsoft.DotNet.Cli.Publish3.Tests var testProjectDirectory = testInstance.TestRoot; var rid = DotnetLegacyRuntimeIdentifiers.InferLegacyRestoreRuntimeIdentifier(); + new Restore3Command() + .WithWorkingDirectory(testProjectDirectory) + .Execute() + .Should().Pass(); + new Publish3Command() .WithFramework("netcoreapp1.0") .WithRuntime(rid) .WithWorkingDirectory(testProjectDirectory) .Execute() - .Should() - .Pass(); + .Should().Pass(); var configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? "Debug"; var outputProgram = Path.Combine(testProjectDirectory, "bin", configuration, "netcoreapp1.0", rid, "publish", $"{testAppName}{Constants.ExeSuffix}"); new TestCommand(outputProgram) .ExecuteWithCapturedOutput() - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World"); + .Should().Pass() + .And.HaveStdOutContaining("Hello World"); } } }