From 768e289f0c7931f9efe58bb426aef0af836724f1 Mon Sep 17 00:00:00 2001 From: Livar Cunha Date: Thu, 22 Sep 2016 16:14:27 -0700 Subject: [PATCH] Adding migrate PackOptions capabilities. --- .../DefaultMigrationRuleSet.cs | 10 +- .../MigrationErrorCodes.cs | 3 + .../Rules/MigratePackOptionsRule.cs | 100 ++++++++ .../GivenThatIWantToMigratePackOptions.cs | 220 ++++++++++++++++++ 4 files changed, 324 insertions(+), 9 deletions(-) create mode 100644 src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigratePackOptionsRule.cs create mode 100644 test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackOptions.cs diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs b/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs index 7801a11d6c..be1ff63239 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs @@ -1,16 +1,7 @@ // 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.Build.Evaluation; -using Microsoft.Build.Construction; -using Microsoft.DotNet.ProjectModel; -using Microsoft.DotNet.Cli; -using System.Linq; -using System.IO; using Microsoft.DotNet.ProjectJsonMigration.Rules; -using Newtonsoft.Json; namespace Microsoft.DotNet.ProjectJsonMigration { @@ -21,6 +12,7 @@ public class DefaultMigrationRuleSet : IMigrationRule new MigrateRootOptionsRule(), new MigrateTFMRule(), new MigrateBuildOptionsRule(), + new MigratePackOptionsRule(), new MigrateRuntimeOptionsRule(), new MigratePublishOptionsRule(), new MigrateProjectDependenciesRule(), diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationErrorCodes.cs b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationErrorCodes.cs index 132d51ab2a..1647e52bfb 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationErrorCodes.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationErrorCodes.cs @@ -31,5 +31,8 @@ public static Func MIGRATE20012 public static Func MIGRATE20013 => (message) => new MigrationError(nameof(MIGRATE20013), "Non-Csharp App", message); + + public static Func MIGRATE20018 + => (message) => new MigrationError(nameof(MIGRATE20018), "Files specified under PackOptions", message); } } \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigratePackOptionsRule.cs b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigratePackOptionsRule.cs new file mode 100644 index 0000000000..f90bdbd56e --- /dev/null +++ b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigratePackOptionsRule.cs @@ -0,0 +1,100 @@ +// 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.Linq; +using Microsoft.DotNet.ProjectJsonMigration; +using Microsoft.DotNet.ProjectJsonMigration.Transforms; +using Microsoft.DotNet.ProjectModel; + +namespace Microsoft.DotNet.ProjectJsonMigration.Rules +{ + public class MigratePackOptionsRule : IMigrationRule + { + private AddPropertyTransform TagsTransform => new AddPropertyTransform( + "PackageTags", + packOptions => string.Join(";", packOptions.Tags), + packOptions => packOptions.Tags != null && packOptions.Tags.Any()); + + private AddPropertyTransform ReleaseNotesTransform => new AddPropertyTransform( + "PackageReleaseNotes", + packOptions => packOptions.ReleaseNotes, + packOptions => !string.IsNullOrEmpty(packOptions.ReleaseNotes)); + + private AddPropertyTransform IconUrlTransform => new AddPropertyTransform( + "PackageIconUrl", + packOptions => packOptions.IconUrl, + packOptions => !string.IsNullOrEmpty(packOptions.IconUrl)); + + private AddPropertyTransform ProjectUrlTransform => new AddPropertyTransform( + "PackageProjectUrl", + packOptions => packOptions.ProjectUrl, + packOptions => !string.IsNullOrEmpty(packOptions.ProjectUrl)); + + private AddPropertyTransform LicenseUrlTransform => new AddPropertyTransform( + "PackageLicenseUrl", + packOptions => packOptions.LicenseUrl, + packOptions => !string.IsNullOrEmpty(packOptions.LicenseUrl)); + + private AddPropertyTransform RequireLicenseAcceptanceTransform => new AddPropertyTransform( + "PackageRequireLicenseAcceptance", + packOptions => packOptions.RequireLicenseAcceptance.ToString().ToLower(), + packOptions => true); + + private AddPropertyTransform RepositoryTypeTransform => new AddPropertyTransform( + "RepositoryType", + packOptions => packOptions.RepositoryType, + packOptions => !string.IsNullOrEmpty(packOptions.RepositoryType)); + + private AddPropertyTransform RepositoryUrlTransform => new AddPropertyTransform( + "RepositoryUrl", + packOptions => packOptions.RepositoryUrl, + packOptions => !string.IsNullOrEmpty(packOptions.RepositoryUrl)); + + private readonly ITransformApplicator _transformApplicator; + + private List> _propertyTransforms; + + public MigratePackOptionsRule(ITransformApplicator transformApplicator = null) + { + _transformApplicator = transformApplicator ?? new TransformApplicator(); + + ConstructTransformLists(); + } + + private void ConstructTransformLists() + { + _propertyTransforms = new List>() + { + TagsTransform, + ReleaseNotesTransform, + IconUrlTransform, + ProjectUrlTransform, + LicenseUrlTransform, + RequireLicenseAcceptanceTransform, + RepositoryTypeTransform, + RepositoryUrlTransform + }; + } + + public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs) + { + var propertyGroup = migrationRuleInputs.CommonPropertyGroup; + + var projectContext = migrationRuleInputs.DefaultProjectContext; + var packOptions = projectContext.ProjectFile.PackOptions; + + if(packOptions.PackInclude != null) + { + MigrationErrorCodes + .MIGRATE20018("Migrating projects with Files specified in PackOptions is not supported.").Throw(); + } + + foreach (var propertyTransfrom in _propertyTransforms) + { + _transformApplicator.Execute(propertyTransfrom.Transform(packOptions), propertyGroup); + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackOptions.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackOptions.cs new file mode 100644 index 0000000000..625e444c1e --- /dev/null +++ b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackOptions.cs @@ -0,0 +1,220 @@ +// 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 Microsoft.Build.Construction; +using Microsoft.DotNet.Tools.Test.Utilities; +using System.Linq; +using Xunit; +using FluentAssertions; +using Microsoft.DotNet.ProjectJsonMigration.Rules; +using System; + +namespace Microsoft.DotNet.ProjectJsonMigration.Tests +{ + public class GivenThatIWantToMigratePackOptions : TestBase + { + [Fact] + public void It_does_not_migrate_Summary() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""summary"": ""Some not important summary"" + } + }"); + + EmitsOnlyAlwaysEmittedPackOptionsProperties(mockProj); + } + + [Fact] + public void It_does_not_migrate_Owner() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""owner"": ""Some not important owner"" + } + }"); + + EmitsOnlyAlwaysEmittedPackOptionsProperties(mockProj); + } + + [Fact] + public void Migrating__empty_tags_does_not_populate_PackageTags() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""tags"": [] + } + }"); + + mockProj.Properties.Count(p => p.Name == "PackageTags").Should().Be(0); + } + + [Fact] + public void Migrating_tags_populates_PackageTags_semicolon_delimited() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""tags"": [""hyperscale"", ""cats""] + } + }"); + + mockProj.Properties.Count(p => p.Name == "PackageTags").Should().Be(1); + mockProj.Properties.First(p => p.Name == "PackageTags").Value.Should().Be("hyperscale;cats"); + } + + [Fact] + public void Migrating_ReleaseNotes_populates_PackageReleaseNotes() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""releaseNotes"": ""Some release notes value."" + } + }"); + + mockProj.Properties.Count(p => p.Name == "PackageReleaseNotes").Should().Be(1); + mockProj.Properties.First(p => p.Name == "PackageReleaseNotes").Value.Should() + .Be("Some release notes value."); + } + + [Fact] + public void Migrating_IconUrl_populates_PackageIconUrl() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""iconUrl"": ""http://www.mylibrary.gov/favicon.ico"" + } + }"); + + mockProj.Properties.Count(p => p.Name == "PackageIconUrl").Should().Be(1); + mockProj.Properties.First(p => p.Name == "PackageIconUrl").Value.Should() + .Be("http://www.mylibrary.gov/favicon.ico"); + } + + [Fact] + public void Migrating_ProjectUrl_populates_PackageProjectUrl() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""projectUrl"": ""http://www.url.to.library.com"" + } + }"); + + mockProj.Properties.Count(p => p.Name == "PackageProjectUrl").Should().Be(1); + mockProj.Properties.First(p => p.Name == "PackageProjectUrl").Value.Should() + .Be("http://www.url.to.library.com"); + } + + [Fact] + public void Migrating_LicenseUrl_populates_PackageLicenseUrl() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""licenseUrl"": ""http://www.url.to.library.com/licence"" + } + }"); + + mockProj.Properties.Count(p => p.Name == "PackageLicenseUrl").Should().Be(1); + mockProj.Properties.First(p => p.Name == "PackageLicenseUrl").Value.Should() + .Be("http://www.url.to.library.com/licence"); + } + + [Fact] + public void Migrating_RequireLicenseAcceptance_populates_PackageRequireLicenseAcceptance() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""requireLicenseAcceptance"": ""true"" + } + }"); + + mockProj.Properties.Count(p => p.Name == "PackageRequireLicenseAcceptance").Should().Be(1); + mockProj.Properties.First(p => p.Name == "PackageRequireLicenseAcceptance").Value.Should().Be("true"); + } + + [Fact] + public void Migrating_RequireLicenseAcceptance_populates_PackageRequireLicenseAcceptance_even_if_its_value_is_false() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""requireLicenseAcceptance"": ""false"" + } + }"); + + mockProj.Properties.Count(p => p.Name == "PackageRequireLicenseAcceptance").Should().Be(1); + mockProj.Properties.First(p => p.Name == "PackageRequireLicenseAcceptance").Value.Should().Be("false"); + } + + [Fact] + public void Migrating_Repository_Type_populates_RepositoryType() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""repository"": { + ""type"": ""git"" + } + } + }"); + + mockProj.Properties.Count(p => p.Name == "RepositoryType").Should().Be(1); + mockProj.Properties.First(p => p.Name == "RepositoryType").Value.Should().Be("git"); + } + + [Fact] + public void Migrating_Repository_Url_populates_RepositoryUrl() + { + var mockProj = RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""repository"": { + ""url"": ""http://github.com/dotnet/cli"" + } + } + }"); + + mockProj.Properties.Count(p => p.Name == "RepositoryUrl").Should().Be(1); + mockProj.Properties.First(p => p.Name == "RepositoryUrl").Value.Should().Be("http://github.com/dotnet/cli"); + } + + [Fact] + public void Migrating_Files_throws_an_exception_for_now() + { + Action action = () => RunPackOptionsRuleOnPj(@" + { + ""packOptions"": { + ""files"": { + ""include"": [""somefile.cs""] + } + } + }"); + + action.ShouldThrow() + .Where(e => e.Message.Contains("Migrating projects with Files specified in PackOptions is not supported.")); + } + + private ProjectRootElement RunPackOptionsRuleOnPj(string packOptions, string testDirectory = null) + { + testDirectory = testDirectory ?? Temp.CreateDirectory().Path; + return TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[] + { + new MigratePackOptionsRule() + }, packOptions, testDirectory); + } + + private void EmitsOnlyAlwaysEmittedPackOptionsProperties(ProjectRootElement project) + { + project.Properties.Count().Should().Be(1); + project.Properties.All(p => p.Name == "PackageRequireLicenseAcceptance").Should().BeTrue(); + } + } +} \ No newline at end of file