Merge pull request #4074 from brthor/brthor/migrate-reviewable
ProjectJson to CSProj Migration
This commit is contained in:
commit
dc59da7ce3
76 changed files with 4996 additions and 32 deletions
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
VisualStudioVersion = 14.0.25123.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED2FE3E2-F7E7-4389-8231-B65123F2076F}"
|
||||
EndProject
|
||||
|
@ -26,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{17735A9D-B
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{0722D325-24C8-4E83-B5AF-0A083E7F0749}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MultiProjectValidator", "tools\MultiProjectValidator\MultiProjectValidator.xproj", "{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "EndToEnd", "test\EndToEnd\EndToEnd.xproj", "{65741CB1-8AEE-4C66-8198-10A7EA0E4258}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestProjects", "TestProjects", "{713CBFBB-5392-438D-B766-A9A585EF1BB8}"
|
||||
|
@ -152,7 +154,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "publish", "publish", "{27B1
|
|||
build\publish\PublishContent.targets = build\publish\PublishContent.targets
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Tools.Test", "src\Microsoft.DotNet.Tools.Test\Microsoft.DotNet.Tools.Test.xproj", "{6D028154-5518-4A56-BAD6-938A90E5BCF6}"
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.ProjectJsonMigration", "src\Microsoft.DotNet.ProjectJsonMigration\Microsoft.DotNet.ProjectJsonMigration.xproj", "{0E083818-2320-4388-8007-4F720FD5C634}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.ProjectJsonMigration.Tests", "test\Microsoft.DotNet.ProjectJsonMigration.Tests\Microsoft.DotNet.ProjectJsonMigration.Tests.xproj", "{1F2EF070-AC5F-4078-AFB0-65745AC691B9}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-migrate.Tests", "test\dotnet-migrate.Tests\dotnet-migrate.Tests.xproj", "{1F2EF070-AC5F-4078-AFB0-65745AC691B9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -246,6 +252,22 @@ Global
|
|||
{DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.Release|x64.Build.0 = Release|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
{65741CB1-8AEE-4C66-8198-10A7EA0E4258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{65741CB1-8AEE-4C66-8198-10A7EA0E4258}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{65741CB1-8AEE-4C66-8198-10A7EA0E4258}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
|
@ -838,6 +860,55 @@ Global
|
|||
{E4F46EAB-B5A5-4E60-9B9D-40A1FADBF45C}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4F46EAB-B5A5-4E60-9B9D-40A1FADBF45C}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{E4F46EAB-B5A5-4E60-9B9D-40A1FADBF45C}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.Release|x64.Build.0 = Release|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.Debug|x64.Build.0 = Debug|x64
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|Any CPU
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.MinSizeRel|Any CPU.Build.0 = MinSizeRel|Any CPU
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.Release|x64.ActiveCfg = Release|x64
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.Release|x64.Build.0 = Release|x64
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|Any CPU
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.RelWithDebInfo|Any CPU.Build.0 = RelWithDebInfo|Any CPU
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{0E083818-2320-4388-8007-4F720FD5C634}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.Debug|x64.Build.0 = Debug|x64
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|Any CPU
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.MinSizeRel|Any CPU.Build.0 = MinSizeRel|Any CPU
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.Release|x64.ActiveCfg = Release|x64
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.Release|x64.Build.0 = Release|x64
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|Any CPU
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.RelWithDebInfo|Any CPU.Build.0 = RelWithDebInfo|Any CPU
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
|
||||
{6D028154-5518-4A56-BAD6-938A90E5BCF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6D028154-5518-4A56-BAD6-938A90E5BCF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6D028154-5518-4A56-BAD6-938A90E5BCF6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
|
@ -864,6 +935,7 @@ Global
|
|||
{A16958E1-24C7-4F1E-B317-204AD91625DD} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
|
||||
{BD7833F8-3209-4682-BF75-B4BCA883E279} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
|
||||
{DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
|
||||
{688870C8-9843-4F9E-8576-D39290AD0F25} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
|
||||
{65741CB1-8AEE-4C66-8198-10A7EA0E4258} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
|
||||
{713CBFBB-5392-438D-B766-A9A585EF1BB8} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
|
||||
{60CF7E6C-D6C8-439D-B7B7-D8A27E29BE2C} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
|
||||
|
@ -911,5 +983,8 @@ Global
|
|||
{E4F46EAB-B5A5-4E60-9B9D-40A1FADBF45C} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
|
||||
{27B12960-ABB0-4903-9C60-5E9157E659C8} = {89905EC4-BC0F-443B-8ADF-691321F10108}
|
||||
{6D028154-5518-4A56-BAD6-938A90E5BCF6} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
|
||||
{EDD6C92D-0A58-4FCB-A0E9-9D0FFC045177} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
|
||||
{0E083818-2320-4388-8007-4F720FD5C634} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
|
||||
{1F2EF070-AC5F-4078-AFB0-65745AC691B9} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>58808bbc-371e-47d6-a3d0-4902145eda4e</ProjectGuid>
|
||||
<RootNamespace>TestApp</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
|
@ -0,0 +1,17 @@
|
|||
// 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("Hello World");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
@echo off
|
||||
echo %*
|
2
TestAssets/TestProjects/TestAppWithMigrateableScripts/echoscript.sh
Executable file
2
TestAssets/TestProjects/TestAppWithMigrateableScripts/echoscript.sh
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env sh
|
||||
echo $@
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"buildOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0",
|
||||
}
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {}
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": [
|
||||
"echoscript prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:FullTargetFramework%?"
|
||||
],
|
||||
"postpublish": [
|
||||
"echoscript postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:FullTargetFramework%?"
|
||||
],
|
||||
"precompile": [
|
||||
"echoscript precompile_output ?%compile:Configuration%? ?%compile:OutputDir%? ?%compile:FullTargetFramework%?"
|
||||
],
|
||||
"postcompile": [
|
||||
"echoscript postcompile_output ?%compile:Configuration%? ?%compile:OutputDir%? ?%compile:FullTargetFramework%?"
|
||||
]
|
||||
}
|
||||
}
|
12
TestAssets/TestProjects/TestAppWithRuntimeOptions/Program.cs
Normal file
12
TestAssets/TestProjects/TestAppWithRuntimeOptions/Program.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace ConsoleApplication
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"buildOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
}
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {}
|
||||
},
|
||||
"runtimeOptions": {
|
||||
"somethingString": "anything",
|
||||
"somethingBoolean": true,
|
||||
"someArray": [
|
||||
"one",
|
||||
"two"
|
||||
],
|
||||
"someObject": {
|
||||
"someProperty": "someValue"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
||||
{
|
||||
public class ConstantPackageNames
|
||||
{
|
||||
public const string CSdkPackageName = "Microsoft.DotNet.Core.Sdk";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// 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
|
||||
{
|
||||
public class DefaultMigrationRuleSet : IMigrationRule
|
||||
{
|
||||
private IMigrationRule[] Rules => new IMigrationRule[]
|
||||
{
|
||||
new MigrateRootOptionsRule(),
|
||||
new MigrateTFMRule(),
|
||||
new MigrateBuildOptionsRule(),
|
||||
new MigrateRuntimeOptionsRule(),
|
||||
new MigratePublishOptionsRule(),
|
||||
new MigrateProjectDependenciesRule(),
|
||||
new MigrateConfigurationsRule(),
|
||||
new MigrateScriptsRule(),
|
||||
new TemporaryMutateProjectJsonRule(),
|
||||
new SaveOutputProjectRule()
|
||||
};
|
||||
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
foreach (var rule in Rules)
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(DefaultMigrationRuleSet)}: Executing migration rule {rule.GetType().Name}");
|
||||
rule.Apply(migrationSettings, migrationRuleInputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
121
src/Microsoft.DotNet.ProjectJsonMigration/MSBuildExtensions.cs
Normal file
121
src/Microsoft.DotNet.ProjectJsonMigration/MSBuildExtensions.cs
Normal file
|
@ -0,0 +1,121 @@
|
|||
// 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.Utils;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
||||
{
|
||||
public static class MSBuildExtensions
|
||||
{
|
||||
public static IEnumerable<ProjectPropertyElement> PropertiesWithoutConditions(
|
||||
this ProjectRootElement projectRoot)
|
||||
{
|
||||
return ElementsWithoutConditions(projectRoot.Properties);
|
||||
}
|
||||
|
||||
public static IEnumerable<ProjectItemElement> ItemsWithoutConditions(
|
||||
this ProjectRootElement projectRoot)
|
||||
{
|
||||
return ElementsWithoutConditions(projectRoot.Items);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Includes(
|
||||
this ProjectItemElement item)
|
||||
{
|
||||
return SplitSemicolonDelimitedValues(item.Include);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Excludes(
|
||||
this ProjectItemElement item)
|
||||
{
|
||||
return SplitSemicolonDelimitedValues(item.Exclude);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> AllConditions(this ProjectElement projectElement)
|
||||
{
|
||||
return new string[] { projectElement.Condition }.Concat(projectElement.AllParents.Select(p=> p.Condition));
|
||||
}
|
||||
|
||||
public static IEnumerable<string> IntersectIncludes(this ProjectItemElement item, ProjectItemElement otherItem)
|
||||
{
|
||||
return item.Includes().Intersect(otherItem.Includes());
|
||||
}
|
||||
|
||||
public static void RemoveIncludes(this ProjectItemElement item, IEnumerable<string> includesToRemove)
|
||||
{
|
||||
item.Include = string.Join(";", item.Includes().Except(includesToRemove));
|
||||
}
|
||||
|
||||
public static void UnionIncludes(this ProjectItemElement item, IEnumerable<string> includesToAdd)
|
||||
{
|
||||
item.Include = string.Join(";", item.Includes().Union(includesToAdd));
|
||||
}
|
||||
|
||||
public static void UnionExcludes(this ProjectItemElement item, IEnumerable<string> excludesToAdd)
|
||||
{
|
||||
item.Exclude = string.Join(";", item.Excludes().Union(excludesToAdd));
|
||||
}
|
||||
|
||||
public static ProjectMetadataElement GetMetadataWithName(this ProjectItemElement item, string name)
|
||||
{
|
||||
return item.Metadata.FirstOrDefault(m => m.Name.Equals(name, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
public static bool ValueEquals(this ProjectMetadataElement metadata, ProjectMetadataElement otherMetadata)
|
||||
{
|
||||
return metadata.Value.Equals(otherMetadata.Value, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static void AddMetadata(this ProjectItemElement item, ICollection<ProjectMetadataElement> metadataElements)
|
||||
{
|
||||
foreach (var metadata in metadataElements)
|
||||
{
|
||||
item.AddMetadata(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveIfEmpty(this ProjectElementContainer container)
|
||||
{
|
||||
if (!container.Children.Any())
|
||||
{
|
||||
container.Parent.RemoveChild(container);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddMetadata(this ProjectItemElement item, ProjectMetadataElement metadata)
|
||||
{
|
||||
var existingMetadata = item.GetMetadataWithName(metadata.Name);
|
||||
|
||||
if (existingMetadata != default(ProjectMetadataElement) && !existingMetadata.ValueEquals(metadata))
|
||||
{
|
||||
throw new Exception("Cannot merge metadata with the same name and different values");
|
||||
}
|
||||
|
||||
if (existingMetadata == default(ProjectMetadataElement))
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(AddMetadata)}: Adding metadata to {item.ItemType} item: {{ {metadata.Name}, {metadata.Value} }}");
|
||||
item.AddMetadata(metadata.Name, metadata.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> SplitSemicolonDelimitedValues(string combinedValue)
|
||||
{
|
||||
return string.IsNullOrEmpty(combinedValue) ? Enumerable.Empty<string>() : combinedValue.Split(';');
|
||||
}
|
||||
|
||||
private static IEnumerable<T> ElementsWithoutConditions<T>(IEnumerable<T> elements) where T : ProjectElement
|
||||
{
|
||||
return elements
|
||||
.Where(e => string.IsNullOrEmpty(e.Condition)
|
||||
&& e.AllParents.All(parent => string.IsNullOrEmpty(parent.Condition)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,16 +4,15 @@
|
|||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>947dd232-8d9b-4b78-9c6a-94f807d2dd58</ProjectGuid>
|
||||
<RootNamespace>TestLibrary</RootNamespace>
|
||||
<ProjectGuid>0E083818-2320-4388-8007-4F720FD5C634</ProjectGuid>
|
||||
<RootNamespace>Microsoft.DotNet.ProjectJsonMigration</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
30
src/Microsoft.DotNet.ProjectJsonMigration/MigrationError.cs
Normal file
30
src/Microsoft.DotNet.ProjectJsonMigration/MigrationError.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
||||
{
|
||||
public class MigrationError
|
||||
{
|
||||
public string ErrorCode { get; }
|
||||
|
||||
public string GeneralErrorReason { get; }
|
||||
|
||||
public string Message { get; }
|
||||
|
||||
public MigrationError(string errorCode, string generalErrorReason, string message)
|
||||
{
|
||||
ErrorCode = errorCode;
|
||||
GeneralErrorReason = generalErrorReason;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public void Throw()
|
||||
{
|
||||
throw new Exception(GetFormattedErrorMessage());
|
||||
}
|
||||
|
||||
public string GetFormattedErrorMessage()
|
||||
{
|
||||
return $"{ErrorCode}::{GeneralErrorReason}: {Message}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
||||
{
|
||||
public static partial class MigrationErrorCodes
|
||||
{
|
||||
public static Func<string, MigrationError> MIGRATE1011
|
||||
=> (message) => new MigrationError(nameof(MIGRATE1011), "Deprecated Project", message);
|
||||
|
||||
public static Func<string, MigrationError> MIGRATE1012
|
||||
=> (message) => new MigrationError(nameof(MIGRATE1012), "Project not Restored", message);
|
||||
|
||||
public static Func<string, MigrationError> MIGRATE1013
|
||||
=> (message) => new MigrationError(nameof(MIGRATE1013), "No Project", message);
|
||||
|
||||
public static Func<string, MigrationError> MIGRATE1014
|
||||
=> (message) => new MigrationError(nameof(MIGRATE1014), "Unresolved Dependency", message);
|
||||
|
||||
public static Func<string, MigrationError> MIGRATE1015
|
||||
=> (message) => new MigrationError(nameof(MIGRATE1015), "File Overwrite", message);
|
||||
|
||||
public static Func<string, MigrationError> MIGRATE1016
|
||||
=> (message) => new MigrationError(nameof(MIGRATE1016), "Unsupported Script Variable", message);
|
||||
|
||||
// Potentially Temporary (Point in Time) Errors
|
||||
public static Func<string, MigrationError> MIGRATE20011
|
||||
=> (message) => new MigrationError(nameof(MIGRATE20011), "Multi-TFM", message);
|
||||
|
||||
public static Func<string, MigrationError> MIGRATE20012
|
||||
=> (message) => new MigrationError(nameof(MIGRATE20012), "Configuration Exclude", message);
|
||||
|
||||
public static Func<string, MigrationError> MIGRATE20013
|
||||
=> (message) => new MigrationError(nameof(MIGRATE20013), "Non-Csharp App", message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// 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.Utils;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
||||
{
|
||||
public class MigrationRuleInputs
|
||||
{
|
||||
public ProjectRootElement OutputMSBuildProject { get; }
|
||||
|
||||
public ProjectItemGroupElement CommonItemGroup { get; }
|
||||
|
||||
public ProjectPropertyGroupElement CommonPropertyGroup { get; }
|
||||
|
||||
public IEnumerable<ProjectContext> ProjectContexts { get; }
|
||||
|
||||
public ProjectContext DefaultProjectContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return ProjectContexts.First();
|
||||
}
|
||||
}
|
||||
|
||||
public MigrationRuleInputs(
|
||||
IEnumerable<ProjectContext> projectContexts,
|
||||
ProjectRootElement outputMSBuildProject,
|
||||
ProjectItemGroupElement commonItemGroup,
|
||||
ProjectPropertyGroupElement commonPropertyGroup)
|
||||
{
|
||||
ProjectContexts = projectContexts;
|
||||
OutputMSBuildProject = outputMSBuildProject;
|
||||
CommonItemGroup = commonItemGroup;
|
||||
CommonPropertyGroup = commonPropertyGroup;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.Build.Evaluation;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
||||
{
|
||||
public class MigrationSettings
|
||||
{
|
||||
public string ProjectDirectory { get; }
|
||||
public string OutputDirectory { get; }
|
||||
public string SdkPackageVersion { get; }
|
||||
public ProjectRootElement MSBuildProjectTemplate { get; }
|
||||
|
||||
public MigrationSettings(
|
||||
string projectDirectory,
|
||||
string outputDirectory,
|
||||
string sdkPackageVersion,
|
||||
ProjectRootElement msBuildProjectTemplate)
|
||||
{
|
||||
ProjectDirectory = projectDirectory;
|
||||
OutputDirectory = outputDirectory;
|
||||
SdkPackageVersion = sdkPackageVersion;
|
||||
MSBuildProjectTemplate = msBuildProjectTemplate;
|
||||
}
|
||||
}
|
||||
}
|
37
src/Microsoft.DotNet.ProjectJsonMigration/MigrationTrace.cs
Normal file
37
src/Microsoft.DotNet.ProjectJsonMigration/MigrationTrace.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
||||
{
|
||||
public class MigrationTrace
|
||||
{
|
||||
public static MigrationTrace Instance { get; set; }
|
||||
|
||||
static MigrationTrace ()
|
||||
{
|
||||
Instance = new MigrationTrace();
|
||||
}
|
||||
|
||||
public string EnableEnvironmentVariable => "DOTNET_MIGRATION_TRACE";
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
#if DEBUG
|
||||
return true;
|
||||
#else
|
||||
return Environment.GetEnvironmentVariable(EnableEnvironmentVariable) != null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
if (IsEnabled)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// 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 Microsoft.DotNet.ProjectJsonMigration.Models
|
||||
{
|
||||
public class ItemMetadataValue<T>
|
||||
{
|
||||
public string MetadataName { get; }
|
||||
|
||||
private readonly string _metadataValue;
|
||||
private readonly Func<T, string> _metadataValueFunc;
|
||||
|
||||
public ItemMetadataValue(string metadataName, string metadataValue)
|
||||
{
|
||||
MetadataName = metadataName;
|
||||
_metadataValue = metadataValue;
|
||||
}
|
||||
|
||||
public ItemMetadataValue(string metadataName, Func<T, string> metadataValueFunc)
|
||||
{
|
||||
MetadataName = metadataName;
|
||||
_metadataValueFunc = metadataValueFunc;
|
||||
}
|
||||
|
||||
public string GetMetadataValue(T source)
|
||||
{
|
||||
return _metadataValue ?? _metadataValueFunc(source);
|
||||
}
|
||||
}
|
||||
}
|
140
src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs
Normal file
140
src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs
Normal file
|
@ -0,0 +1,140 @@
|
|||
// 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 Microsoft.DotNet.Tools.Common;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
||||
{
|
||||
public class ProjectMigrator
|
||||
{
|
||||
// TODO: Migrate PackOptions
|
||||
// TODO: Support Mappings in IncludeContext Transformations
|
||||
// TODO: Migrate Multi-TFM projects
|
||||
// TODO: Tests
|
||||
// TODO: Out of Scope
|
||||
// - Globs that resolve to directories: /some/path/**/somedir
|
||||
// - Migrating Deprecated project.jsons
|
||||
// - Configuration dependent source exclusion
|
||||
|
||||
private readonly IMigrationRule _ruleSet;
|
||||
|
||||
public ProjectMigrator() : this(new DefaultMigrationRuleSet()) { }
|
||||
|
||||
public ProjectMigrator(IMigrationRule ruleSet)
|
||||
{
|
||||
_ruleSet = ruleSet;
|
||||
}
|
||||
|
||||
public void Migrate(MigrationSettings migrationSettings)
|
||||
{
|
||||
var migrationRuleInputs = ComputeMigrationRuleInputs(migrationSettings);
|
||||
VerifyInputs(migrationRuleInputs, migrationSettings);
|
||||
|
||||
SetupOutputDirectory(migrationSettings.ProjectDirectory, migrationSettings.OutputDirectory);
|
||||
|
||||
_ruleSet.Apply(migrationSettings, migrationRuleInputs);
|
||||
}
|
||||
|
||||
private MigrationRuleInputs ComputeMigrationRuleInputs(MigrationSettings migrationSettings)
|
||||
{
|
||||
var projectContexts = ProjectContext.CreateContextForEachFramework(migrationSettings.ProjectDirectory);
|
||||
|
||||
var templateMSBuildProject = migrationSettings.MSBuildProjectTemplate;
|
||||
if (templateMSBuildProject == null)
|
||||
{
|
||||
throw new Exception("Expected non-null MSBuildProjectTemplate in MigrationSettings");
|
||||
}
|
||||
|
||||
var propertyGroup = templateMSBuildProject.AddPropertyGroup();
|
||||
var itemGroup = templateMSBuildProject.AddItemGroup();
|
||||
|
||||
return new MigrationRuleInputs(projectContexts, templateMSBuildProject, itemGroup, propertyGroup);
|
||||
}
|
||||
|
||||
private void VerifyInputs(MigrationRuleInputs migrationRuleInputs, MigrationSettings migrationSettings)
|
||||
{
|
||||
VerifyProject(migrationRuleInputs.ProjectContexts, migrationSettings.ProjectDirectory);
|
||||
}
|
||||
|
||||
private void VerifyProject(IEnumerable<ProjectContext> projectContexts, string projectDirectory)
|
||||
{
|
||||
if (projectContexts.Count() > 1)
|
||||
{
|
||||
MigrationErrorCodes.MIGRATE20011($"Multi-TFM projects currently not supported.").Throw();
|
||||
}
|
||||
|
||||
if (!projectContexts.Any())
|
||||
{
|
||||
MigrationErrorCodes.MIGRATE1013($"No projects found in {projectDirectory}").Throw();
|
||||
}
|
||||
|
||||
var defaultProjectContext = projectContexts.First();
|
||||
|
||||
if (defaultProjectContext.LockFile == null)
|
||||
{
|
||||
MigrationErrorCodes.MIGRATE1012(
|
||||
$"project.lock.json not found in {projectDirectory}, please run dotnet restore before doing migration").Throw();
|
||||
}
|
||||
|
||||
var diagnostics = defaultProjectContext.ProjectFile.Diagnostics;
|
||||
if (diagnostics.Any())
|
||||
{
|
||||
MigrationErrorCodes.MIGRATE1011(
|
||||
$"{projectDirectory}{Environment.NewLine}{string.Join(Environment.NewLine, diagnostics.Select(d => d.Message))}")
|
||||
.Throw();
|
||||
}
|
||||
|
||||
var compilerName =
|
||||
defaultProjectContext.ProjectFile.GetCompilerOptions(defaultProjectContext.TargetFramework, "_")
|
||||
.CompilerName;
|
||||
if (!compilerName.Equals("csc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
MigrationErrorCodes.MIGRATE20013(
|
||||
$"Cannot migrate project {defaultProjectContext.ProjectFile.ProjectFilePath} using compiler {compilerName}").Throw();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupOutputDirectory(string projectDirectory, string outputDirectory)
|
||||
{
|
||||
if (!Directory.Exists(outputDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(outputDirectory);
|
||||
}
|
||||
|
||||
if (projectDirectory != outputDirectory)
|
||||
{
|
||||
CopyProjectToOutputDirectory(projectDirectory, outputDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyProjectToOutputDirectory(string projectDirectory, string outputDirectory)
|
||||
{
|
||||
var sourceFilePaths = Directory.EnumerateFiles(projectDirectory, "*", SearchOption.AllDirectories);
|
||||
|
||||
foreach (var sourceFilePath in sourceFilePaths)
|
||||
{
|
||||
var relativeFilePath = PathUtility.GetRelativePath(projectDirectory, sourceFilePath);
|
||||
var destinationFilePath = Path.Combine(outputDirectory, relativeFilePath);
|
||||
var destinationDirectory = Path.GetDirectoryName(destinationFilePath);
|
||||
|
||||
if (!Directory.Exists(destinationDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(destinationDirectory);
|
||||
}
|
||||
|
||||
File.Copy(sourceFilePath, destinationFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +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.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Microsoft.DotNet.ProjectJsonMigration.Tests")]
|
|
@ -0,0 +1,10 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
public interface IMigrationRule
|
||||
{
|
||||
void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,402 @@
|
|||
// 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.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Files;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
// TODO: Should All build options be protected by a configuration condition?
|
||||
// This will prevent the entire merge issue altogether and sidesteps the problem of having a duplicate include with different excludes...
|
||||
public class MigrateBuildOptionsRule : IMigrationRule
|
||||
{
|
||||
private AddPropertyTransform<CommonCompilerOptions>[] EmitEntryPointTransforms
|
||||
=> new []
|
||||
{
|
||||
new AddPropertyTransform<CommonCompilerOptions>("OutputType", "Exe",
|
||||
compilerOptions => compilerOptions.EmitEntryPoint != null && compilerOptions.EmitEntryPoint.Value),
|
||||
new AddPropertyTransform<CommonCompilerOptions>("OutputType", "Library",
|
||||
compilerOptions => compilerOptions.EmitEntryPoint == null || !compilerOptions.EmitEntryPoint.Value)
|
||||
};
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions>[] KeyFileTransforms
|
||||
=> new []
|
||||
{
|
||||
new AddPropertyTransform<CommonCompilerOptions>("AssemblyOriginatorKeyFile",
|
||||
compilerOptions => compilerOptions.KeyFile,
|
||||
compilerOptions => !string.IsNullOrEmpty(compilerOptions.KeyFile)),
|
||||
new AddPropertyTransform<CommonCompilerOptions>("SignAssembly",
|
||||
"true",
|
||||
compilerOptions => !string.IsNullOrEmpty(compilerOptions.KeyFile))
|
||||
};
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> DefineTransform => new AddPropertyTransform<CommonCompilerOptions>(
|
||||
"DefineConstants",
|
||||
compilerOptions => string.Join(";", compilerOptions.Defines),
|
||||
compilerOptions => compilerOptions.Defines != null && compilerOptions.Defines.Any());
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> NoWarnTransform => new AddPropertyTransform<CommonCompilerOptions>(
|
||||
"NoWarn",
|
||||
compilerOptions => string.Join(";", compilerOptions.SuppressWarnings),
|
||||
compilerOptions => compilerOptions.SuppressWarnings != null && compilerOptions.SuppressWarnings.Any());
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> PreserveCompilationContextTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("PreserveCompilationContext",
|
||||
compilerOptions => compilerOptions.PreserveCompilationContext.ToString().ToLower(),
|
||||
compilerOptions => compilerOptions.PreserveCompilationContext != null && compilerOptions.PreserveCompilationContext.Value);
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> WarningsAsErrorsTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("WarningsAsErrors",
|
||||
compilerOptions => compilerOptions.WarningsAsErrors.ToString().ToLower(),
|
||||
compilerOptions => compilerOptions.WarningsAsErrors != null && compilerOptions.WarningsAsErrors.Value);
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> AllowUnsafeTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("AllowUnsafeBlocks",
|
||||
compilerOptions => compilerOptions.AllowUnsafe.ToString().ToLower(),
|
||||
compilerOptions => compilerOptions.AllowUnsafe != null && compilerOptions.AllowUnsafe.Value);
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> OptimizeTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("Optimize",
|
||||
compilerOptions => compilerOptions.Optimize.ToString().ToLower(),
|
||||
compilerOptions => compilerOptions.Optimize != null && compilerOptions.Optimize.Value);
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> PlatformTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("PlatformTarget",
|
||||
compilerOptions => compilerOptions.Platform,
|
||||
compilerOptions => !string.IsNullOrEmpty(compilerOptions.Platform));
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> LanguageVersionTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("LangVersion",
|
||||
compilerOptions => compilerOptions.LanguageVersion,
|
||||
compilerOptions => !string.IsNullOrEmpty(compilerOptions.LanguageVersion));
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> DelaySignTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("DelaySign",
|
||||
compilerOptions => compilerOptions.DelaySign.ToString().ToLower(),
|
||||
compilerOptions => compilerOptions.DelaySign != null && compilerOptions.DelaySign.Value);
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> PublicSignTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("PublicSign",
|
||||
compilerOptions => compilerOptions.PublicSign.ToString().ToLower(),
|
||||
compilerOptions => compilerOptions.PublicSign != null && compilerOptions.PublicSign.Value);
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> DebugTypeTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("DebugType",
|
||||
compilerOptions => compilerOptions.DebugType,
|
||||
compilerOptions => !string.IsNullOrEmpty(compilerOptions.DebugType));
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> XmlDocTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("GenerateDocumentationFile",
|
||||
compilerOptions => compilerOptions.GenerateXmlDocumentation.ToString().ToLower(),
|
||||
compilerOptions => compilerOptions.GenerateXmlDocumentation != null && compilerOptions.GenerateXmlDocumentation.Value);
|
||||
|
||||
// TODO: https://github.com/dotnet/sdk/issues/67
|
||||
private AddPropertyTransform<CommonCompilerOptions> XmlDocTransformFilePath =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("DocumentationFile",
|
||||
@"$(OutputPath)\$(AssemblyName).xml",
|
||||
compilerOptions => compilerOptions.GenerateXmlDocumentation != null && compilerOptions.GenerateXmlDocumentation.Value);
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> OutputNameTransform =>
|
||||
new AddPropertyTransform<CommonCompilerOptions>("AssemblyName",
|
||||
compilerOptions => compilerOptions.OutputName,
|
||||
compilerOptions => !string.IsNullOrEmpty(compilerOptions.OutputName));
|
||||
|
||||
private IncludeContextTransform CompileFilesTransform =>
|
||||
new IncludeContextTransform("Compile", transformMappings: false);
|
||||
|
||||
private IncludeContextTransform EmbedFilesTransform =>
|
||||
new IncludeContextTransform("EmbeddedResource", transformMappings: false);
|
||||
|
||||
private IncludeContextTransform CopyToOutputFilesTransform =>
|
||||
new IncludeContextTransform("Content", transformMappings: true)
|
||||
.WithMetadata("CopyToOutputDirectory", "PreserveNewest");
|
||||
|
||||
private Func<CommonCompilerOptions, string, IEnumerable<ProjectItemElement>> CompileFilesTransformExecute =>
|
||||
(compilerOptions, projectDirectory) =>
|
||||
CompileFilesTransform.Transform(GetCompileIncludeContext(compilerOptions, projectDirectory));
|
||||
|
||||
private Func<CommonCompilerOptions, string, IEnumerable<ProjectItemElement>> EmbedFilesTransformExecute =>
|
||||
(compilerOptions, projectDirectory) =>
|
||||
EmbedFilesTransform.Transform(GetEmbedIncludeContext(compilerOptions, projectDirectory));
|
||||
|
||||
private Func<CommonCompilerOptions, string, IEnumerable<ProjectItemElement>> CopyToOutputFilesTransformExecute =>
|
||||
(compilerOptions, projectDirectory) =>
|
||||
CopyToOutputFilesTransform.Transform(GetCopyToOutputIncludeContext(compilerOptions, projectDirectory));
|
||||
|
||||
private readonly string _configuration;
|
||||
private readonly NuGetFramework _framework;
|
||||
private readonly ProjectPropertyGroupElement _configurationPropertyGroup;
|
||||
private readonly ProjectItemGroupElement _configurationItemGroup;
|
||||
|
||||
private List<AddPropertyTransform<CommonCompilerOptions>> _propertyTransforms;
|
||||
private List<Func<CommonCompilerOptions, string, IEnumerable<ProjectItemElement>>> _includeContextTransformExecutes;
|
||||
|
||||
private readonly ITransformApplicator _transformApplicator;
|
||||
|
||||
public MigrateBuildOptionsRule(ITransformApplicator transformApplicator = null)
|
||||
{
|
||||
_transformApplicator = transformApplicator ?? new TransformApplicator();
|
||||
ConstructTransformLists();
|
||||
}
|
||||
|
||||
public MigrateBuildOptionsRule(
|
||||
string configuration,
|
||||
NuGetFramework framework,
|
||||
ProjectPropertyGroupElement configurationPropertyGroup,
|
||||
ProjectItemGroupElement configurationItemGroup,
|
||||
ITransformApplicator transformApplicator = null)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_framework = framework;
|
||||
_configurationPropertyGroup = configurationPropertyGroup;
|
||||
_configurationItemGroup = configurationItemGroup;
|
||||
_transformApplicator = transformApplicator ?? new TransformApplicator();
|
||||
|
||||
ConstructTransformLists();
|
||||
}
|
||||
|
||||
private void ConstructTransformLists()
|
||||
{
|
||||
_propertyTransforms = new List<AddPropertyTransform<CommonCompilerOptions>>()
|
||||
{
|
||||
DefineTransform,
|
||||
NoWarnTransform,
|
||||
WarningsAsErrorsTransform,
|
||||
AllowUnsafeTransform,
|
||||
OptimizeTransform,
|
||||
PlatformTransform,
|
||||
LanguageVersionTransform,
|
||||
DelaySignTransform,
|
||||
PublicSignTransform,
|
||||
DebugTypeTransform,
|
||||
OutputNameTransform,
|
||||
XmlDocTransform,
|
||||
XmlDocTransformFilePath,
|
||||
PreserveCompilationContextTransform
|
||||
};
|
||||
|
||||
_propertyTransforms.AddRange(EmitEntryPointTransforms);
|
||||
_propertyTransforms.AddRange(KeyFileTransforms);
|
||||
|
||||
_includeContextTransformExecutes = new List<Func<CommonCompilerOptions, string, IEnumerable<ProjectItemElement>>>()
|
||||
{
|
||||
CompileFilesTransformExecute,
|
||||
EmbedFilesTransformExecute,
|
||||
CopyToOutputFilesTransformExecute
|
||||
};
|
||||
}
|
||||
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var csproj = migrationRuleInputs.OutputMSBuildProject;
|
||||
var projectContext = migrationRuleInputs.DefaultProjectContext;
|
||||
|
||||
var propertyGroup = _configurationPropertyGroup ?? migrationRuleInputs.CommonPropertyGroup;
|
||||
var itemGroup = _configurationItemGroup ?? migrationRuleInputs.CommonItemGroup;
|
||||
|
||||
var compilerOptions = projectContext.ProjectFile.GetCompilerOptions(projectContext.TargetFramework, null);
|
||||
var configurationCompilerOptions =
|
||||
projectContext.ProjectFile.GetCompilerOptions(_framework, _configuration);
|
||||
|
||||
// If we're in a configuration, we need to be careful not to overwrite values from BuildOptions
|
||||
// without a configuration
|
||||
if (_configuration == null)
|
||||
{
|
||||
CleanExistingProperties(csproj);
|
||||
|
||||
PerformPropertyAndItemMappings(
|
||||
compilerOptions,
|
||||
propertyGroup,
|
||||
itemGroup,
|
||||
_transformApplicator,
|
||||
migrationSettings.ProjectDirectory);
|
||||
}
|
||||
else
|
||||
{
|
||||
PerformConfigurationPropertyAndItemMappings(
|
||||
compilerOptions,
|
||||
configurationCompilerOptions,
|
||||
propertyGroup,
|
||||
itemGroup,
|
||||
_transformApplicator,
|
||||
migrationSettings.ProjectDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformConfigurationPropertyAndItemMappings(
|
||||
CommonCompilerOptions compilerOptions,
|
||||
CommonCompilerOptions configurationCompilerOptions,
|
||||
ProjectPropertyGroupElement propertyGroup,
|
||||
ProjectItemGroupElement itemGroup,
|
||||
ITransformApplicator transformApplicator,
|
||||
string projectDirectory)
|
||||
{
|
||||
foreach (var transform in _propertyTransforms)
|
||||
{
|
||||
var nonConfigurationOutput = transform.Transform(compilerOptions);
|
||||
var configurationOutput = transform.Transform(configurationCompilerOptions);
|
||||
|
||||
if (!PropertiesAreEqual(nonConfigurationOutput, configurationOutput))
|
||||
{
|
||||
transformApplicator.Execute(configurationOutput, propertyGroup);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var includeContextTransformExecute in _includeContextTransformExecutes)
|
||||
{
|
||||
var nonConfigurationOutput = includeContextTransformExecute(compilerOptions, projectDirectory);
|
||||
var configurationOutput = includeContextTransformExecute(configurationCompilerOptions, projectDirectory).ToArray();
|
||||
|
||||
if (configurationOutput != null && nonConfigurationOutput != null)
|
||||
{
|
||||
// TODO: HACK: this is leaky, see top comments, the throw at least covers the scenario
|
||||
ThrowIfConfigurationHasAdditionalExcludes(configurationOutput, nonConfigurationOutput);
|
||||
RemoveCommonIncludes(configurationOutput, nonConfigurationOutput);
|
||||
configurationOutput = configurationOutput.Where(i => i != null && !string.IsNullOrEmpty(i.Include)).ToArray();
|
||||
}
|
||||
|
||||
// Don't merge with existing items when doing a configuration
|
||||
transformApplicator.Execute(configurationOutput, itemGroup, mergeExisting: false);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowIfConfigurationHasAdditionalExcludes(IEnumerable<ProjectItemElement> configurationOutput, IEnumerable<ProjectItemElement> nonConfigurationOutput)
|
||||
{
|
||||
foreach (var item1 in configurationOutput)
|
||||
{
|
||||
if (item1 == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var item2Excludes = new HashSet<string>();
|
||||
foreach (var item2 in nonConfigurationOutput)
|
||||
{
|
||||
if (item2 != null)
|
||||
{
|
||||
item2Excludes.UnionWith(item2.Excludes());
|
||||
}
|
||||
}
|
||||
var configurationHasAdditionalExclude =
|
||||
item1.Excludes().Any(exclude => item2Excludes.All(item2Exclude => item2Exclude != exclude));
|
||||
|
||||
if (configurationHasAdditionalExclude)
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine(item1.Exclude);
|
||||
MigrationTrace.Instance.WriteLine(item2Excludes.ToString());
|
||||
|
||||
MigrationErrorCodes.MIGRATE20012("Unable to migrate projects with excluded files in configurations.")
|
||||
.Throw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveCommonIncludes(IEnumerable<ProjectItemElement> itemsToRemoveFrom,
|
||||
IEnumerable<ProjectItemElement> otherItems)
|
||||
{
|
||||
foreach (var item1 in itemsToRemoveFrom)
|
||||
{
|
||||
if (item1 == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (
|
||||
var item2 in
|
||||
otherItems.Where(
|
||||
i => i != null && string.Equals(i.ItemType, item1.ItemType, StringComparison.Ordinal)))
|
||||
{
|
||||
item1.Include = string.Join(";", item1.Includes().Except(item2.Includes()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool PropertiesAreEqual(ProjectPropertyElement nonConfigurationOutput, ProjectPropertyElement configurationOutput)
|
||||
{
|
||||
if (configurationOutput != null && nonConfigurationOutput != null)
|
||||
{
|
||||
return string.Equals(nonConfigurationOutput.Value, configurationOutput.Value, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
return configurationOutput == nonConfigurationOutput;
|
||||
}
|
||||
|
||||
private void PerformPropertyAndItemMappings(
|
||||
CommonCompilerOptions compilerOptions,
|
||||
ProjectPropertyGroupElement propertyGroup,
|
||||
ProjectItemGroupElement itemGroup,
|
||||
ITransformApplicator transformApplicator,
|
||||
string projectDirectory)
|
||||
{
|
||||
foreach (var transform in _propertyTransforms)
|
||||
{
|
||||
transformApplicator.Execute(transform.Transform(compilerOptions), propertyGroup);
|
||||
}
|
||||
|
||||
foreach (var includeContextTransformExecute in _includeContextTransformExecutes)
|
||||
{
|
||||
transformApplicator.Execute(
|
||||
includeContextTransformExecute(compilerOptions, projectDirectory),
|
||||
itemGroup,
|
||||
mergeExisting: true);
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanExistingProperties(ProjectRootElement csproj)
|
||||
{
|
||||
var existingPropertiesToRemove = new [] {"OutputType", "TargetExt"};
|
||||
|
||||
foreach (var propertyName in existingPropertiesToRemove)
|
||||
{
|
||||
var properties = csproj.Properties.Where(p => p.Name == propertyName);
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
property.Parent.RemoveChild(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IncludeContext GetCompileIncludeContext(CommonCompilerOptions compilerOptions, string projectDirectory)
|
||||
{
|
||||
// Defaults from src/Microsoft.DotNet.ProjectModel/ProjectReader.cs #L596
|
||||
return compilerOptions.CompileInclude ??
|
||||
new IncludeContext(
|
||||
projectDirectory,
|
||||
"compile",
|
||||
new JObject(),
|
||||
ProjectFilesCollection.DefaultCompileBuiltInPatterns,
|
||||
ProjectFilesCollection.DefaultBuiltInExcludePatterns);
|
||||
}
|
||||
|
||||
private IncludeContext GetEmbedIncludeContext(CommonCompilerOptions compilerOptions, string projectDirectory)
|
||||
{
|
||||
// Defaults from src/Microsoft.DotNet.ProjectModel/ProjectReader.cs #L602
|
||||
return compilerOptions.EmbedInclude ??
|
||||
new IncludeContext(
|
||||
projectDirectory,
|
||||
"embed",
|
||||
new JObject(),
|
||||
ProjectFilesCollection.DefaultResourcesBuiltInPatterns,
|
||||
ProjectFilesCollection.DefaultBuiltInExcludePatterns);
|
||||
}
|
||||
|
||||
private IncludeContext GetCopyToOutputIncludeContext(CommonCompilerOptions compilerOptions, string projectDirectory)
|
||||
{
|
||||
// Defaults from src/Microsoft.DotNet.ProjectModel/ProjectReader.cs #608
|
||||
return compilerOptions.CopyToOutputInclude ??
|
||||
new IncludeContext(
|
||||
projectDirectory,
|
||||
"copyToOutput",
|
||||
new JObject(),
|
||||
null,
|
||||
ProjectFilesCollection.DefaultPublishExcludePatterns);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// 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.Build.Construction;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
public class MigrateConfigurationsRule : IMigrationRule
|
||||
{
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var projectContext = migrationRuleInputs.DefaultProjectContext;
|
||||
var configurations = projectContext.ProjectFile.GetConfigurations().ToList();
|
||||
|
||||
var frameworks = new List<NuGetFramework>();
|
||||
frameworks.Add(null);
|
||||
frameworks.AddRange(projectContext.ProjectFile.GetTargetFrameworks().Select(t => t.FrameworkName));
|
||||
|
||||
if (!configurations.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var frameworkConfigurationCombinations = frameworks.SelectMany(f => configurations, Tuple.Create);
|
||||
|
||||
foreach (var entry in frameworkConfigurationCombinations)
|
||||
{
|
||||
var framework = entry.Item1;
|
||||
var configuration = entry.Item2;
|
||||
|
||||
MigrateConfiguration(configuration, framework, migrationSettings, migrationRuleInputs);
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateConfiguration(
|
||||
string configuration,
|
||||
NuGetFramework framework,
|
||||
MigrationSettings migrationSettings,
|
||||
MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var csproj = migrationRuleInputs.OutputMSBuildProject;
|
||||
|
||||
var propertyGroup = CreatePropertyGroupAtEndOfProject(csproj);
|
||||
var itemGroup = CreateItemGroupAtEndOfProject(csproj);
|
||||
|
||||
var configurationCondition = $" '$(Configuration)' == '{configuration}' ";
|
||||
if (framework != null)
|
||||
{
|
||||
configurationCondition +=
|
||||
$" and '$(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion)' == '{framework.DotNetFrameworkName}' ";
|
||||
}
|
||||
propertyGroup.Condition = configurationCondition;
|
||||
itemGroup.Condition = configurationCondition;
|
||||
|
||||
new MigrateBuildOptionsRule(configuration, framework, propertyGroup, itemGroup)
|
||||
.Apply(migrationSettings, migrationRuleInputs);
|
||||
|
||||
propertyGroup.RemoveIfEmpty();
|
||||
itemGroup.RemoveIfEmpty();
|
||||
}
|
||||
|
||||
private ProjectPropertyGroupElement CreatePropertyGroupAtEndOfProject(ProjectRootElement csproj)
|
||||
{
|
||||
var propertyGroup = csproj.CreatePropertyGroupElement();
|
||||
csproj.InsertBeforeChild(propertyGroup, csproj.LastChild);
|
||||
return propertyGroup;
|
||||
}
|
||||
|
||||
private ProjectItemGroupElement CreateItemGroupAtEndOfProject(ProjectRootElement csproj)
|
||||
{
|
||||
var itemGroup = csproj.CreateItemGroupElement();
|
||||
csproj.InsertBeforeChild(itemGroup, csproj.LastChild);
|
||||
return itemGroup;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Compilation;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
public class MigrateProjectDependenciesRule : IMigrationRule
|
||||
{
|
||||
private readonly ITransformApplicator _transformApplicator;
|
||||
private string _projectDirectory;
|
||||
|
||||
public MigrateProjectDependenciesRule(ITransformApplicator transformApplicator = null)
|
||||
{
|
||||
_transformApplicator = transformApplicator ?? new TransformApplicator();
|
||||
}
|
||||
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
_projectDirectory = migrationSettings.ProjectDirectory;
|
||||
|
||||
var csproj = migrationRuleInputs.OutputMSBuildProject;
|
||||
var projectContext = migrationRuleInputs.DefaultProjectContext;
|
||||
var projectExports = projectContext.CreateExporter("_").GetDependencies(LibraryType.Project);
|
||||
|
||||
var projectDependencyTransformResults =
|
||||
projectExports.Select(projectExport => ProjectDependencyTransform.Transform(projectExport));
|
||||
|
||||
if (projectDependencyTransformResults.Any())
|
||||
{
|
||||
AddPropertyTransformsToCommonPropertyGroup(migrationRuleInputs.CommonPropertyGroup);
|
||||
AddProjectDependenciesToNewItemGroup(csproj.AddItemGroup(), projectDependencyTransformResults);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddProjectDependenciesToNewItemGroup(ProjectItemGroupElement itemGroup, IEnumerable<ProjectItemElement> projectDependencyTransformResults)
|
||||
{
|
||||
foreach (var projectDependencyTransformResult in projectDependencyTransformResults)
|
||||
{
|
||||
_transformApplicator.Execute(projectDependencyTransformResult, itemGroup);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddPropertyTransformsToCommonPropertyGroup(ProjectPropertyGroupElement commonPropertyGroup)
|
||||
{
|
||||
var propertyTransformResults = new[]
|
||||
{
|
||||
AutoUnifyTransform.Transform(true),
|
||||
DesignTimeAutoUnifyTransform.Transform(true)
|
||||
};
|
||||
|
||||
foreach (var propertyTransformResult in propertyTransformResults)
|
||||
{
|
||||
_transformApplicator.Execute(propertyTransformResult, commonPropertyGroup);
|
||||
}
|
||||
}
|
||||
|
||||
private AddPropertyTransform<bool> AutoUnifyTransform => new AddPropertyTransform<bool>(
|
||||
"AutoUnify",
|
||||
"true",
|
||||
b => true);
|
||||
|
||||
private AddPropertyTransform<bool> DesignTimeAutoUnifyTransform => new AddPropertyTransform<bool>(
|
||||
"DesignTimeAutoUnify",
|
||||
"true",
|
||||
b => true);
|
||||
|
||||
private AddItemTransform<LibraryExport> ProjectDependencyTransform => new AddItemTransform<LibraryExport>(
|
||||
"ProjectReference",
|
||||
export =>
|
||||
{
|
||||
if (!export.Library.Resolved)
|
||||
{
|
||||
MigrationErrorCodes.MIGRATE1014(
|
||||
$"Unresolved project dependency ({export.Library.Identity.Name})").Throw();
|
||||
}
|
||||
|
||||
var projectFile = ((ProjectDescription)export.Library).Project.ProjectFilePath;
|
||||
var projectDir = Path.GetDirectoryName(projectFile);
|
||||
var migratedProjectFileName = Path.GetFileName(projectDir) + ".csproj";
|
||||
var relativeProjectDir = PathUtility.GetRelativePath(_projectDirectory + "/", projectDir);
|
||||
|
||||
return Path.Combine(relativeProjectDir, migratedProjectFileName);
|
||||
},
|
||||
export => "",
|
||||
export => true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// 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.ProjectJsonMigration.Transforms;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
public class MigratePublishOptionsRule : IMigrationRule
|
||||
{
|
||||
private readonly ITransformApplicator _transformApplicator;
|
||||
|
||||
public MigratePublishOptionsRule(ITransformApplicator transformApplicator = null)
|
||||
{
|
||||
_transformApplicator = transformApplicator ?? new TransformApplicator();
|
||||
}
|
||||
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var csproj = migrationRuleInputs.OutputMSBuildProject;
|
||||
var projectContext = migrationRuleInputs.DefaultProjectContext;
|
||||
|
||||
var transformResult = CopyToOutputFilesTransform.Transform(projectContext.ProjectFile.PublishOptions);
|
||||
|
||||
if (transformResult != null && transformResult.Any())
|
||||
{
|
||||
var itemGroup = migrationRuleInputs.CommonItemGroup;
|
||||
_transformApplicator.Execute(
|
||||
transformResult,
|
||||
itemGroup,
|
||||
mergeExisting: true);
|
||||
}
|
||||
}
|
||||
|
||||
private IncludeContextTransform CopyToOutputFilesTransform =>
|
||||
new IncludeContextTransform("Content", transformMappings: true)
|
||||
.WithMetadata("CopyToPublishDirectory", "PreserveNewest");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
// 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.ProjectJsonMigration.Transforms;
|
||||
using Project = Microsoft.DotNet.ProjectModel.Project;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
public class MigrateRootOptionsRule : IMigrationRule
|
||||
{
|
||||
private readonly ITransformApplicator _transformApplicator;
|
||||
private readonly AddPropertyTransform<Project>[] _transforms;
|
||||
|
||||
public MigrateRootOptionsRule(ITransformApplicator transformApplicator = null)
|
||||
{
|
||||
_transformApplicator = transformApplicator ?? new TransformApplicator();
|
||||
|
||||
_transforms = new[]
|
||||
{
|
||||
DescriptionTransform,
|
||||
CopyrightTransform,
|
||||
TitleTransform,
|
||||
LanguageTransform,
|
||||
VersionTransform
|
||||
};
|
||||
}
|
||||
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var projectContext = migrationRuleInputs.DefaultProjectContext;
|
||||
|
||||
var transformResults = _transforms.Select(t => t.Transform(projectContext.ProjectFile)).ToArray();
|
||||
if (transformResults.Any())
|
||||
{
|
||||
var propertyGroup = migrationRuleInputs.CommonPropertyGroup;
|
||||
|
||||
foreach (var transformResult in transformResults)
|
||||
{
|
||||
_transformApplicator.Execute(transformResult, propertyGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AddPropertyTransform<Project> DescriptionTransform => new AddPropertyTransform<Project>("Description",
|
||||
project => project.Description,
|
||||
project => !string.IsNullOrEmpty(project.Description));
|
||||
|
||||
private AddPropertyTransform<Project> CopyrightTransform => new AddPropertyTransform<Project>("Copyright",
|
||||
project => project.Copyright,
|
||||
project => !string.IsNullOrEmpty(project.Copyright));
|
||||
|
||||
private AddPropertyTransform<Project> TitleTransform => new AddPropertyTransform<Project>("AssemblyTitle",
|
||||
project => project.Title,
|
||||
project => !string.IsNullOrEmpty(project.Title));
|
||||
|
||||
private AddPropertyTransform<Project> LanguageTransform => new AddPropertyTransform<Project>("NeutralLanguage",
|
||||
project => project.Language,
|
||||
project => !string.IsNullOrEmpty(project.Language));
|
||||
|
||||
private AddPropertyTransform<Project> VersionTransform => new AddPropertyTransform<Project>("VersionPrefix",
|
||||
project => project.Version.ToString(), p => true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// 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.IO;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
public class MigrateRuntimeOptionsRule : IMigrationRule
|
||||
{
|
||||
private static readonly string s_runtimeOptionsFileName = "runtimeconfig.template.json";
|
||||
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var projectContext = migrationRuleInputs.DefaultProjectContext;
|
||||
var raw = projectContext.ProjectFile.RawRuntimeOptions;
|
||||
var outputRuntimeOptionsFile = Path.Combine(migrationSettings.OutputDirectory, s_runtimeOptionsFileName);
|
||||
|
||||
if (!string.IsNullOrEmpty(raw))
|
||||
{
|
||||
if (File.Exists(outputRuntimeOptionsFile))
|
||||
{
|
||||
MigrationErrorCodes.MIGRATE1015(
|
||||
$"{outputRuntimeOptionsFile} already exists. Has migration already been run?").Throw();
|
||||
}
|
||||
|
||||
File.WriteAllText(outputRuntimeOptionsFile, raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Cli.Utils.CommandParsing;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
public class MigrateScriptsRule : IMigrationRule
|
||||
{
|
||||
private static readonly string s_unixScriptExtension = ".sh";
|
||||
private static readonly string s_windowsScriptExtension = ".cmd";
|
||||
|
||||
private readonly ITransformApplicator _transformApplicator;
|
||||
|
||||
public MigrateScriptsRule(ITransformApplicator transformApplicator = null)
|
||||
{
|
||||
_transformApplicator = transformApplicator ?? new TransformApplicator();
|
||||
}
|
||||
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var csproj = migrationRuleInputs.OutputMSBuildProject;
|
||||
var projectContext = migrationRuleInputs.DefaultProjectContext;
|
||||
var scripts = projectContext.ProjectFile.Scripts;
|
||||
|
||||
foreach (var scriptSet in scripts)
|
||||
{
|
||||
MigrateScriptSet(csproj, migrationRuleInputs.CommonPropertyGroup, scriptSet.Value, scriptSet.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public ProjectTargetElement MigrateScriptSet(ProjectRootElement csproj,
|
||||
ProjectPropertyGroupElement propertyGroup,
|
||||
IEnumerable<string> scriptCommands,
|
||||
string scriptSetName)
|
||||
{
|
||||
var target = CreateTarget(csproj, scriptSetName);
|
||||
var count = 0;
|
||||
foreach (var scriptCommand in scriptCommands)
|
||||
{
|
||||
var scriptExtensionPropertyName = AddScriptExtension(propertyGroup, scriptCommand, $"{scriptSetName}_{++count}");
|
||||
AddExec(target, FormatScriptCommand(scriptCommand, scriptExtensionPropertyName));
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
private string AddScriptExtension(ProjectPropertyGroupElement propertyGroup, string scriptCommandline, string scriptId)
|
||||
{
|
||||
var scriptArguments = CommandGrammar.Process(
|
||||
scriptCommandline,
|
||||
(s) => null,
|
||||
preserveSurroundingQuotes: false);
|
||||
|
||||
scriptArguments = scriptArguments.Where(argument => !string.IsNullOrEmpty(argument)).ToArray();
|
||||
var scriptCommand = scriptArguments.First();
|
||||
var propertyName = $"MigratedScriptExtension_{scriptId}";
|
||||
|
||||
var windowsScriptExtensionProperty = propertyGroup.AddProperty(propertyName,
|
||||
s_windowsScriptExtension);
|
||||
var unixScriptExtensionProperty = propertyGroup.AddProperty(propertyName,
|
||||
s_unixScriptExtension);
|
||||
|
||||
windowsScriptExtensionProperty.Condition =
|
||||
$" '$(OS)' == 'Windows_NT' and Exists('{scriptCommand}{s_windowsScriptExtension}') ";
|
||||
unixScriptExtensionProperty.Condition =
|
||||
$" '$(OS)' != 'Windows_NT' and Exists('{scriptCommand}{s_unixScriptExtension}') ";
|
||||
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
internal string FormatScriptCommand(string scriptCommandline, string scriptExtensionPropertyName)
|
||||
{
|
||||
var command = AddScriptExtensionPropertyToCommandLine(scriptCommandline, scriptExtensionPropertyName);
|
||||
return ReplaceScriptVariables(command);
|
||||
}
|
||||
|
||||
internal string AddScriptExtensionPropertyToCommandLine(string scriptCommandline,
|
||||
string scriptExtensionPropertyName)
|
||||
{
|
||||
var scriptArguments = CommandGrammar.Process(
|
||||
scriptCommandline,
|
||||
(s) => null,
|
||||
preserveSurroundingQuotes: true);
|
||||
|
||||
scriptArguments = scriptArguments.Where(argument => !string.IsNullOrEmpty(argument)).ToArray();
|
||||
|
||||
var scriptCommand = scriptArguments.First();
|
||||
var trimmedCommand = scriptCommand.Trim('\"').Trim('\'');
|
||||
|
||||
// Path.IsPathRooted only looks at paths conforming to the current os,
|
||||
// we need to account for all things
|
||||
if (!IsPathRootedForAnyOS(trimmedCommand))
|
||||
{
|
||||
scriptCommand = @".\" + scriptCommand;
|
||||
}
|
||||
|
||||
if (scriptCommand.EndsWith("\"") || scriptCommand.EndsWith("'"))
|
||||
{
|
||||
var endChar = scriptCommand.Last();
|
||||
scriptCommand = $"{scriptCommand.TrimEnd(endChar)}$({scriptExtensionPropertyName}){endChar}";
|
||||
}
|
||||
else
|
||||
{
|
||||
scriptCommand += $"$({scriptExtensionPropertyName})";
|
||||
}
|
||||
|
||||
var command = string.Join(" ", new[] {scriptCommand}.Concat(scriptArguments.Skip(1)));
|
||||
return command;
|
||||
}
|
||||
|
||||
internal string ReplaceScriptVariables(string command)
|
||||
{
|
||||
foreach (var scriptVariableEntry in ScriptVariableToMSBuildMap)
|
||||
{
|
||||
var scriptVariableName = scriptVariableEntry.Key;
|
||||
var msbuildMapping = scriptVariableEntry.Value;
|
||||
|
||||
if (command.Contains($"%{scriptVariableName}%"))
|
||||
{
|
||||
if (msbuildMapping == null)
|
||||
{
|
||||
MigrationErrorCodes.MIGRATE1016(
|
||||
$"{scriptVariableName} is currently an unsupported script variable for project migration")
|
||||
.Throw();
|
||||
}
|
||||
|
||||
command = command.Replace($"%{scriptVariableName}%", msbuildMapping);
|
||||
}
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private bool IsPathRootedForAnyOS(string path)
|
||||
{
|
||||
return path.StartsWith("/") || path.Substring(1).StartsWith(":\\");
|
||||
}
|
||||
|
||||
private ProjectTargetElement CreateTarget(ProjectRootElement csproj, string scriptSetName)
|
||||
{
|
||||
var targetName = $"{scriptSetName[0].ToString().ToUpper()}{string.Concat(scriptSetName.Skip(1))}Script";
|
||||
var targetHookInfo = ScriptSetToMSBuildHookTargetMap[scriptSetName];
|
||||
|
||||
var target = csproj.CreateTargetElement(targetName);
|
||||
csproj.InsertBeforeChild(target, csproj.LastChild);
|
||||
if (targetHookInfo.IsRunBefore)
|
||||
{
|
||||
target.BeforeTargets = targetHookInfo.TargetName;
|
||||
}
|
||||
else
|
||||
{
|
||||
target.AfterTargets = targetHookInfo.TargetName;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
private void AddExec(ProjectTargetElement target, string command)
|
||||
{
|
||||
var task = target.AddTask("Exec");
|
||||
task.SetParameter("Command", command);
|
||||
}
|
||||
|
||||
// ProjectJson Script Set Name to
|
||||
private static Dictionary<string, TargetHookInfo> ScriptSetToMSBuildHookTargetMap => new Dictionary<string, TargetHookInfo>()
|
||||
{
|
||||
{ "precompile", new TargetHookInfo(true, "Build") },
|
||||
{ "postcompile", new TargetHookInfo(false, "Build") },
|
||||
{ "prepublish", new TargetHookInfo(true, "Publish") },
|
||||
{ "postpublish", new TargetHookInfo(false, "Publish") }
|
||||
};
|
||||
|
||||
private static Dictionary<string, string> ScriptVariableToMSBuildMap => new Dictionary<string, string>()
|
||||
{
|
||||
{ "compile:TargetFramework", null }, // TODO: Need Short framework name in CSProj
|
||||
{ "compile:ResponseFile", null }, // Not migrated
|
||||
{ "compile:CompilerExitCode", null }, // Not migrated
|
||||
{ "compile:RuntimeOutputDir", null }, // Not migrated
|
||||
{ "compile:RuntimeIdentifier", null },// Not Migrated
|
||||
|
||||
{ "publish:TargetFramework", null }, // TODO: Need Short framework name in CSProj
|
||||
{ "publish:Runtime", "$(RuntimeIdentifier)" },
|
||||
|
||||
{ "compile:FullTargetFramework", "$(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion)" },
|
||||
{ "compile:Configuration", "$(Configuration)" },
|
||||
{ "compile:OutputFile", "$(TargetPath)" },
|
||||
{ "compile:OutputDir", "$(TargetDir)" },
|
||||
|
||||
{ "publish:ProjectPath", "$(MSBuildThisFileDirectory)" },
|
||||
{ "publish:Configuration", "$(Configuration)" },
|
||||
{ "publish:OutputPath", "$(TargetDir)" },
|
||||
{ "publish:FullTargetFramework", "$(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion)" },
|
||||
|
||||
{ "project:Directory", "$(MSBuildProjectDirectory)" },
|
||||
{ "project:Name", "$(AssemblyName)" },
|
||||
{ "project:Version", "$(Version)" }
|
||||
};
|
||||
|
||||
private class TargetHookInfo
|
||||
{
|
||||
public bool IsRunBefore { get; }
|
||||
public string TargetName { get; }
|
||||
|
||||
public TargetHookInfo(bool isRunBefore, string targetName)
|
||||
{
|
||||
IsRunBefore = isRunBefore;
|
||||
TargetName = targetName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
// 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.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
// TODO: Support Multi-TFM
|
||||
public class MigrateTFMRule : IMigrationRule
|
||||
{
|
||||
private readonly ITransformApplicator _transformApplicator;
|
||||
private readonly AddPropertyTransform<NuGetFramework>[] _transforms;
|
||||
|
||||
public MigrateTFMRule(ITransformApplicator transformApplicator = null)
|
||||
{
|
||||
_transformApplicator = transformApplicator ?? new TransformApplicator();
|
||||
|
||||
_transforms = new AddPropertyTransform<NuGetFramework>[]
|
||||
{
|
||||
OutputPathTransform,
|
||||
FrameworkIdentifierTransform,
|
||||
FrameworkVersionTransform
|
||||
};
|
||||
}
|
||||
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var csproj = migrationRuleInputs.OutputMSBuildProject;
|
||||
var propertyGroup = migrationRuleInputs.CommonPropertyGroup;
|
||||
|
||||
CleanExistingProperties(csproj);
|
||||
|
||||
foreach (var transform in _transforms)
|
||||
{
|
||||
_transformApplicator.Execute(
|
||||
transform.Transform(migrationRuleInputs.DefaultProjectContext.TargetFramework),
|
||||
propertyGroup);
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanExistingProperties(ProjectRootElement csproj)
|
||||
{
|
||||
var existingPropertiesToRemove = new string[] { "TargetFrameworkIdentifier", "TargetFrameworkVersion" };
|
||||
var properties = csproj.Properties.Where(p => existingPropertiesToRemove.Contains(p.Name));
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
property.Parent.RemoveChild(property);
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from private NuGet.Frameworks method
|
||||
// https://github.com/NuGet/NuGet.Client/blob/33b8f85a94b01f805f1e955f9b68992b297fad6e/src/NuGet.Core/NuGet.Frameworks/NuGetFramework.cs#L234
|
||||
private static string GetDisplayVersion(Version version)
|
||||
{
|
||||
var sb = new StringBuilder(String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor));
|
||||
|
||||
if (version.Build > 0
|
||||
|| version.Revision > 0)
|
||||
{
|
||||
sb.AppendFormat(CultureInfo.InvariantCulture, ".{0}", version.Build);
|
||||
|
||||
if (version.Revision > 0)
|
||||
{
|
||||
sb.AppendFormat(CultureInfo.InvariantCulture, ".{0}", version.Revision);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
// TODO: When we have this inferred in the sdk targets, we won't need this
|
||||
private AddPropertyTransform<NuGetFramework> OutputPathTransform =>
|
||||
new AddPropertyTransform<NuGetFramework>("OutputPath",
|
||||
f => $"bin/$(Configuration)/{f.GetShortFolderName()}",
|
||||
f => true);
|
||||
|
||||
private AddPropertyTransform<NuGetFramework> FrameworkIdentifierTransform =>
|
||||
new AddPropertyTransform<NuGetFramework>("TargetFrameworkIdentifier",
|
||||
f => f.Framework,
|
||||
f => true);
|
||||
|
||||
private AddPropertyTransform<NuGetFramework> FrameworkVersionTransform =>
|
||||
new AddPropertyTransform<NuGetFramework>("TargetFrameworkVersion",
|
||||
f => "v" + GetDisplayVersion(f.Version),
|
||||
f => true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
public class MigrateXprojProjectReferencesRule : IMigrationRule
|
||||
{
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
throw new NotImplementedException("TODO: XProj ProjectToProject references");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// 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.IO;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
public class SaveOutputProjectRule : IMigrationRule
|
||||
{
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var outputName = Path.GetFileNameWithoutExtension(
|
||||
migrationRuleInputs.DefaultProjectContext.GetOutputPaths("_").CompilationFiles.Assembly);
|
||||
|
||||
var outputProject = Path.Combine(migrationSettings.OutputDirectory, outputName + ".csproj");
|
||||
|
||||
migrationRuleInputs.OutputMSBuildProject.Save(outputProject);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// 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 System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
/// <summary>
|
||||
/// This rule is temporary while project.json still exists in the new project system.
|
||||
/// It renames your existing project.json (if output directory is the current project directory),
|
||||
/// creates a copy, then mutates that copy.
|
||||
///
|
||||
/// Mutations:
|
||||
/// - inject a dependency on the Microsoft.SDK targets
|
||||
/// - removing the "runtimes" node.
|
||||
/// </summary>
|
||||
public class TemporaryMutateProjectJsonRule : IMigrationRule
|
||||
{
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
bool shouldRenameOldProject = PathsAreEqual(migrationSettings.OutputDirectory, migrationSettings.ProjectDirectory);
|
||||
|
||||
if (!shouldRenameOldProject && File.Exists(Path.Combine(migrationSettings.OutputDirectory, "project.json")))
|
||||
{
|
||||
// TODO: should there be a setting to overwrite anything in output directory?
|
||||
throw new Exception("Existing project.json found in output directory.");
|
||||
}
|
||||
|
||||
var sourceProjectFile = Path.Combine(migrationSettings.ProjectDirectory, "project.json");
|
||||
var destinationProjectFile = Path.Combine(migrationSettings.OutputDirectory, "project.json");
|
||||
if (shouldRenameOldProject)
|
||||
{
|
||||
var renamedProjectFile = Path.Combine(migrationSettings.ProjectDirectory, "project.migrated.json");
|
||||
File.Move(sourceProjectFile, renamedProjectFile);
|
||||
sourceProjectFile = renamedProjectFile;
|
||||
}
|
||||
|
||||
var json = CreateDestinationProjectFile(sourceProjectFile, destinationProjectFile);
|
||||
InjectSdkReference(json, ConstantPackageNames.CSdkPackageName, migrationSettings.SdkPackageVersion);
|
||||
RemoveRuntimesNode(json);
|
||||
|
||||
File.WriteAllText(destinationProjectFile, json.ToString());
|
||||
}
|
||||
|
||||
private JObject CreateDestinationProjectFile(string sourceProjectFile, string destinationProjectFile)
|
||||
{
|
||||
File.Copy(sourceProjectFile, destinationProjectFile);
|
||||
return JObject.Parse(File.ReadAllText(destinationProjectFile));
|
||||
}
|
||||
|
||||
private void InjectSdkReference(JObject json, string sdkPackageName, string sdkPackageVersion)
|
||||
{
|
||||
JToken dependenciesNode;
|
||||
if (json.TryGetValue("dependencies", out dependenciesNode))
|
||||
{
|
||||
var dependenciesNodeObject = dependenciesNode.Value<JObject>();
|
||||
dependenciesNodeObject.Add(sdkPackageName, sdkPackageVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dependenciesNodeObject = new JObject();
|
||||
dependenciesNodeObject.Add(sdkPackageName, sdkPackageVersion);
|
||||
|
||||
json.Add("dependencies", dependenciesNodeObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveRuntimesNode(JObject json)
|
||||
{
|
||||
json.Remove("runtimes");
|
||||
}
|
||||
|
||||
private bool PathsAreEqual(params string[] paths)
|
||||
{
|
||||
var normalizedPaths = paths.Select(path => Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar)).ToList();
|
||||
|
||||
for (int i=1; i<normalizedPaths.Count(); ++i)
|
||||
{
|
||||
var path1 = normalizedPaths[i - 1];
|
||||
var path2 = normalizedPaths[i];
|
||||
if (!string.Equals(path1, path2, StringComparison.Ordinal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
24
src/Microsoft.DotNet.ProjectJsonMigration/project.json
Normal file
24
src/Microsoft.DotNet.ProjectJsonMigration/project.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"version": "1.0.0-featmsbuild-*",
|
||||
"buildOptions": {
|
||||
"warningsAsErrors": true
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.DotNet.Compiler.Common": {
|
||||
"target": "project"
|
||||
},
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"target": "project"
|
||||
},
|
||||
"Microsoft.DotNet.ProjectModel": {
|
||||
"target": "project"
|
||||
},
|
||||
"Microsoft.Build.Framework": "0.1.0-preview-00029-160805",
|
||||
"Microsoft.Build.Utilities.Core": "0.1.0-preview-00029-160805",
|
||||
"Microsoft.Build": "0.1.0-preview-00029-160805",
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
// 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.Utils;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
||||
{
|
||||
public class AddItemTransform<T> : ConditionalTransform<T, ProjectItemElement>
|
||||
{
|
||||
private readonly ProjectRootElement _itemObjectGenerator = ProjectRootElement.Create();
|
||||
|
||||
private readonly string _itemName;
|
||||
private readonly string _includeValue;
|
||||
private readonly string _excludeValue;
|
||||
|
||||
private readonly Func<T, string> _includeValueFunc;
|
||||
private readonly Func<T, string> _excludeValueFunc;
|
||||
|
||||
private readonly List<ItemMetadataValue<T>> _metadata = new List<ItemMetadataValue<T>>();
|
||||
|
||||
public AddItemTransform(
|
||||
string itemName,
|
||||
IEnumerable<string> includeValues,
|
||||
IEnumerable<string> excludeValues,
|
||||
Func<T, bool> condition)
|
||||
: this(itemName, string.Join(";", includeValues), string.Join(";", excludeValues), condition) { }
|
||||
|
||||
public AddItemTransform(
|
||||
string itemName,
|
||||
Func<T, string> includeValueFunc,
|
||||
Func<T, string> excludeValueFunc,
|
||||
Func<T, bool> condition)
|
||||
: base(condition)
|
||||
{
|
||||
_itemName = itemName;
|
||||
_includeValueFunc = includeValueFunc;
|
||||
_excludeValueFunc = excludeValueFunc;
|
||||
}
|
||||
|
||||
public AddItemTransform(
|
||||
string itemName,
|
||||
string includeValue,
|
||||
Func<T, string> excludeValueFunc,
|
||||
Func<T, bool> condition)
|
||||
: base(condition)
|
||||
{
|
||||
_itemName = itemName;
|
||||
_includeValue = includeValue;
|
||||
_excludeValueFunc = excludeValueFunc;
|
||||
}
|
||||
|
||||
public AddItemTransform(
|
||||
string itemName,
|
||||
Func<T, string> includeValueFunc,
|
||||
string excludeValue,
|
||||
Func<T, bool> condition)
|
||||
: base(condition)
|
||||
{
|
||||
_itemName = itemName;
|
||||
_includeValueFunc = includeValueFunc;
|
||||
_excludeValue = excludeValue;
|
||||
}
|
||||
|
||||
public AddItemTransform(
|
||||
string itemName,
|
||||
string includeValue,
|
||||
string excludeValue,
|
||||
Func<T, bool> condition)
|
||||
: base(condition)
|
||||
{
|
||||
_itemName = itemName;
|
||||
_includeValue = includeValue;
|
||||
_excludeValue = excludeValue;
|
||||
}
|
||||
|
||||
public AddItemTransform<T> WithMetadata(string metadataName, string metadataValue)
|
||||
{
|
||||
_metadata.Add(new ItemMetadataValue<T>(metadataName, metadataValue));
|
||||
return this;
|
||||
}
|
||||
|
||||
public AddItemTransform<T> WithMetadata(string metadataName, Func<T, string> metadataValueFunc)
|
||||
{
|
||||
_metadata.Add(new ItemMetadataValue<T>(metadataName, metadataValueFunc));
|
||||
return this;
|
||||
}
|
||||
|
||||
public AddItemTransform<T> WithMetadata(ItemMetadataValue<T> metadata)
|
||||
{
|
||||
_metadata.Add(metadata);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override ProjectItemElement ConditionallyTransform(T source)
|
||||
{
|
||||
string includeValue = _includeValue ?? _includeValueFunc(source);
|
||||
string excludeValue = _excludeValue ?? _excludeValueFunc(source);
|
||||
|
||||
var item = _itemObjectGenerator.AddItem(_itemName, includeValue);
|
||||
item.Exclude = excludeValue;
|
||||
|
||||
foreach (var metadata in _metadata)
|
||||
{
|
||||
item.AddMetadata(metadata.MetadataName, metadata.GetMetadataValue(source));
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// 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.Utils;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
||||
{
|
||||
public class AddPropertyTransform<T> : ConditionalTransform<T, ProjectPropertyElement>
|
||||
{
|
||||
public string PropertyName { get; }
|
||||
|
||||
private readonly ProjectRootElement _propertyObjectGenerator = ProjectRootElement.Create();
|
||||
private readonly string _propertyValue;
|
||||
private readonly Func<T,string> _propertyValueFunc;
|
||||
|
||||
public AddPropertyTransform(string propertyName, string propertyValue, Func<T,bool> condition)
|
||||
: base(condition)
|
||||
{
|
||||
PropertyName = propertyName;
|
||||
_propertyValue = propertyValue;
|
||||
}
|
||||
|
||||
public AddPropertyTransform(string propertyName, Func<T, string> propertyValueFunc, Func<T,bool> condition)
|
||||
: base(condition)
|
||||
{
|
||||
PropertyName = propertyName;
|
||||
_propertyValueFunc = propertyValueFunc;
|
||||
}
|
||||
|
||||
public override ProjectPropertyElement ConditionallyTransform(T source)
|
||||
{
|
||||
string propertyValue = GetPropertyValue(source);
|
||||
|
||||
var property = _propertyObjectGenerator.CreatePropertyElement(PropertyName);
|
||||
property.Value = propertyValue;
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
public string GetPropertyValue(T source)
|
||||
{
|
||||
return _propertyValue ?? _propertyValueFunc(source);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// 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.Utils;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
||||
{
|
||||
public abstract class ConditionalTransform<T, U> : ITransform<T, U>
|
||||
{
|
||||
private Func<T, bool> _condition;
|
||||
|
||||
public ConditionalTransform(Func<T,bool> condition)
|
||||
{
|
||||
_condition = condition;
|
||||
}
|
||||
|
||||
public U Transform(T source)
|
||||
{
|
||||
if (_condition == null || _condition(source))
|
||||
{
|
||||
return ConditionallyTransform(source);
|
||||
}
|
||||
|
||||
return default(U);
|
||||
}
|
||||
|
||||
public abstract U ConditionallyTransform(T source);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using Microsoft.Build.Construction;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
||||
{
|
||||
public interface ITransform<T, U>
|
||||
{
|
||||
U Transform(T source);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.Build.Construction;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
||||
{
|
||||
public interface ITransformApplicator
|
||||
{
|
||||
void Execute<T, U>(
|
||||
T element,
|
||||
U destinationElement) where T : ProjectElement where U : ProjectElementContainer;
|
||||
|
||||
void Execute<T, U>(
|
||||
IEnumerable<T> elements,
|
||||
U destinationElement) where T : ProjectElement where U : ProjectElementContainer;
|
||||
|
||||
void Execute(
|
||||
ProjectItemElement item,
|
||||
ProjectItemGroupElement destinationItemGroup,
|
||||
bool mergeExisting);
|
||||
|
||||
void Execute(
|
||||
IEnumerable<ProjectItemElement> items,
|
||||
ProjectItemGroupElement destinationItemGroup,
|
||||
bool mergeExisting);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
using Microsoft.DotNet.ProjectModel.Files;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Models;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
||||
{
|
||||
public class IncludeContextTransform : ConditionalTransform<IncludeContext, IEnumerable<ProjectItemElement>>
|
||||
{
|
||||
// TODO: If a directory is specified in project.json does this need to be replaced with a glob in msbuild?
|
||||
// - Partially solved, what if the resolved glob is a directory?
|
||||
// TODO: Support mappings
|
||||
|
||||
private readonly string _itemName;
|
||||
private bool _transformMappings;
|
||||
private readonly List<ItemMetadataValue<IncludeContext>> _metadata = new List<ItemMetadataValue<IncludeContext>>();
|
||||
private AddItemTransform<IncludeContext>[] _transformSet;
|
||||
|
||||
public IncludeContextTransform(
|
||||
string itemName,
|
||||
bool transformMappings = true,
|
||||
Func<IncludeContext, bool> condition = null) : base(condition)
|
||||
{
|
||||
_itemName = itemName;
|
||||
_transformMappings = transformMappings;
|
||||
}
|
||||
|
||||
public IncludeContextTransform WithMetadata(string metadataName, string metadataValue)
|
||||
{
|
||||
_metadata.Add(new ItemMetadataValue<IncludeContext>(metadataName, metadataValue));
|
||||
return this;
|
||||
}
|
||||
|
||||
public IncludeContextTransform WithMetadata(string metadataName, Func<IncludeContext, string> metadataValueFunc)
|
||||
{
|
||||
_metadata.Add(new ItemMetadataValue<IncludeContext>(metadataName, metadataValueFunc));
|
||||
return this;
|
||||
}
|
||||
|
||||
private void CreateTransformSet()
|
||||
{
|
||||
var includeFilesExcludeFilesTransformation = new AddItemTransform<IncludeContext>(
|
||||
_itemName,
|
||||
includeContext => FormatPatterns(includeContext.IncludeFiles, includeContext.SourceBasePath),
|
||||
includeContext => FormatPatterns(includeContext.ExcludeFiles, includeContext.SourceBasePath),
|
||||
includeContext => includeContext != null && includeContext.IncludeFiles.Count > 0);
|
||||
|
||||
var includeExcludeTransformation = new AddItemTransform<IncludeContext>(
|
||||
_itemName,
|
||||
includeContext =>
|
||||
{
|
||||
var fullIncludeSet = includeContext.IncludePatterns.OrEmptyIfNull()
|
||||
.Union(includeContext.BuiltInsInclude.OrEmptyIfNull());
|
||||
|
||||
return FormatPatterns(fullIncludeSet, includeContext.SourceBasePath);
|
||||
},
|
||||
includeContext =>
|
||||
{
|
||||
var fullExcludeSet = includeContext.ExcludePatterns.OrEmptyIfNull()
|
||||
.Union(includeContext.BuiltInsExclude.OrEmptyIfNull())
|
||||
.Union(includeContext.ExcludeFiles.OrEmptyIfNull());
|
||||
|
||||
return FormatPatterns(fullExcludeSet, includeContext.SourceBasePath);
|
||||
},
|
||||
includeContext =>
|
||||
{
|
||||
return includeContext != null &&
|
||||
(
|
||||
(includeContext.IncludePatterns != null && includeContext.IncludePatterns.Count > 0)
|
||||
||
|
||||
(includeContext.BuiltInsInclude != null && includeContext.BuiltInsInclude.Count > 0)
|
||||
);
|
||||
});
|
||||
|
||||
foreach (var metadata in _metadata)
|
||||
{
|
||||
includeFilesExcludeFilesTransformation.WithMetadata(metadata);
|
||||
includeExcludeTransformation.WithMetadata(metadata);
|
||||
}
|
||||
|
||||
_transformSet = new []
|
||||
{
|
||||
includeFilesExcludeFilesTransformation,
|
||||
includeExcludeTransformation
|
||||
};
|
||||
}
|
||||
|
||||
private string FormatPatterns(IEnumerable<string> patterns, string projectDirectory)
|
||||
{
|
||||
List<string> mutatedPatterns = new List<string>(patterns.Count());
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
// Do not use forward slashes
|
||||
// https://github.com/Microsoft/msbuild/issues/724
|
||||
var mutatedPattern = pattern.Replace('/', '\\');
|
||||
|
||||
// MSBuild cannot copy directories
|
||||
mutatedPattern = ReplaceDirectoriesWithGlobs(mutatedPattern, projectDirectory);
|
||||
|
||||
mutatedPatterns.Add(mutatedPattern);
|
||||
}
|
||||
|
||||
return string.Join(";", mutatedPatterns);
|
||||
}
|
||||
|
||||
private string ReplaceDirectoriesWithGlobs(string pattern, string projectDirectory)
|
||||
{
|
||||
if (PatternIsDirectory(pattern, projectDirectory))
|
||||
{
|
||||
return $"{pattern.TrimEnd(new char[] { '\\' })}\\**\\*";
|
||||
}
|
||||
else
|
||||
{
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
||||
private bool PatternIsDirectory(string pattern, string projectDirectory)
|
||||
{
|
||||
// TODO: what about /some/path/**/somedir?
|
||||
// Should this even be migrated?
|
||||
var path = pattern;
|
||||
|
||||
if (!Path.IsPathRooted(path))
|
||||
{
|
||||
path = Path.Combine(projectDirectory, path);
|
||||
}
|
||||
|
||||
return Directory.Exists(path);
|
||||
}
|
||||
|
||||
public override IEnumerable<ProjectItemElement> ConditionallyTransform(IncludeContext source)
|
||||
{
|
||||
CreateTransformSet();
|
||||
|
||||
return _transformSet.Select(t => t.Transform(source));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
// 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.Utils;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
||||
{
|
||||
public class TransformApplicator : ITransformApplicator
|
||||
{
|
||||
private readonly ProjectRootElement _projectElementGenerator = ProjectRootElement.Create();
|
||||
|
||||
public void Execute<T, U>(
|
||||
T element,
|
||||
U destinationElement) where T : ProjectElement where U : ProjectElementContainer
|
||||
{
|
||||
if (element != null)
|
||||
{
|
||||
if (typeof(T) == typeof(ProjectItemElement))
|
||||
{
|
||||
var item = destinationElement.ContainingProject.CreateItemElement("___TEMP___");
|
||||
item.CopyFrom(element);
|
||||
|
||||
destinationElement.AppendChild(item);
|
||||
item.AddMetadata((element as ProjectItemElement).Metadata);
|
||||
}
|
||||
else if (typeof(T) == typeof(ProjectPropertyElement))
|
||||
{
|
||||
var property = destinationElement.ContainingProject.CreatePropertyElement("___TEMP___");
|
||||
property.CopyFrom(element);
|
||||
|
||||
destinationElement.AppendChild(property);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unable to add unknown project element to project");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute<T, U>(
|
||||
IEnumerable<T> elements,
|
||||
U destinationElement) where T : ProjectElement where U : ProjectElementContainer
|
||||
{
|
||||
foreach (var element in elements)
|
||||
{
|
||||
Execute(element, destinationElement);
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute(
|
||||
ProjectItemElement item,
|
||||
ProjectItemGroupElement destinationItemGroup,
|
||||
bool mergeExisting)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mergeExisting)
|
||||
{
|
||||
var existingItems = FindExistingItems(item, destinationItemGroup.ContainingProject);
|
||||
|
||||
foreach (var existingItem in existingItems)
|
||||
{
|
||||
var mergeResult = MergeItems(item, existingItem);
|
||||
item = mergeResult.InputItem;
|
||||
|
||||
// Existing Item is null when it's entire set of includes has been merged with the MergeItem
|
||||
if (mergeResult.ExistingItem == null)
|
||||
{
|
||||
existingItem.Parent.RemoveChild(existingItem);
|
||||
}
|
||||
|
||||
Execute(mergeResult.MergedItem, destinationItemGroup);
|
||||
}
|
||||
|
||||
// Item will be null only when it's entire set of includes is merged with existing items
|
||||
if (item != null)
|
||||
{
|
||||
Execute(item, destinationItemGroup);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Execute(item, destinationItemGroup);
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute(
|
||||
IEnumerable<ProjectItemElement> items,
|
||||
ProjectItemGroupElement destinationItemGroup,
|
||||
bool mergeExisting)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
Execute(item, destinationItemGroup, mergeExisting);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges two items on their common sets of includes.
|
||||
/// The output is 3 items, the 2 input items and the merged items. If the common
|
||||
/// set of includes spans the entirety of the includes of either of the 2 input
|
||||
/// items, that item will be returned as null.
|
||||
///
|
||||
/// The 3rd output item, the merged item, will have the Union of the excludes and
|
||||
/// metadata from the 2 input items. If any metadata between the 2 input items is different,
|
||||
/// this will throw.
|
||||
///
|
||||
/// This function will mutate the Include property of the 2 input items, removing the common subset.
|
||||
/// </summary>
|
||||
private MergeResult MergeItems(ProjectItemElement item, ProjectItemElement existingItem)
|
||||
{
|
||||
if (!string.Equals(item.ItemType, existingItem.ItemType, StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException("Cannot merge items of different types.");
|
||||
}
|
||||
|
||||
if (!item.IntersectIncludes(existingItem).Any())
|
||||
{
|
||||
throw new InvalidOperationException("Cannot merge items without a common include.");
|
||||
}
|
||||
|
||||
var commonIncludes = item.IntersectIncludes(existingItem).ToList();
|
||||
item.RemoveIncludes(commonIncludes);
|
||||
existingItem.RemoveIncludes(commonIncludes);
|
||||
|
||||
var mergedItem = _projectElementGenerator.AddItem(item.ItemType, string.Join(";", commonIncludes));
|
||||
|
||||
mergedItem.UnionExcludes(existingItem.Excludes());
|
||||
mergedItem.UnionExcludes(item.Excludes());
|
||||
|
||||
mergedItem.AddMetadata(existingItem.Metadata);
|
||||
mergedItem.AddMetadata(item.Metadata);
|
||||
|
||||
var mergeResult = new MergeResult
|
||||
{
|
||||
InputItem = string.IsNullOrEmpty(item.Include) ? null : item,
|
||||
ExistingItem = string.IsNullOrEmpty(existingItem.Include) ? null : existingItem,
|
||||
MergedItem = mergedItem
|
||||
};
|
||||
|
||||
return mergeResult;
|
||||
}
|
||||
|
||||
private IEnumerable<ProjectItemElement> FindExistingItems(ProjectItemElement item, ProjectRootElement project)
|
||||
{
|
||||
return project.ItemsWithoutConditions()
|
||||
.Where(i => string.Equals(i.ItemType, item.ItemType, StringComparison.Ordinal))
|
||||
.Where(i => i.IntersectIncludes(item).Any());
|
||||
}
|
||||
|
||||
private class MergeResult
|
||||
{
|
||||
public ProjectItemElement InputItem { get; set; }
|
||||
public ProjectItemElement ExistingItem { get; set; }
|
||||
public ProjectItemElement MergedItem { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>1c599ffd-fb52-4279-a8e5-465d3ec499e1</ProjectGuid>
|
||||
<ProjectGuid>651DDD55-4819-4F20-B619-4F8A5BC2DF6D</ProjectGuid>
|
||||
<RootNamespace>Microsoft.DotNet.ProjectModel.Loader</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin</OutputPath>
|
||||
|
|
|
@ -38,7 +38,15 @@ namespace Microsoft.DotNet.ProjectModel.Files
|
|||
SourceBasePath = sourceBasePath;
|
||||
Option = option;
|
||||
var token = rawObject.Value<JToken>(option);
|
||||
if (token.Type != JTokenType.Object)
|
||||
|
||||
if (token == null)
|
||||
{
|
||||
IncludePatterns = new List<string>();
|
||||
ExcludePatterns = new List<string>();
|
||||
IncludeFiles = new List<string>();
|
||||
ExcludeFiles = new List<string>();
|
||||
}
|
||||
else if (token.Type != JTokenType.Object)
|
||||
{
|
||||
IncludePatterns = CreateCollection(
|
||||
sourceBasePath, option, ExtractValues(token), literalPath: false);
|
||||
|
|
|
@ -21,6 +21,7 @@ using Microsoft.DotNet.Tools.Restore;
|
|||
using Microsoft.DotNet.Tools.Restore3;
|
||||
using Microsoft.DotNet.Tools.Run;
|
||||
using Microsoft.DotNet.Tools.Test;
|
||||
using Microsoft.DotNet.Tools.Migrate;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli
|
||||
|
@ -42,6 +43,7 @@ namespace Microsoft.DotNet.Cli
|
|||
["run3"] = Run3Command.Run,
|
||||
["restore3"] = Restore3Command.Run,
|
||||
["pack3"] = Pack3Command.Run,
|
||||
["migrate"] = MigrateCommand.Run
|
||||
};
|
||||
|
||||
public static int Main(string[] args)
|
||||
|
|
|
@ -2,4 +2,4 @@ using System.Reflection;
|
|||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyMetadataAttribute("Serviceable", "True")]
|
||||
[assembly: InternalsVisibleTo("dotnet.Tests")]
|
||||
[assembly: InternalsVisibleTo("dotnet.Tests")]
|
|
@ -15,6 +15,5 @@ namespace Microsoft.DotNet.Cli
|
|||
{
|
||||
return new MSBuildForwardingApp(args).Execute();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
78
src/dotnet/commands/dotnet-migrate/MigrateCommand.cs
Normal file
78
src/dotnet/commands/dotnet-migrate/MigrateCommand.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
// 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.Build.Construction;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using Microsoft.DotNet.ProjectJsonMigration;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Migrate
|
||||
{
|
||||
public partial class MigrateCommand
|
||||
{
|
||||
private readonly string _templateFile;
|
||||
private readonly string _outputDirectory;
|
||||
private readonly string _projectJson;
|
||||
private readonly string _sdkVersion;
|
||||
|
||||
private readonly TemporaryDotnetNewTemplateProject _temporaryDotnetNewProject;
|
||||
|
||||
public MigrateCommand(string templateFile, string outputDirectory, string projectJson, string sdkVersion)
|
||||
{
|
||||
_templateFile = templateFile;
|
||||
_outputDirectory = outputDirectory;
|
||||
_projectJson = projectJson;
|
||||
_sdkVersion = sdkVersion;
|
||||
|
||||
_temporaryDotnetNewProject = new TemporaryDotnetNewTemplateProject();
|
||||
}
|
||||
|
||||
public int Execute()
|
||||
{
|
||||
var project = GetProjectJsonPath(_projectJson) ?? GetProjectJsonPath(Directory.GetCurrentDirectory());
|
||||
EnsureNotNull(project, "Unable to find project.json");
|
||||
var projectDirectory = Path.GetDirectoryName(project);
|
||||
|
||||
var msBuildTemplate = _templateFile != null ?
|
||||
ProjectRootElement.TryOpen(_templateFile) : _temporaryDotnetNewProject.MSBuildProject;
|
||||
|
||||
var outputDirectory = _outputDirectory ?? projectDirectory;
|
||||
EnsureNotNull(outputDirectory, "Null output directory");
|
||||
|
||||
var sdkVersion = _sdkVersion ?? new ProjectJsonParser(_temporaryDotnetNewProject.ProjectJson).SdkPackageVersion;
|
||||
EnsureNotNull(sdkVersion, "Null Sdk Version");
|
||||
|
||||
var migrationSettings = new MigrationSettings(projectDirectory, outputDirectory, sdkVersion, msBuildTemplate);
|
||||
new ProjectMigrator().Migrate(migrationSettings);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void EnsureNotNull(string variable, string message)
|
||||
{
|
||||
if (variable == null)
|
||||
{
|
||||
throw new Exception(message);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetProjectJsonPath(string projectJson)
|
||||
{
|
||||
if (projectJson == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
projectJson = ProjectPathHelper.NormalizeProjectFilePath(projectJson);
|
||||
|
||||
if (File.Exists(projectJson))
|
||||
{
|
||||
return projectJson;
|
||||
}
|
||||
|
||||
throw new Exception($"Unable to find project file at {projectJson}");
|
||||
}
|
||||
}
|
||||
}
|
54
src/dotnet/commands/dotnet-migrate/Program.cs
Normal file
54
src/dotnet/commands/dotnet-migrate/Program.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
// 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 Microsoft.DotNet.Cli.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Migrate
|
||||
{
|
||||
public partial class MigrateCommand
|
||||
{
|
||||
public static int Run(string[] args)
|
||||
{
|
||||
DebugHelper.HandleDebugSwitch(ref args);
|
||||
|
||||
CommandLineApplication app = new CommandLineApplication();
|
||||
app.Name = "dotnet migrate";
|
||||
app.FullName = ".NET Migrate Command";
|
||||
app.Description = "Command used to migrate project.json projects to msbuild";
|
||||
app.HandleResponseFiles = true;
|
||||
app.HelpOption("-h|--help");
|
||||
|
||||
CommandOption template = app.Option("-t|--template-file", "Base MSBuild template to use for migrated app. The default is the project included in dotnet new -t msbuild", CommandOptionType.SingleValue);
|
||||
CommandOption output = app.Option("-o|--output", "Directory to output migrated project to. The default is the project directory", CommandOptionType.SingleValue);
|
||||
CommandOption project = app.Option("-p|--project", "The path to the project to run (defaults to the current directory). Can be a path to a project.json or a project directory", CommandOptionType.SingleValue);
|
||||
CommandOption sdkVersion = app.Option("-v|--sdk-package-version", "The version of the sdk package that will be referenced in the migrated app. The default is the version of the sdk in dotnet new -t msbuild", CommandOptionType.SingleValue);
|
||||
|
||||
app.OnExecute(() =>
|
||||
{
|
||||
MigrateCommand migrateCommand = new MigrateCommand(
|
||||
template.Value(),
|
||||
output.Value(),
|
||||
project.Value(),
|
||||
sdkVersion.Value());
|
||||
|
||||
return migrateCommand.Execute();
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
return app.Execute(args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Reporter.Error.WriteLine(ex.ToString());
|
||||
#else
|
||||
Reporter.Error.WriteLine(ex.Message);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
80
src/dotnet/commands/dotnet-migrate/ProjectJsonParser.cs
Normal file
80
src/dotnet/commands/dotnet-migrate/ProjectJsonParser.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.ProjectJsonMigration;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Migrate
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses select data from a project.json without relying on ProjectModel.
|
||||
/// Used to parse simple information.
|
||||
/// </summary>
|
||||
internal class ProjectJsonParser
|
||||
{
|
||||
public string SdkPackageVersion { get; }
|
||||
|
||||
public ProjectJsonParser(JObject projectJson)
|
||||
{
|
||||
SdkPackageVersion = GetPackageVersion(projectJson, ConstantPackageNames.CSdkPackageName);
|
||||
}
|
||||
|
||||
private string GetPackageVersion(JObject projectJson, string packageName)
|
||||
{
|
||||
var sdkPackageNode = SelectJsonNodes(projectJson, property => property.Name == packageName).First();
|
||||
|
||||
if (sdkPackageNode.Value.Type == JTokenType.String)
|
||||
{
|
||||
return (string)sdkPackageNode.Value;
|
||||
}
|
||||
else if (sdkPackageNode.Type == JTokenType.Object)
|
||||
{
|
||||
var sdkPackageNodeValue = (JObject)sdkPackageNode.Value;
|
||||
|
||||
JToken versionNode;
|
||||
if (sdkPackageNodeValue.TryGetValue("version", out versionNode))
|
||||
{
|
||||
return versionNode.Value<string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unable to determine sdk version, no version node in default template.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unable to determine sdk version, no version information found");
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<JProperty> SelectJsonNodes(
|
||||
JToken jsonNode,
|
||||
Func<JProperty, bool> condition,
|
||||
List<JProperty> nodeAccumulator = null)
|
||||
{
|
||||
nodeAccumulator = nodeAccumulator ?? new List<JProperty>();
|
||||
|
||||
if (jsonNode.Type == JTokenType.Object)
|
||||
{
|
||||
var eligibleNodes = jsonNode.Children<JProperty>().Where(j => condition(j));
|
||||
nodeAccumulator.AddRange(eligibleNodes);
|
||||
|
||||
foreach (var child in jsonNode.Children<JProperty>())
|
||||
{
|
||||
SelectJsonNodes(child.Value, condition, nodeAccumulator: nodeAccumulator);
|
||||
}
|
||||
}
|
||||
else if (jsonNode.Type == JTokenType.Array)
|
||||
{
|
||||
foreach (var child in jsonNode.Children())
|
||||
{
|
||||
SelectJsonNodes(child, condition, nodeAccumulator: nodeAccumulator);
|
||||
}
|
||||
}
|
||||
|
||||
return nodeAccumulator;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.ProjectJsonMigration;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Migrate
|
||||
{
|
||||
internal class TemporaryDotnetNewTemplateProject
|
||||
{
|
||||
private const string c_temporaryDotnetNewMSBuildProjectName = "p";
|
||||
|
||||
private readonly string _projectDirectory;
|
||||
|
||||
public ProjectRootElement MSBuildProject { get; }
|
||||
public JObject ProjectJson { get; }
|
||||
|
||||
public TemporaryDotnetNewTemplateProject()
|
||||
{
|
||||
_projectDirectory = CreateDotnetNewMSBuild(c_temporaryDotnetNewMSBuildProjectName);
|
||||
MSBuildProject = GetMSBuildProject(_projectDirectory);
|
||||
ProjectJson = GetProjectJson(_projectDirectory);
|
||||
|
||||
Clean();
|
||||
}
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
Directory.Delete(Path.Combine(_projectDirectory, ".."), true);
|
||||
}
|
||||
|
||||
private string CreateDotnetNewMSBuild(string projectName)
|
||||
{
|
||||
var tempDir = Path.Combine(
|
||||
Path.GetTempPath(),
|
||||
this.GetType().Namespace,
|
||||
Path.GetRandomFileName(),
|
||||
c_temporaryDotnetNewMSBuildProjectName);
|
||||
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, true);
|
||||
}
|
||||
Directory.CreateDirectory(tempDir);
|
||||
|
||||
RunCommand("new", new string[] { "-t", "msbuild" }, tempDir);
|
||||
|
||||
return tempDir;
|
||||
}
|
||||
|
||||
private ProjectRootElement GetMSBuildProject(string temporaryDotnetNewMSBuildDirectory)
|
||||
{
|
||||
var templateProjPath = Path.Combine(temporaryDotnetNewMSBuildDirectory,
|
||||
c_temporaryDotnetNewMSBuildProjectName + ".csproj");
|
||||
|
||||
return ProjectRootElement.Open(templateProjPath);
|
||||
}
|
||||
|
||||
private JObject GetProjectJson(string temporaryDotnetNewMSBuildDirectory)
|
||||
{
|
||||
var projectJsonFile = Path.Combine(temporaryDotnetNewMSBuildDirectory, "project.json");
|
||||
return JObject.Parse(File.ReadAllText(projectJsonFile));
|
||||
}
|
||||
|
||||
private void RunCommand(string commandToExecute, IEnumerable<string> args, string workingDirectory)
|
||||
{
|
||||
var command = new DotNetCommandFactory()
|
||||
.Create(commandToExecute, args)
|
||||
.WorkingDirectory(workingDirectory)
|
||||
.CaptureStdOut()
|
||||
.CaptureStdErr();
|
||||
|
||||
var commandResult = command.Execute();
|
||||
|
||||
if (commandResult.ExitCode != 0)
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine(commandResult.StdOut);
|
||||
MigrationTrace.Instance.WriteLine(commandResult.StdErr);
|
||||
|
||||
throw new Exception($"Failed to run {commandToExecute} in directory: {workingDirectory}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,6 +45,9 @@
|
|||
"Microsoft.DotNet.Configurer": {
|
||||
"target": "project"
|
||||
},
|
||||
"Microsoft.DotNet.ProjectJsonMigration": {
|
||||
"target": "project"
|
||||
},
|
||||
"Microsoft.DotNet.Tools.Test": {
|
||||
"target": "project"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Rules;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using NuGet.Frameworks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
||||
{
|
||||
public class GivenAProjectMigrator : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void It_copies_ProjectDirectory_contents_to_OutputDirectory_when_the_directories_are_different()
|
||||
{
|
||||
var testProjectDirectory = TestAssetsManager.CreateTestInstance("TestAppSimple", callingMethod: "z")
|
||||
.WithLockFiles().Path;
|
||||
var outputDirectory = Temp.CreateDirectory().Path;
|
||||
|
||||
var projectDirectoryRelativeFilePaths = EnumerateFilesWithRelativePath(testProjectDirectory);
|
||||
|
||||
var mockProj = ProjectRootElement.Create();
|
||||
var testSettings = new MigrationSettings(testProjectDirectory, outputDirectory, "1.0.0", mockProj);
|
||||
|
||||
var projectMigrator = new ProjectMigrator(new FakeEmptyMigrationRule());
|
||||
projectMigrator.Migrate(testSettings);
|
||||
|
||||
foreach (var projectDirectoryRelativeFilePath in projectDirectoryRelativeFilePaths)
|
||||
{
|
||||
File.Exists(Path.Combine(outputDirectory, projectDirectoryRelativeFilePath)).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_throws_when_migrating_a_deprecated_projectJson()
|
||||
{
|
||||
var testProjectDirectory =
|
||||
TestAssetsManager.CreateTestInstance("TestLibraryWithDeprecatedProjectFile", callingMethod: "z")
|
||||
.WithLockFiles().Path;
|
||||
|
||||
var mockProj = ProjectRootElement.Create();
|
||||
var testSettings = new MigrationSettings(testProjectDirectory, testProjectDirectory, "1.0.0", mockProj);
|
||||
|
||||
var projectMigrator = new ProjectMigrator(new FakeEmptyMigrationRule());
|
||||
Action migrateAction = () => projectMigrator.Migrate(testSettings);
|
||||
|
||||
migrateAction.ShouldThrow<Exception>().Where(
|
||||
e => e.Message.Contains("MIGRATE1011::Deprecated Project:")
|
||||
&& e.Message.Contains("The 'packInclude' option is deprecated. Use 'files' in 'packOptions' instead.")
|
||||
&& e.Message.Contains("The 'compilationOptions' option is deprecated. Use 'buildOptions' instead."));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_throws_when_migrating_a_non_csharp_app()
|
||||
{
|
||||
var testProjectDirectory =
|
||||
TestAssetsManager.CreateTestInstance("FSharpTestProjects/TestApp", callingMethod: "z")
|
||||
.WithLockFiles().Path;
|
||||
|
||||
var mockProj = ProjectRootElement.Create();
|
||||
var testSettings = new MigrationSettings(testProjectDirectory, testProjectDirectory, "1.0.0", mockProj);
|
||||
|
||||
var projectMigrator = new ProjectMigrator(new FakeEmptyMigrationRule());
|
||||
Action migrateAction = () => projectMigrator.Migrate(testSettings);
|
||||
|
||||
migrateAction.ShouldThrow<Exception>().Where(
|
||||
e => e.Message.Contains("MIGRATE20013::Non-Csharp App: Cannot migrate project"));
|
||||
}
|
||||
|
||||
private IEnumerable<string> EnumerateFilesWithRelativePath(string testProjectDirectory)
|
||||
{
|
||||
return
|
||||
Directory.EnumerateFiles(testProjectDirectory, "*", SearchOption.AllDirectories)
|
||||
.Select(file => PathUtility.GetRelativePath(testProjectDirectory, file));
|
||||
}
|
||||
|
||||
private class FakeEmptyMigrationRule : IMigrationRule
|
||||
{
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Build.Construction;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
||||
{
|
||||
public class GivenMSBuildExtensions
|
||||
{
|
||||
[Fact]
|
||||
public void Includes_returns_include_value_split_by_semicolon()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var item = project.CreateItemElement("test");
|
||||
item.Include = "include1;include2;aaa";
|
||||
|
||||
var includes = item.Includes().ToArray();
|
||||
|
||||
includes.Should().HaveCount(3);
|
||||
includes[0].Should().Be("include1");
|
||||
includes[1].Should().Be("include2");
|
||||
includes[2].Should().Be("aaa");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Excludes_returns_include_value_split_by_semicolon()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var item = project.CreateItemElement("test");
|
||||
item.Exclude = "include1;include2;aaa";
|
||||
|
||||
var excludes = item.Excludes().ToArray();
|
||||
|
||||
excludes.Should().HaveCount(3);
|
||||
excludes[0].Should().Be("include1");
|
||||
excludes[1].Should().Be("include2");
|
||||
excludes[2].Should().Be("aaa");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItemsWithoutConditions_returns_items_without_a_condition()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var item = project.AddItem("test", "include1");
|
||||
|
||||
project.ItemsWithoutConditions().Count().Should().Be(1);
|
||||
project.ItemsWithoutConditions().First().Should().Be(item);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItemsWithoutConditions_doesnt_return_items_with_a_condition()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var conditionlessItems = project.AddItem("test", "include1");
|
||||
var conditionItem = project.AddItem("test2", "include2");
|
||||
conditionItem.Condition = "SomeCondition";
|
||||
|
||||
project.ItemsWithoutConditions().Count().Should().Be(1);
|
||||
project.ItemsWithoutConditions().First().Should().Be(conditionlessItems);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItemsWithoutConditions_doesnt_return_items_with_a_parent_with_a_condition()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var conditionlessItems = project.AddItem("test", "include1");
|
||||
|
||||
var conditionItemGroup = project.AddItemGroup();
|
||||
conditionItemGroup.Condition = "SomeCondition";
|
||||
conditionItemGroup.AddItem("test2", "include2");
|
||||
|
||||
project.ItemsWithoutConditions().Count().Should().Be(1);
|
||||
project.ItemsWithoutConditions().First().Should().Be(conditionlessItems);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddIncludes_merges_include_sets()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var item1 = project.AddItem("test", "include1;include2");
|
||||
item1.UnionIncludes(new string[] {"include2", "include3"});
|
||||
|
||||
item1.Include.Should().Be("include1;include2;include3");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddExcludes_merges_include_sets()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var item1 = project.AddItem("test", "include1");
|
||||
item1.Exclude = "exclude1;exclude2";
|
||||
item1.UnionExcludes(new string[] {"exclude2", "exclude3"});
|
||||
|
||||
item1.Exclude.Should().Be("exclude1;exclude2;exclude3");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddMetadata_adds_metadata_available_via_Metadata_on_an_item()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var item1 = project.AddItem("test", "include1");
|
||||
item1.AddMetadata("name", "value");
|
||||
item1.HasMetadata.Should().BeTrue();
|
||||
|
||||
var item2 = project.AddItem("test1", "include1");
|
||||
item2.AddMetadata(item1.Metadata);
|
||||
|
||||
item2.HasMetadata.Should().BeTrue();
|
||||
item2.Metadata.First().Name.Should().Be("name");
|
||||
item2.Metadata.First().Value.Should().Be("value");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddMetadata_adds_metadata_from_an_item_generated_from_another_project()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var item1 = project.AddItem("test", "include1");
|
||||
item1.AddMetadata("name", "value");
|
||||
item1.HasMetadata.Should().BeTrue();
|
||||
|
||||
var project2 = ProjectRootElement.Create();
|
||||
var item2 = project2.AddItem("test1", "include1");
|
||||
item2.AddMetadata(item1.Metadata);
|
||||
|
||||
item2.HasMetadata.Should().BeTrue();
|
||||
item2.Metadata.First().Name.Should().Be("name");
|
||||
item2.Metadata.First().Value.Should().Be("value");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
https://github.com/Microsoft/msbuild/issues/927
|
|
@ -0,0 +1 @@
|
|||
https://github.com/Microsoft/msbuild/issues/927
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>1F2EF070-AC5F-4078-AFB0-65745AC691B9</ProjectGuid>
|
||||
<RootNamespace>Microsoft.DotNet.ProjectJsonMigration.Tests</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' “>..\artifact\obj\$(RootNamespace)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' “>..\artifacts\bin\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
|
@ -0,0 +1,110 @@
|
|||
using Microsoft.DotNet.TestFramework;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to build up test scenario project.jsons without needing to add a new test asset.
|
||||
/// </summary>
|
||||
public class ProjectJsonBuilder
|
||||
{
|
||||
private readonly TestAssetsManager _testAssetsManager;
|
||||
private JObject _projectJson;
|
||||
|
||||
private bool _baseDefined = false;
|
||||
private bool _baseProjectDirectory;
|
||||
|
||||
public ProjectJsonBuilder(TestAssetsManager testAssetsManager)
|
||||
{
|
||||
_testAssetsManager = testAssetsManager;
|
||||
}
|
||||
|
||||
public string SaveToDisk(string outputDirectory)
|
||||
{
|
||||
EnsureBaseIsSet();
|
||||
|
||||
var projectPath = Path.Combine(outputDirectory, "project.json");
|
||||
File.WriteAllText(projectPath, _projectJson.ToString());
|
||||
return projectPath;
|
||||
}
|
||||
|
||||
public JObject Build()
|
||||
{
|
||||
EnsureBaseIsSet();
|
||||
return _projectJson;
|
||||
}
|
||||
|
||||
public ProjectJsonBuilder FromTestAssetBase(string testAssetName)
|
||||
{
|
||||
var testProjectDirectory = _testAssetsManager.CreateTestInstance(testAssetName).Path;
|
||||
var testProject = Path.Combine(testProjectDirectory, "project.json");
|
||||
|
||||
SetBase(JObject.Parse(File.ReadAllText(testProject)));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProjectJsonBuilder FromStringBase(string jsonString)
|
||||
{
|
||||
SetBase(JObject.Parse(jsonString));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProjectJsonBuilder FromEmptyBase()
|
||||
{
|
||||
SetBase(new JObject());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProjectJsonBuilder WithCustomProperty(string propertyName, Dictionary<string, string> value)
|
||||
{
|
||||
EnsureBaseIsSet();
|
||||
|
||||
_projectJson[propertyName] = JObject.FromObject(value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProjectJsonBuilder WithCustomProperty(string propertyName, string value)
|
||||
{
|
||||
EnsureBaseIsSet();
|
||||
|
||||
_projectJson[propertyName] = value;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProjectJsonBuilder WithCustomProperty(string propertyName, string[] value)
|
||||
{
|
||||
EnsureBaseIsSet();
|
||||
|
||||
_projectJson[propertyName] = JArray.FromObject(value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void SetBase(JObject project)
|
||||
{
|
||||
if (_baseDefined)
|
||||
{
|
||||
throw new Exception("Base was already defined.");
|
||||
}
|
||||
_baseDefined = true;
|
||||
|
||||
_projectJson = project;
|
||||
}
|
||||
|
||||
private void EnsureBaseIsSet()
|
||||
{
|
||||
if (!_baseDefined)
|
||||
{
|
||||
throw new Exception("Cannot build without base set");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,452 @@
|
|||
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.IO;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Rules;
|
||||
using Microsoft.DotNet.ProjectModel.Files;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
||||
{
|
||||
public class GivenThatIWantToMigrateBuildOptions : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void Specified_default_properties_are_removed_when_they_exists_in_the_csproj_template()
|
||||
{
|
||||
// Setup project with default properties
|
||||
var defaultPropertiesExpectedToBeRemoved = new string[]
|
||||
{
|
||||
"OutputType",
|
||||
"TargetExt"
|
||||
};
|
||||
|
||||
var defaultValue = "defaultValue";
|
||||
|
||||
var templateProj = ProjectRootElement.Create();
|
||||
var defaultPropertyGroup = templateProj.AddPropertyGroup();
|
||||
|
||||
foreach (var defaultPropertyName in defaultPropertiesExpectedToBeRemoved)
|
||||
{
|
||||
defaultPropertyGroup.AddProperty(defaultPropertyName, defaultValue);
|
||||
}
|
||||
|
||||
// Setup projectcontext
|
||||
var testProjectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithRuntimeOptions").Path;
|
||||
var projectContext = ProjectContext.Create(testProjectDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
|
||||
|
||||
var testSettings = new MigrationSettings(testProjectDirectory, testProjectDirectory, "1.0.0", templateProj);
|
||||
var testInputs = new MigrationRuleInputs(new[] {projectContext}, templateProj, templateProj.AddItemGroup(),
|
||||
templateProj.AddPropertyGroup());
|
||||
new MigrateBuildOptionsRule().Apply(testSettings, testInputs);
|
||||
|
||||
defaultPropertyGroup.Properties.Count.Should().Be(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_empty_buildOptions_populates_only_AssemblyName_and_OutputType()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": { }
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count().Should().Be(2);
|
||||
mockProj.Properties.Any(
|
||||
p =>
|
||||
!(p.Name.Equals("AssemblyName", StringComparison.Ordinal) ||
|
||||
p.Name.Equals("OutputType", StringComparison.Ordinal))).Should().BeFalse();
|
||||
|
||||
mockProj.Items.Count().Should().Be(2);
|
||||
mockProj.Items.First(i => i.ItemType == "Compile").Include.Should().Be(@"**\*.cs");
|
||||
mockProj.Items.First(i => i.ItemType == "Compile").Exclude.Should().Be(@"bin\**;obj\**;**\*.xproj;packages\**");
|
||||
mockProj.Items.First(i => i.ItemType == "EmbeddedResource").Include.Should().Be(@"compiler\resources\**\*;**\*.resx");
|
||||
mockProj.Items.First(i => i.ItemType == "EmbeddedResource").Exclude.Should().Be(@"bin\**;obj\**;**\*.xproj;packages\**");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_EmitEntryPoint_true_populates_OutputType_field()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""emitEntryPoint"": ""true""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "OutputType").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "OutputType").Value.Should().Be("Exe");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_EmitEntryPoint_false_populates_OutputType_fields()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""emitEntryPoint"": ""false""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "OutputType").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "OutputType").Value.Should().Be("Library");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_define_populates_DefineConstants()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""define"": [ ""DEBUG"", ""TRACE"" ]
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "DefineConstants").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "DefineConstants").Value.Should().Be("DEBUG;TRACE");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_nowarn_populates_NoWarn()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""nowarn"": [ ""CS0168"", ""CS0219"" ]
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "NoWarn").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "NoWarn").Value.Should().Be("CS0168;CS0219");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_warningsAsErrors_populates_WarningsAsErrors()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""warningsAsErrors"": ""true""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "WarningsAsErrors").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "WarningsAsErrors").Value.Should().Be("true");
|
||||
|
||||
mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""warningsAsErrors"": ""false""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "WarningsAsErrors").Should().Be(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_allowUnsafe_populates_AllowUnsafeBlocks()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""allowUnsafe"": ""true""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "AllowUnsafeBlocks").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "AllowUnsafeBlocks").Value.Should().Be("true");
|
||||
|
||||
mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""allowUnsafe"": ""false""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "AllowUnsafeBlocks").Should().Be(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_optimize_populates_Optimize()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""optimize"": ""true""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "Optimize").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "Optimize").Value.Should().Be("true");
|
||||
|
||||
mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""optimize"": ""false""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "Optimize").Should().Be(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_platform_populates_PlatformTarget()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""platform"": ""x64""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "PlatformTarget").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "PlatformTarget").Value.Should().Be("x64");
|
||||
|
||||
mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""platform"": ""x86""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "PlatformTarget").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "PlatformTarget").Value.Should().Be("x86");
|
||||
|
||||
mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""platform"": ""foo""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "PlatformTarget").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "PlatformTarget").Value.Should().Be("foo");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_languageVersion_populates_LangVersion()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""languageVersion"": ""5""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "LangVersion").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "LangVersion").Value.Should().Be("5");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_keyFile_populates_AssemblyOriginatorKeyFile_and_SignAssembly()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""keyFile"": ""../keyfile.snk""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "AssemblyOriginatorKeyFile").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "AssemblyOriginatorKeyFile").Value.Should().Be("../keyfile.snk");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "SignAssembly").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "SignAssembly").Value.Should().Be("true");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_delaySign_populates_DelaySign()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""delaySign"": ""true""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "DelaySign").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "DelaySign").Value.Should().Be("true");
|
||||
|
||||
mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""delaySign"": ""false""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "DelaySign").Should().Be(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_publicSign_populates_PublicSign()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""publicSign"": ""true""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "PublicSign").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "PublicSign").Value.Should().Be("true");
|
||||
|
||||
mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""publicSign"": ""false""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "PublicSign").Should().Be(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_debugType_populates_DebugType()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""debugType"": ""full""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "DebugType").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "DebugType").Value.Should().Be("full");
|
||||
|
||||
mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""debugType"": ""foo""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "DebugType").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "DebugType").Value.Should().Be("foo");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_outputName_populates_AssemblyName()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""outputName"": ""ARandomName""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "AssemblyName").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "AssemblyName").Value.Should().Be("ARandomName");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_xmlDoc_populates_GenerateDocumentationFile()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""xmlDoc"": ""true""
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "GenerateDocumentationFile").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "GenerateDocumentationFile").Value.Should().Be("true");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("compile", "Compile")]
|
||||
[InlineData("embed", "EmbeddedResource")]
|
||||
[InlineData("copyToOutput", "Content")]
|
||||
private void Migrating_group_include_exclude_Populates_appropriate_ProjectItemElement(
|
||||
string group,
|
||||
string itemName)
|
||||
{
|
||||
var testDirectory = Temp.CreateDirectory().Path;
|
||||
|
||||
Directory.CreateDirectory(Path.Combine(testDirectory, "root"));
|
||||
Directory.CreateDirectory(Path.Combine(testDirectory, "src"));
|
||||
File.WriteAllText(Path.Combine(testDirectory, "root", "file1.txt"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "root", "file2.txt"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "root", "file3.txt"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "src", "file1.cs"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "src", "file2.cs"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "src", "file3.cs"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "rootfile.cs"), "content");
|
||||
|
||||
var pj = @"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""<group>"": {
|
||||
""include"": [""root"", ""src"", ""rootfile.cs""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""]
|
||||
}
|
||||
}
|
||||
}".Replace("<group>", group);
|
||||
|
||||
var mockProj = RunBuildOptionsRuleOnPj(pj,
|
||||
testDirectory: testDirectory);
|
||||
|
||||
mockProj.Items.Count(i => i.ItemType.Equals(itemName, StringComparison.Ordinal)).Should().Be(2);
|
||||
|
||||
var defaultIncludePatterns = group == "compile" ? ProjectFilesCollection.DefaultCompileBuiltInPatterns
|
||||
: group == "embed" ? ProjectFilesCollection.DefaultResourcesBuiltInPatterns
|
||||
: Enumerable.Empty<string>();
|
||||
|
||||
var defaultExcludePatterns = group == "copyToOutput" ? ProjectFilesCollection.DefaultPublishExcludePatterns
|
||||
: ProjectFilesCollection.DefaultBuiltInExcludePatterns;
|
||||
|
||||
foreach (var item in mockProj.Items.Where(i => i.ItemType.Equals(itemName, StringComparison.Ordinal)))
|
||||
{
|
||||
if (item.ItemType == "Content")
|
||||
{
|
||||
item.Metadata.Count(m => m.Name == "CopyToOutputDirectory").Should().Be(1);
|
||||
}
|
||||
|
||||
if (item.Include.Contains(@"src\file1.cs"))
|
||||
{
|
||||
item.Include.Should().Be(@"src\file1.cs;src\file2.cs");
|
||||
item.Exclude.Should().Be(@"src\file2.cs");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (defaultIncludePatterns.Any())
|
||||
{
|
||||
item.Include.Should()
|
||||
.Be(@"root\**\*;src\**\*;rootfile.cs;" + string.Join(";", defaultIncludePatterns).Replace("/", "\\"));
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Include.Should()
|
||||
.Be(@"root\**\*;src\**\*;rootfile.cs");
|
||||
}
|
||||
|
||||
if (defaultExcludePatterns.Any())
|
||||
{
|
||||
item.Exclude.Should()
|
||||
.Be(@"src\**\*;rootfile.cs;" + string.Join(";", defaultExcludePatterns).Replace("/", "\\") +
|
||||
@";src\file2.cs");
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Exclude.Should()
|
||||
.Be(@"src\**\*;rootfile.cs;src\file2.cs");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ProjectRootElement RunBuildOptionsRuleOnPj(string s, string testDirectory = null)
|
||||
{
|
||||
testDirectory = testDirectory ?? Temp.CreateDirectory().Path;
|
||||
return TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[]
|
||||
{
|
||||
new MigrateBuildOptionsRule()
|
||||
}, s, testDirectory);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Migration.Tests;
|
||||
using Microsoft.DotNet.ProjectJsonMigration;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using NuGet.Frameworks;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Rules;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Tests;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigrationMigration.Tests
|
||||
{
|
||||
public class GivenThatIWantToMigrateConfigurations : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_produce_expected_properties_in_a_group_with_a_condition()
|
||||
{
|
||||
var mockProj = RunConfigurationsRuleOnPj(@"
|
||||
{
|
||||
""configurations"": {
|
||||
""testconfig"": {
|
||||
""buildOptions"": {
|
||||
""emitEntryPoint"": ""true"",
|
||||
""debugType"": ""full""
|
||||
}
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(
|
||||
prop => prop.Name == "OutputType" || prop.Name == "DebugType").Should().Be(2);
|
||||
|
||||
mockProj.Properties.First(p => p.Name == "OutputType")
|
||||
.Parent.Condition.Should()
|
||||
.Contain("'$(Configuration)' == 'testconfig'");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_properties_are_not_written_when_they_overlap_with_buildOptions()
|
||||
{
|
||||
var mockProj = RunConfigurationsAndBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""emitEntryPoint"": ""true"",
|
||||
""debugType"": ""full""
|
||||
},
|
||||
""configurations"": {
|
||||
""testconfig"": {
|
||||
""buildOptions"": {
|
||||
""emitEntryPoint"": ""true"",
|
||||
""debugType"": ""full""
|
||||
}
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(property =>
|
||||
property.Name == "OutputType" || property.Name == "DebugType")
|
||||
.Should().Be(2);
|
||||
|
||||
foreach (var property in mockProj.Properties.Where(property =>
|
||||
property.Name == "OutputType" || property.Name == "DebugType"))
|
||||
{
|
||||
property.Parent.Condition.Should().Be(string.Empty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_includes_are_not_written_when_they_overlap_with_buildOptions()
|
||||
{
|
||||
var mockProj = RunConfigurationsAndBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
""include"": [""src""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""]
|
||||
}
|
||||
},
|
||||
""configurations"": {
|
||||
""testconfig"": {
|
||||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
""include"": [""root"", ""src"", ""rootfile.cs""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Items.Count(item => item.ItemType == "Content").Should().Be(3);
|
||||
|
||||
mockProj.Items.Where(item => item.ItemType == "Content")
|
||||
.Count(item => !string.IsNullOrEmpty(item.Parent.Condition))
|
||||
.Should()
|
||||
.Be(1);
|
||||
|
||||
var configContent = mockProj.Items
|
||||
.Where(item => item.ItemType == "Content").First(item => !string.IsNullOrEmpty(item.Parent.Condition));
|
||||
|
||||
// Directories are not converted to globs in the result because we did not write the directory
|
||||
configContent.Include.Should().Be(@"root;rootfile.cs");
|
||||
configContent.Exclude.Should().Be(@"src;rootfile.cs;src\file2.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_includes_which_have_different_excludes_than_buildOptions_throws()
|
||||
{
|
||||
Action action = () => RunConfigurationsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
""include"": [""src""],
|
||||
""exclude"": [""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file3.cs""]
|
||||
}
|
||||
},
|
||||
""configurations"": {
|
||||
""testconfig"": {
|
||||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
""include"": [""root"", ""src"", ""rootfile.cs""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
action.ShouldThrow<Exception>()
|
||||
.WithMessage(
|
||||
"MIGRATE20012::Configuration Exclude: Unable to migrate projects with excluded files in configurations.");
|
||||
}
|
||||
private ProjectRootElement RunConfigurationsRuleOnPj(string s, string testDirectory = null)
|
||||
{
|
||||
testDirectory = testDirectory ?? Temp.CreateDirectory().Path;
|
||||
return TemporaryProjectFileRuleRunner.RunRules(new[] {new MigrateConfigurationsRule()}, s, testDirectory);
|
||||
}
|
||||
|
||||
private ProjectRootElement RunConfigurationsAndBuildOptionsRuleOnPj(string s, string testDirectory = null)
|
||||
{
|
||||
testDirectory = testDirectory ?? Temp.CreateDirectory().Path;
|
||||
return TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[]
|
||||
{
|
||||
new MigrateBuildOptionsRule(),
|
||||
new MigrateConfigurationsRule()
|
||||
}, s, testDirectory);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
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.Migration.Tests
|
||||
{
|
||||
public class GivenThatIWantToMigrateProjectDependencies : TestBase
|
||||
{
|
||||
// Workaround For P2P dependencies
|
||||
// ISSUE: https://github.com/dotnet/sdk/issues/73
|
||||
[Fact]
|
||||
public void If_a_project_dependency_is_present_DesignTimeAutoUnify_and_AutoUnify_are_present()
|
||||
{
|
||||
var solutionDirectory =
|
||||
TestAssetsManager.CreateTestInstance("TestAppWithLibrary", callingMethod: "p").WithLockFiles().Path;
|
||||
|
||||
var appDirectory = Path.Combine(solutionDirectory, "TestApp");
|
||||
var libDirectory = Path.Combine(solutionDirectory, "TestLibrary");
|
||||
|
||||
var projectContext = ProjectContext.Create(appDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
|
||||
var mockProj = ProjectRootElement.Create();
|
||||
var testSettings = new MigrationSettings(appDirectory, appDirectory, "1.0.0", mockProj);
|
||||
var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(),
|
||||
mockProj.AddPropertyGroup());
|
||||
new MigrateProjectDependenciesRule().Apply(testSettings, testInputs);
|
||||
|
||||
var autoUnify = mockProj.Properties.Where(p => p.Name == "AutoUnify");
|
||||
autoUnify.Count().Should().Be(1);
|
||||
autoUnify.First().Value.Should().Be("true");
|
||||
|
||||
var designTimeAutoUnify = mockProj.Properties.Where(p => p.Name == "DesignTimeAutoUnify");
|
||||
designTimeAutoUnify.Count().Should().Be(1);
|
||||
designTimeAutoUnify.First().Value.Should().Be("true");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Project_dependencies_are_migrated_to_ProjectReference()
|
||||
{
|
||||
var solutionDirectory =
|
||||
TestAssetsManager.CreateTestInstance("TestAppWithLibrary", callingMethod: "p").WithLockFiles().Path;
|
||||
|
||||
var appDirectory = Path.Combine(solutionDirectory, "TestApp");
|
||||
|
||||
var projectContext = ProjectContext.Create(appDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
|
||||
var mockProj = ProjectRootElement.Create();
|
||||
var testSettings = new MigrationSettings(appDirectory, appDirectory, "1.0.0", mockProj);
|
||||
var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(),
|
||||
mockProj.AddPropertyGroup());
|
||||
new MigrateProjectDependenciesRule().Apply(testSettings, testInputs);
|
||||
|
||||
var projectReferences = mockProj.Items.Where(item => item.ItemType.Equals("ProjectReference", StringComparison.Ordinal));
|
||||
projectReferences.Count().Should().Be(1);
|
||||
|
||||
projectReferences.First().Include.Should().Be(Path.Combine("..", "TestLibrary", "TestLibrary.csproj"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_throws_when_project_dependency_is_unresolved()
|
||||
{
|
||||
// No Lock file => unresolved
|
||||
var solutionDirectory =
|
||||
TestAssetsManager.CreateTestInstance("TestAppWithLibrary").Path;
|
||||
|
||||
var appDirectory = Path.Combine(solutionDirectory, "TestApp");
|
||||
|
||||
var projectContext = ProjectContext.Create(appDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
|
||||
var mockProj = ProjectRootElement.Create();
|
||||
var testSettings = new MigrationSettings(appDirectory, appDirectory, "1.0.0", mockProj);
|
||||
var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(), mockProj.AddPropertyGroup());
|
||||
|
||||
Action action = () => new MigrateProjectDependenciesRule().Apply(testSettings, testInputs);
|
||||
action.ShouldThrow<Exception>()
|
||||
.Where(e => e.Message.Contains("MIGRATE1014::Unresolved Dependency: Unresolved project dependency (TestLibrary)"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Migration.Tests;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Files;
|
||||
using Microsoft.DotNet.TestFramework;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using NuGet.Frameworks;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Rules;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
||||
{
|
||||
public class GivenThatIWantToMigratePublishOptions : TestBase
|
||||
{
|
||||
[Fact]
|
||||
private void Migrating_publishOptions_include_exclude_populates_Content_item()
|
||||
{
|
||||
var testDirectory = Temp.CreateDirectory().Path;
|
||||
WriteFilesInProjectDirectory(testDirectory);
|
||||
|
||||
var mockProj = RunPublishOptionsRuleOnPj(@"
|
||||
{
|
||||
""publishOptions"": {
|
||||
""include"": [""root"", ""src"", ""rootfile.cs""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""]
|
||||
}
|
||||
}",
|
||||
testDirectory: testDirectory);
|
||||
|
||||
mockProj.Items.Count(i => i.ItemType.Equals("Content", StringComparison.Ordinal)).Should().Be(2);
|
||||
|
||||
foreach (var item in mockProj.Items.Where(i => i.ItemType.Equals("Content", StringComparison.Ordinal)))
|
||||
{
|
||||
item.Metadata.Count(m => m.Name == "CopyToPublishDirectory").Should().Be(1);
|
||||
|
||||
if (item.Include.Contains(@"src\file1.cs"))
|
||||
{
|
||||
item.Include.Should().Be(@"src\file1.cs;src\file2.cs");
|
||||
item.Exclude.Should().Be(@"src\file2.cs");
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Include.Should()
|
||||
.Be(@"root\**\*;src\**\*;rootfile.cs");
|
||||
|
||||
item.Exclude.Should()
|
||||
.Be(@"src\**\*;rootfile.cs;src\file2.cs");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
private void Migrating_publishOptions_and_buildOptions_CopyToOutput_merges_Content_items()
|
||||
{
|
||||
var testDirectory = Temp.CreateDirectory().Path;
|
||||
WriteFilesInProjectDirectory(testDirectory);
|
||||
|
||||
var mockProj = RunPublishAndBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
""include"": [""src"", ""rootfile.cs""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""]
|
||||
}
|
||||
},
|
||||
""publishOptions"": {
|
||||
""include"": [""root"", ""src"", ""rootfile.cs""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file3.cs""]
|
||||
}
|
||||
}",
|
||||
testDirectory: testDirectory);
|
||||
|
||||
Console.WriteLine(string.Join(";", mockProj.Items.Select(i => " ;; " + i.ItemType)));
|
||||
Console.WriteLine(string.Join(";", mockProj.Items.Select(i => " ;; " + i.Include)));
|
||||
Console.WriteLine(string.Join(";", mockProj.Items.Select(i => " ;; " + i.Exclude)));
|
||||
|
||||
mockProj.Items.Count(i => i.ItemType.Equals("Content", StringComparison.Ordinal)).Should().Be(3);
|
||||
|
||||
// From ProjectReader #L725 (Both are empty)
|
||||
var defaultIncludePatterns = Enumerable.Empty<string>();
|
||||
var defaultExcludePatterns = ProjectFilesCollection.DefaultPublishExcludePatterns;
|
||||
|
||||
foreach (var item in mockProj.Items.Where(i => i.ItemType.Equals("Content", StringComparison.Ordinal)))
|
||||
{
|
||||
if (item.Include.Contains(@"root\**\*"))
|
||||
{
|
||||
item.Include.Should().Be(@"root\**\*");
|
||||
item.Exclude.Should().Be(@"src\**\*;rootfile.cs;src\file3.cs");
|
||||
}
|
||||
else if (item.Include.Contains(@"src\file1.cs"))
|
||||
{
|
||||
item.Include.Should().Be(@"src\file1.cs;src\file2.cs");
|
||||
item.Exclude.Should().Be(@"src\file2.cs;src\file3.cs");
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Include.Should()
|
||||
.Be(@"src\**\*;rootfile.cs");
|
||||
|
||||
item.Exclude.Should()
|
||||
.Be(@"src\**\*;rootfile.cs;src\file2.cs;src\file3.cs");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteFilesInProjectDirectory(string testDirectory)
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(testDirectory, "root"));
|
||||
Directory.CreateDirectory(Path.Combine(testDirectory, "src"));
|
||||
File.WriteAllText(Path.Combine(testDirectory, "root", "file1.txt"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "root", "file2.txt"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "root", "file3.txt"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "src", "file1.cs"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "src", "file2.cs"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "src", "file3.cs"), "content");
|
||||
File.WriteAllText(Path.Combine(testDirectory, "rootfile.cs"), "content");
|
||||
}
|
||||
|
||||
private ProjectRootElement RunPublishOptionsRuleOnPj(string s, string testDirectory = null)
|
||||
{
|
||||
testDirectory = testDirectory ?? Temp.CreateDirectory().Path;
|
||||
return TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[]
|
||||
{
|
||||
new MigratePublishOptionsRule()
|
||||
}, s, testDirectory);
|
||||
}
|
||||
|
||||
private ProjectRootElement RunPublishAndBuildOptionsRuleOnPj(string s, string testDirectory = null)
|
||||
{
|
||||
testDirectory = testDirectory ?? Temp.CreateDirectory().Path;
|
||||
return TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[]
|
||||
{
|
||||
new MigrateBuildOptionsRule(),
|
||||
new MigratePublishOptionsRule()
|
||||
}, s, testDirectory);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
// 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 FluentAssertions;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Xunit;
|
||||
using Microsoft.DotNet.ProjectJsonMigration;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using NuGet.Frameworks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Rules;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
||||
{
|
||||
public class GivenThatIWantToMigrateRuntimeOptions : TestBase
|
||||
{
|
||||
private static readonly string s_runtimeConfigFileName = "runtimeconfig.template.json";
|
||||
|
||||
[Fact]
|
||||
public void RuntimeOptions_are_copied_from_projectJson_to_runtimeconfig_template_json_file()
|
||||
{
|
||||
var testInstance = TestAssetsManager.CreateTestInstance("TestAppWithRuntimeOptions").WithLockFiles();
|
||||
var projectDir = testInstance.Path;
|
||||
var projectPath = Path.Combine(testInstance.Path, "project.json");
|
||||
|
||||
var project = JObject.Parse(File.ReadAllText(projectPath));
|
||||
var rawRuntimeOptions = (JObject)project.GetValue("runtimeOptions");
|
||||
|
||||
var projectContext = ProjectContext.Create(projectDir, FrameworkConstants.CommonFrameworks.NetCoreApp10);
|
||||
|
||||
var testSettings = new MigrationSettings(projectDir, projectDir, "1.0.0", default(ProjectRootElement));
|
||||
var testInputs = new MigrationRuleInputs(new[] { projectContext }, null, null, null);
|
||||
new MigrateRuntimeOptionsRule().Apply(testSettings, testInputs);
|
||||
|
||||
var migratedRuntimeOptionsPath = Path.Combine(projectDir, s_runtimeConfigFileName);
|
||||
|
||||
File.Exists(migratedRuntimeOptionsPath).Should().BeTrue();
|
||||
Console.WriteLine(migratedRuntimeOptionsPath);
|
||||
|
||||
var migratedRuntimeOptionsContent = JObject.Parse(File.ReadAllText(migratedRuntimeOptionsPath));
|
||||
JToken.DeepEquals(rawRuntimeOptions, migratedRuntimeOptionsContent).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_ProjectJson_with_no_RuntimeOptions_produces_no_runtimeconfig_template_json_file()
|
||||
{
|
||||
var testInstance = TestAssetsManager.CreateTestInstance("TestAppSimple").WithLockFiles();
|
||||
var projectDir = testInstance.Path;
|
||||
|
||||
var projectContext = ProjectContext.Create(projectDir, FrameworkConstants.CommonFrameworks.NetCoreApp10);
|
||||
|
||||
var testSettings = new MigrationSettings(projectDir, projectDir, "1.0.0", default(ProjectRootElement));
|
||||
var testInputs = new MigrationRuleInputs(new[] { projectContext }, null, null, null);
|
||||
new MigrateRuntimeOptionsRule().Apply(testSettings, testInputs);
|
||||
|
||||
var migratedRuntimeOptionsPath = Path.Combine(projectDir, s_runtimeConfigFileName);
|
||||
|
||||
File.Exists(migratedRuntimeOptionsPath).Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
// 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 FluentAssertions;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Xunit;
|
||||
using Microsoft.DotNet.ProjectJsonMigration;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Rules;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
||||
{
|
||||
public class GivenThatIWantToMigrateScripts : TestBase
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("compile:FullTargetFramework", "$(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion)")]
|
||||
[InlineData("compile:Configuration", "$(Configuration)")]
|
||||
[InlineData("compile:OutputFile", "$(TargetPath)")]
|
||||
[InlineData("compile:OutputDir", "$(TargetDir)")]
|
||||
[InlineData("publish:ProjectPath", "$(MSBuildThisFileDirectory)")]
|
||||
[InlineData("publish:Configuration", "$(Configuration)")]
|
||||
[InlineData("publish:OutputPath", "$(TargetDir)")]
|
||||
[InlineData("publish:FullTargetFramework", "$(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion)")]
|
||||
[InlineData("project:Version", "$(Version)")]
|
||||
[InlineData("project:Name", "$(AssemblyName)")]
|
||||
[InlineData("project:Directory", "$(MSBuildProjectDirectory)")]
|
||||
[InlineData("publish:Runtime", "$(RuntimeIdentifier)")]
|
||||
public void Formatting_script_commands_replaces_variables_with_the_right_msbuild_properties(
|
||||
string variable,
|
||||
string msbuildReplacement)
|
||||
{
|
||||
var scriptMigrationRule = new MigrateScriptsRule();
|
||||
scriptMigrationRule.ReplaceScriptVariables($"%{variable}%").Should().Be(msbuildReplacement);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("compile:TargetFramework")]
|
||||
[InlineData("compile:ResponseFile")]
|
||||
[InlineData("compile:CompilerExitCode")]
|
||||
[InlineData("compile:RuntimeOutputDir")]
|
||||
[InlineData("compile:RuntimeIdentifier")]
|
||||
[InlineData("publish:TargetFramework")]
|
||||
public void Formatting_script_commands_throws_when_variable_is_unsupported(string unsupportedVariable)
|
||||
{
|
||||
var scriptMigrationRule = new MigrateScriptsRule();
|
||||
|
||||
Action formatScriptAction = () => scriptMigrationRule.ReplaceScriptVariables($"%{unsupportedVariable}%");
|
||||
formatScriptAction.ShouldThrow<Exception>()
|
||||
.Where(exc => exc.Message.Contains("is currently an unsupported script variable for project migration"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("precompile", "Build")]
|
||||
[InlineData("prepublish", "Publish")]
|
||||
public void Migrating_pre_scripts_populates_BeforeTargets_with_appropriate_target(string scriptName, string targetName)
|
||||
{
|
||||
var scriptMigrationRule = new MigrateScriptsRule();
|
||||
ProjectRootElement mockProj = ProjectRootElement.Create();
|
||||
var commands = new string[] { "fakecommand" };
|
||||
|
||||
var target = scriptMigrationRule.MigrateScriptSet(mockProj, mockProj.AddPropertyGroup(), commands, scriptName);
|
||||
|
||||
target.BeforeTargets.Should().Be(targetName);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("postcompile", "Build")]
|
||||
[InlineData("postpublish", "Publish")]
|
||||
public void Migrating_post_scripts_populates_AfterTargets_with_appropriate_target(string scriptName, string targetName)
|
||||
{
|
||||
var scriptMigrationRule = new MigrateScriptsRule();
|
||||
ProjectRootElement mockProj = ProjectRootElement.Create();
|
||||
var commands = new string[] { "fakecommand" };
|
||||
|
||||
var target = scriptMigrationRule.MigrateScriptSet(mockProj, mockProj.AddPropertyGroup(), commands, scriptName);
|
||||
|
||||
target.AfterTargets.Should().Be(targetName);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("precompile")]
|
||||
[InlineData("postcompile")]
|
||||
[InlineData("prepublish")]
|
||||
[InlineData("postpublish")]
|
||||
public void Migrating_scripts_with_multiple_commands_creates_Exec_task_for_each(string scriptName)
|
||||
{
|
||||
var scriptMigrationRule = new MigrateScriptsRule();
|
||||
ProjectRootElement mockProj = ProjectRootElement.Create();
|
||||
|
||||
var commands = new string[] { "fakecommand1", "fakecommand2", "mockcommand3" };
|
||||
var commandsInTask = commands.ToDictionary(c => c, c => false);
|
||||
|
||||
var target = scriptMigrationRule.MigrateScriptSet(mockProj, mockProj.AddPropertyGroup(), commands, scriptName);
|
||||
|
||||
foreach (var task in target.Tasks)
|
||||
{
|
||||
var taskCommand = task.GetParameter("Command");
|
||||
var originalCommandCandidates = commands.Where(c => taskCommand.Contains(c));
|
||||
originalCommandCandidates.Count().Should().Be(1);
|
||||
|
||||
var command = originalCommandCandidates.First();
|
||||
commandsInTask[command].Should().Be(false, "Expected to find each element from commands Array once");
|
||||
|
||||
commandsInTask[command] = true;
|
||||
}
|
||||
|
||||
commandsInTask.All(commandInTask => commandInTask.Value)
|
||||
.Should()
|
||||
.BeTrue("Expected each element from commands array to be found in a task");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("precompile")]
|
||||
[InlineData("postcompile")]
|
||||
[InlineData("prepublish")]
|
||||
[InlineData("postpublish")]
|
||||
public void Migrated_ScriptSet_has_Exec_and_replaces_variables(string scriptName)
|
||||
{
|
||||
var scriptMigrationRule = new MigrateScriptsRule();
|
||||
ProjectRootElement mockProj = ProjectRootElement.Create();
|
||||
|
||||
var commands = new string[] { "compile:FullTargetFramework", "compile:Configuration"};
|
||||
|
||||
var target = scriptMigrationRule.MigrateScriptSet(mockProj, mockProj.AddPropertyGroup(), commands, scriptName);
|
||||
target.Tasks.Count().Should().Be(commands.Length);
|
||||
|
||||
foreach (var task in target.Tasks)
|
||||
{
|
||||
var taskCommand = task.GetParameter("Command");
|
||||
var commandIndex = Array.IndexOf(commands, taskCommand);
|
||||
|
||||
commandIndex.Should().Be(-1, "Expected command array elements to be replaced by appropriate msbuild properties");
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("precompile")]
|
||||
[InlineData("postcompile")]
|
||||
[InlineData("prepublish")]
|
||||
[InlineData("postpublish")]
|
||||
public void Migrated_ScriptSet_has_two_MigratedScriptExtensionProperties_for_each_script(string scriptName)
|
||||
{
|
||||
var scriptMigrationRule = new MigrateScriptsRule();
|
||||
ProjectRootElement mockProj = ProjectRootElement.Create();
|
||||
|
||||
var commands = new string[] {"compile:FullTargetFramework", "compile:Configuration"};
|
||||
var propertyGroup = mockProj.AddPropertyGroup();
|
||||
var target = scriptMigrationRule.MigrateScriptSet(mockProj, propertyGroup, commands,
|
||||
scriptName);
|
||||
|
||||
Console.WriteLine(string.Join(";", propertyGroup.Properties.Select(n => n.Name)));
|
||||
propertyGroup.Properties.Count().Should().Be(commands.Length * 2);
|
||||
|
||||
var count = 0;
|
||||
foreach (var command in commands)
|
||||
{
|
||||
count += 1;
|
||||
var scriptExtensionProperties =
|
||||
propertyGroup.Properties.Where(p => p.Name.Contains($"MigratedScriptExtension_{scriptName}_{count}")).ToArray();
|
||||
|
||||
scriptExtensionProperties.All(p => p.Value == ".sh" || p.Value == ".cmd").Should().BeTrue();
|
||||
scriptExtensionProperties.Count().Should().Be(2);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("echo", ".\\echo$(MigratedScriptExtension_1)")]
|
||||
[InlineData("echo hello world", ".\\echo$(MigratedScriptExtension_1) hello world")]
|
||||
[InlineData("\"echo\"", ".\\\"echo$(MigratedScriptExtension_1)\"")]
|
||||
[InlineData("\"echo space\"", ".\\\"echo space$(MigratedScriptExtension_1)\"")]
|
||||
[InlineData("\"echo space\" other args", ".\\\"echo space$(MigratedScriptExtension_1)\" other args")]
|
||||
[InlineData("\"echo space\" \"other space\"", ".\\\"echo space$(MigratedScriptExtension_1)\" \"other space\"")]
|
||||
public void Migrated_ScriptSet_has_ScriptExtension_added_to_script_command(string scriptCommandline, string expectedOutputCommand)
|
||||
{
|
||||
var scriptMigrationRule = new MigrateScriptsRule();
|
||||
ProjectRootElement mockProj = ProjectRootElement.Create();
|
||||
|
||||
var formattedCommand = scriptMigrationRule.AddScriptExtensionPropertyToCommandLine(scriptCommandline,
|
||||
"MigratedScriptExtension_1");
|
||||
|
||||
formattedCommand.Should().Be(expectedOutputCommand);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("echo", @".\echo")]
|
||||
[InlineData("/usr/echo", "/usr/echo")]
|
||||
[InlineData(@"C:\usr\echo", @"C:\usr\echo")]
|
||||
[InlineData("\"echo\"", @".\""echo")]
|
||||
[InlineData("\"/usr/echo\"", @"""/usr/echo")]
|
||||
[InlineData(@"""C:\usr\echo", @"""C:\usr\echo")]
|
||||
public void Migrated_ScriptSet_has_dotSlash_prepended_when_command_is_not_rooted(string scriptCommandline,
|
||||
string expectedOutputCommandPrefix)
|
||||
{
|
||||
var scriptMigrationRule = new MigrateScriptsRule();
|
||||
ProjectRootElement mockProj = ProjectRootElement.Create();
|
||||
|
||||
var formattedCommand = scriptMigrationRule.FormatScriptCommand(scriptCommandline,
|
||||
"MigratedScriptExtension_1");
|
||||
|
||||
formattedCommand.Should().StartWith(expectedOutputCommandPrefix);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
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.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Rules;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
||||
{
|
||||
public class GivenThatIWantToMigrateProjectFramework : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void Migrating_netcoreapp_project_Populates_TargetFrameworkIdentifier_and_TargetFrameworkVersion()
|
||||
{
|
||||
var testDirectory = Temp.CreateDirectory().Path;
|
||||
var testPJ = new ProjectJsonBuilder(TestAssetsManager)
|
||||
.FromTestAssetBase("TestAppWithRuntimeOptions")
|
||||
.WithCustomProperty("buildOptions", new Dictionary<string, string>
|
||||
{
|
||||
{ "emitEntryPoint", "false" }
|
||||
})
|
||||
.SaveToDisk(testDirectory);
|
||||
|
||||
var projectContext = ProjectContext.Create(testDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
|
||||
var mockProj = ProjectRootElement.Create();
|
||||
|
||||
// Run BuildOptionsRule
|
||||
var testSettings = new MigrationSettings(testDirectory, testDirectory, "1.0.0", mockProj);
|
||||
var testInputs = new MigrationRuleInputs(new[] { projectContext }, mockProj, mockProj.AddItemGroup(), mockProj.AddPropertyGroup());
|
||||
new MigrateTFMRule().Apply(testSettings, testInputs);
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "TargetFrameworkIdentifier").Should().Be(1);
|
||||
mockProj.Properties.Count(p => p.Name == "TargetFrameworkVersion").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "TargetFrameworkIdentifier").Value.Should().Be(".NETCoreApp");
|
||||
mockProj.Properties.First(p => p.Name == "TargetFrameworkVersion").Value.Should().Be("v1.0");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Rules;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
||||
{
|
||||
public class TemporaryProjectFileRuleRunner
|
||||
{
|
||||
public static ProjectRootElement RunRules(IEnumerable<IMigrationRule> rules, string projectJson,
|
||||
string testDirectory)
|
||||
{
|
||||
var projectContext = GenerateProjectContextFromString(testDirectory, projectJson);
|
||||
return RunMigrationRulesOnGeneratedProject(rules, projectContext, testDirectory);
|
||||
}
|
||||
|
||||
private static ProjectContext GenerateProjectContextFromString(string projectDirectory, string json)
|
||||
{
|
||||
var testPj = new ProjectJsonBuilder(null)
|
||||
.FromStringBase(json)
|
||||
.SaveToDisk(projectDirectory);
|
||||
|
||||
return ProjectContext.Create(testPj, FrameworkConstants.CommonFrameworks.NetCoreApp10);
|
||||
}
|
||||
|
||||
private static ProjectRootElement RunMigrationRulesOnGeneratedProject(IEnumerable<IMigrationRule> rules,
|
||||
ProjectContext projectContext, string testDirectory)
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var testSettings = new MigrationSettings(testDirectory, testDirectory, "1.0.0", project);
|
||||
var testInputs = new MigrationRuleInputs(new[] {projectContext}, project,
|
||||
project.AddItemGroup(),
|
||||
project.AddPropertyGroup());
|
||||
|
||||
foreach (var rule in rules)
|
||||
{
|
||||
rule.Apply(testSettings, testInputs);
|
||||
}
|
||||
|
||||
return project;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using Microsoft.DotNet.ProjectJsonMigration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
||||
{
|
||||
public class GivenAConditionalTransform
|
||||
{
|
||||
[Fact]
|
||||
public void It_returns_null_when_condition_is_false()
|
||||
{
|
||||
var conditionalTransform = new TestConditionalTransform(t => false);
|
||||
conditionalTransform.Transform("astring").Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_returns_result_of_ConditionallyTransform_when_condition_is_true()
|
||||
{
|
||||
var conditionalTransform = new TestConditionalTransform(t => true);
|
||||
|
||||
var property = conditionalTransform.Transform("astring");
|
||||
property.Should().NotBeNull();
|
||||
property.Name.Should().Be("astring");
|
||||
property.Value.Should().Be("astring");
|
||||
}
|
||||
|
||||
private class TestConditionalTransform : ConditionalTransform<string, ProjectPropertyElement>
|
||||
{
|
||||
public TestConditionalTransform(Func<string, bool> condition) : base(condition) { }
|
||||
|
||||
public override ProjectPropertyElement ConditionallyTransform(string source)
|
||||
{
|
||||
var property = ProjectRootElement.Create().CreatePropertyElement(source);
|
||||
property.Value = source;
|
||||
return property;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
using Microsoft.Build.Construction;
|
||||
using Xunit;
|
||||
using Xunit.Runner.DotNet;
|
||||
using FluentAssertions;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Models;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Tests.Transforms
|
||||
{
|
||||
public class GivenATransformApplicator
|
||||
{
|
||||
[Fact]
|
||||
public void It_merges_Metadata_and_Exclude_with_items_with_same_ItemType_and_Include_when_mergeExisting_is_true()
|
||||
{
|
||||
var metadata = new ItemMetadataValue<string>[]
|
||||
{
|
||||
new ItemMetadataValue<string>("metadata1", "value1"),
|
||||
new ItemMetadataValue<string>("metadata2", "value2")
|
||||
};
|
||||
|
||||
var fullItemTransformSetIncludeValue = "include1;include2";
|
||||
|
||||
var transform1 = new AddItemTransform<string>("item",
|
||||
fullItemTransformSetIncludeValue,
|
||||
"exclude1",
|
||||
t => true)
|
||||
.WithMetadata(metadata[0]);
|
||||
|
||||
var transform2 = new AddItemTransform<string>("item",
|
||||
fullItemTransformSetIncludeValue,
|
||||
"exclude2",
|
||||
t => true)
|
||||
.WithMetadata(metadata[1]);
|
||||
|
||||
var mockProj = ProjectRootElement.Create();
|
||||
var itemGroup = mockProj.AddItemGroup();
|
||||
|
||||
var item1 = transform1.Transform("_");
|
||||
item1.AddMetadata(metadata[0].MetadataName, metadata[0].GetMetadataValue(null));
|
||||
|
||||
var item2 = transform2.Transform("_");
|
||||
item2.AddMetadata(metadata[1].MetadataName, metadata[1].GetMetadataValue(null));
|
||||
|
||||
var transformApplicator = new TransformApplicator();
|
||||
transformApplicator.Execute(new ProjectItemElement[] {item1, item2}, itemGroup, mergeExisting:true);
|
||||
|
||||
itemGroup.Items.Count.Should().Be(1);
|
||||
|
||||
var item = itemGroup.Items.First();
|
||||
item.Exclude.Should().Be("exclude1;exclude2");
|
||||
|
||||
item.Metadata.Count().Should().Be(2);
|
||||
var foundMetadata = metadata.ToDictionary<ItemMetadataValue<string>, string, bool>(m => m.MetadataName,
|
||||
m => false);
|
||||
|
||||
foreach (var metadataEntry in item.Metadata)
|
||||
{
|
||||
foundMetadata.Should().ContainKey(metadataEntry.Name);
|
||||
foundMetadata[metadataEntry.Name].Should().BeFalse();
|
||||
foundMetadata[metadataEntry.Name] = true;
|
||||
}
|
||||
|
||||
foundMetadata.All(kv => kv.Value).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectJsonMigration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Models;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
|
||||
|
||||
namespace Microsoft.DotNet.Migration.Tests
|
||||
{
|
||||
public class GivenAnAddItemTransform
|
||||
{
|
||||
[Fact]
|
||||
public void It_returns_an_item_with_Include_Exclude_and_Metadata_to_project_when_condition_is_true()
|
||||
{
|
||||
var itemTransforms = GetFullItemTransformSet(true);
|
||||
|
||||
foreach (var transform in itemTransforms)
|
||||
{
|
||||
var item = transform.Transform("_");
|
||||
|
||||
item.Should().NotBeNull();
|
||||
item.Include.Should().Be(FullItemTransformSetIncludeValue);
|
||||
item.Exclude.Should().Be(FullItemTransformSetExcludeValue);
|
||||
|
||||
item.HasMetadata.Should().BeTrue();
|
||||
|
||||
var metadata = item.Metadata.First();
|
||||
metadata.Name.Should().Be(FullItemTransformSetMetadataName);
|
||||
metadata.Value.Should().Be(FullItemTransformSetMetadataValue);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_returns_null_when_condition_is_false()
|
||||
{
|
||||
var itemTransforms = GetFullItemTransformSet(false);
|
||||
|
||||
foreach (var transform in itemTransforms)
|
||||
{
|
||||
transform.Transform("_").Should().BeNull();
|
||||
}
|
||||
}
|
||||
|
||||
private static string FullItemTransformSetItemNamePrefix => "item";
|
||||
private static string FullItemTransformSetIncludeValue => "include1;include2";
|
||||
private static string FullItemTransformSetExcludeValue => "exclude1;exclude2";
|
||||
private static string FullItemTransformSetMetadataName => "SomeName";
|
||||
private static string FullItemTransformSetMetadataValue => "SomeValue";
|
||||
|
||||
private AddItemTransform<string>[] GetFullItemTransformSet(bool condition)
|
||||
{
|
||||
return new AddItemTransform<string>[]
|
||||
{
|
||||
new AddItemTransform<string>(FullItemTransformSetItemNamePrefix + "1",
|
||||
FullItemTransformSetIncludeValue.Split(';'),
|
||||
FullItemTransformSetExcludeValue.Split(';'),
|
||||
t => condition)
|
||||
.WithMetadata(FullItemTransformSetMetadataName, FullItemTransformSetMetadataValue),
|
||||
new AddItemTransform<string>(FullItemTransformSetItemNamePrefix + "2",
|
||||
t => FullItemTransformSetIncludeValue,
|
||||
t => FullItemTransformSetExcludeValue,
|
||||
t => condition)
|
||||
.WithMetadata(FullItemTransformSetMetadataName, t => FullItemTransformSetMetadataValue),
|
||||
new AddItemTransform<string>(FullItemTransformSetItemNamePrefix + "3",
|
||||
FullItemTransformSetIncludeValue,
|
||||
t => FullItemTransformSetExcludeValue,
|
||||
t => condition)
|
||||
.WithMetadata(new ItemMetadataValue<string>(FullItemTransformSetMetadataName, FullItemTransformSetMetadataValue)),
|
||||
new AddItemTransform<string>(FullItemTransformSetItemNamePrefix + "4",
|
||||
t => FullItemTransformSetIncludeValue,
|
||||
FullItemTransformSetExcludeValue,
|
||||
t => condition)
|
||||
.WithMetadata(new ItemMetadataValue<string>(FullItemTransformSetMetadataName, t => FullItemTransformSetMetadataValue)),
|
||||
new AddItemTransform<string>(FullItemTransformSetItemNamePrefix + "5",
|
||||
FullItemTransformSetIncludeValue,
|
||||
FullItemTransformSetExcludeValue,
|
||||
t => condition)
|
||||
.WithMetadata(FullItemTransformSetMetadataName, FullItemTransformSetMetadataValue)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.ProjectJsonMigration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
|
||||
|
||||
namespace Microsoft.DotNet.Migration.Tests
|
||||
{
|
||||
public class GivenAnAddPropertyTransform
|
||||
{
|
||||
[Fact]
|
||||
public void It_returns_a_property_with_specified_value()
|
||||
{
|
||||
var propertyName = "Property1";
|
||||
var propertyValue = "Value1";
|
||||
|
||||
var propertyTransform = new AddPropertyTransform<string>(propertyName, propertyValue, t=>true);
|
||||
var property = propertyTransform.Transform("_");
|
||||
|
||||
property.Name.Should().Be(propertyName);
|
||||
property.Value.Should().Be(propertyValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_returns_a_property_with_computed_value()
|
||||
{
|
||||
var propertyName = "Property1";
|
||||
var propertyValue = "Value1";
|
||||
|
||||
var propertyTransform = new AddPropertyTransform<string>(propertyName, t => t.ToUpper(), t => true);
|
||||
var property = propertyTransform.Transform(propertyValue);
|
||||
|
||||
property.Name.Should().Be(propertyName);
|
||||
property.Value.Should().Be(propertyValue.ToUpper());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_returns_null_when_condition_is_false()
|
||||
{
|
||||
var propertyName = "Property1";
|
||||
var propertyValue = "Value1";
|
||||
|
||||
var propertyTransform = new AddPropertyTransform<string>(propertyName, propertyValue, t => false);
|
||||
propertyTransform.Transform(propertyValue).Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_returns_a_property_when_source_is_null_and_propertyValue_is_a_string()
|
||||
{
|
||||
var propertyName = "Property1";
|
||||
var propertyValue = "Value1";
|
||||
|
||||
var propertyTransform = new AddPropertyTransform<string>(
|
||||
propertyName,
|
||||
propertyValue,
|
||||
t => true);
|
||||
var property = propertyTransform.Transform(null);
|
||||
property.Should().NotBeNull();
|
||||
property.Value.Should().Be(propertyValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_returns_a_property_when_source_is_null_and_propertyValue_is_a_Func_that_handles_null()
|
||||
{
|
||||
var propertyName = "Property1";
|
||||
var propertyValue = "Value1";
|
||||
|
||||
var propertyTransform = new AddPropertyTransform<string>(
|
||||
propertyName,
|
||||
t=> t == null ? propertyValue.ToUpper() : propertyValue.ToLower(),
|
||||
t => true);
|
||||
var property = propertyTransform.Transform(null);
|
||||
property.Value.Should().Be(propertyValue.ToUpper());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_throws_when_source_is_null_and_propertyValue_is_a_Func_that_doesnt_handle_null()
|
||||
{
|
||||
var propertyName = "Property1";
|
||||
|
||||
var propertyTransform = new AddPropertyTransform<string>(
|
||||
propertyName,
|
||||
t => t.ToUpper(),
|
||||
t => true);
|
||||
|
||||
Action transform = () => propertyTransform.Transform(null);
|
||||
transform.ShouldThrow<Exception>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
|
||||
|
||||
namespace Microsoft.DotNet.Migration.Tests
|
||||
{
|
||||
public class GivenAnIncludeContextTransformation
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"buildOptions": {
|
||||
"copyToOutput": ["MSBuild.exe", "MSBuild.exe.config"]
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"Microsoft.DotNet.ProjectJsonMigration": {
|
||||
"target": "project"
|
||||
},
|
||||
"xunit": "2.2.0-beta3-build3330",
|
||||
"dotnet-test-xunit": "1.0.0-rc2-318883-21",
|
||||
"FluentAssertions": "4.0.0",
|
||||
"moq.netcore": "4.4.0-beta8",
|
||||
"Microsoft.DotNet.Tools.Tests.Utilities": {
|
||||
"target": "project"
|
||||
},
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"target": "project"
|
||||
},
|
||||
"dotnet": {
|
||||
"target":"project"
|
||||
}
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [
|
||||
"netstandardapp1.5",
|
||||
"dotnet5.4",
|
||||
"portable-net451+win8"
|
||||
]
|
||||
}
|
||||
},
|
||||
"testRunner": "xunit"
|
||||
}
|
|
@ -18,5 +18,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
args = $"new {args}";
|
||||
return base.Execute(args);
|
||||
}
|
||||
|
||||
public override CommandResult ExecuteWithCapturedOutput(string args = "")
|
||||
{
|
||||
args = $"new {args}";
|
||||
return base.ExecuteWithCapturedOutput(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
253
test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs
Normal file
253
test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs
Normal file
|
@ -0,0 +1,253 @@
|
|||
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.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using Microsoft.DotNet.Tools.Migrate;
|
||||
using Build3Command = Microsoft.DotNet.Tools.Test.Utilities.Build3Command;
|
||||
|
||||
namespace Microsoft.DotNet.Migration.Tests
|
||||
{
|
||||
public class GivenThatIWantToMigrateTestApps : TestBase
|
||||
{
|
||||
[Theory]
|
||||
// TODO: Standalone apps [InlineData("TestAppSimple", false)]
|
||||
// https://github.com/dotnet/sdk/issues/73 [InlineData("TestAppWithLibrary/TestApp", false)]
|
||||
[InlineData("TestAppWithRuntimeOptions")]
|
||||
public void It_migrates_apps(string projectName)
|
||||
{
|
||||
var projectDirectory = TestAssetsManager.CreateTestInstance(projectName, callingMethod: "i").WithLockFiles().Path;
|
||||
var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory);
|
||||
|
||||
var outputsIdentical =
|
||||
outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
||||
if (!outputsIdentical)
|
||||
{
|
||||
OutputDiagnostics(outputComparisonData);
|
||||
}
|
||||
outputsIdentical.Should().BeTrue();
|
||||
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_migrates_dotnet_new_console_with_identical_outputs()
|
||||
{
|
||||
var projectDirectory = Temp.CreateDirectory().Path;
|
||||
var outputComparisonData = GetDotnetNewComparisonData(projectDirectory, "console");
|
||||
|
||||
var outputsIdentical =
|
||||
outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
||||
if (!outputsIdentical)
|
||||
{
|
||||
OutputDiagnostics(outputComparisonData);
|
||||
}
|
||||
outputsIdentical.Should().BeTrue();
|
||||
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
// Outputs Not Identical: https://github.com/dotnet/sdk/issues/97
|
||||
public void It_migrates_dotnet_new_web_with_outputs_containing_project_json_outputs()
|
||||
{
|
||||
var projectDirectory = Temp.CreateDirectory().Path;
|
||||
var outputComparisonData = GetDotnetNewComparisonData(projectDirectory, "web");
|
||||
|
||||
var projectJsonOutputIsSubsetOfMSBuildOutput =
|
||||
outputComparisonData.ProjectJsonBuildOutputs.IsProperSubsetOf(outputComparisonData.MSBuildBuildOutputs);
|
||||
if (!projectJsonOutputIsSubsetOfMSBuildOutput)
|
||||
{
|
||||
OutputDiagnostics(outputComparisonData);
|
||||
}
|
||||
projectJsonOutputIsSubsetOfMSBuildOutput.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("TestAppWithLibrary/TestLibrary")]
|
||||
[InlineData("TestLibraryWithAnalyzer")]
|
||||
[InlineData("TestLibraryWithConfiguration")]
|
||||
public void It_migrates_a_library(string projectName)
|
||||
{
|
||||
var projectDirectory =
|
||||
TestAssetsManager.CreateTestInstance(projectName, callingMethod: "i").WithLockFiles().Path;
|
||||
var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory);
|
||||
|
||||
var msBuildHasAdditionalOutputsButIncludesProjectJsonOutputs =
|
||||
outputComparisonData.ProjectJsonBuildOutputs.IsProperSubsetOf(outputComparisonData.MSBuildBuildOutputs);
|
||||
|
||||
if (!msBuildHasAdditionalOutputsButIncludesProjectJsonOutputs)
|
||||
{
|
||||
OutputDiagnostics(outputComparisonData);
|
||||
}
|
||||
|
||||
msBuildHasAdditionalOutputsButIncludesProjectJsonOutputs.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_migrates_an_app_with_scripts_and_the_scripts_run()
|
||||
{
|
||||
var projectDirectory =
|
||||
TestAssetsManager.CreateTestInstance("TestAppWithMigrateableScripts", callingMethod: "i").WithLockFiles().Path;
|
||||
|
||||
BuildProjectJson(projectDirectory);
|
||||
var projectJsonBuildOutputs = new HashSet<string>(CollectBuildOutputs(projectDirectory));
|
||||
CleanBinObj(projectDirectory);
|
||||
|
||||
MigrateProject(projectDirectory);
|
||||
Restore(projectDirectory);
|
||||
var msBuildStdOut = BuildMSBuild(projectDirectory);
|
||||
|
||||
var msbuildBuildOutputs = new HashSet<string>(CollectBuildOutputs(projectDirectory));
|
||||
|
||||
var outputsIdentical = projectJsonBuildOutputs.SetEquals(msbuildBuildOutputs);
|
||||
outputsIdentical.Should().BeTrue();
|
||||
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
||||
|
||||
var outputDir =
|
||||
PathUtility.EnsureTrailingSlash(Path.Combine(projectDirectory, "bin", "Debug", "netcoreapp1.0"));
|
||||
|
||||
msBuildStdOut.Should().Contain($"precompile_output ?Debug? ?{outputDir}? ?.NETCoreApp,Version=v1.0?");
|
||||
msBuildStdOut.Should().Contain($"postcompile_output ?Debug? ?{outputDir}? ?.NETCoreApp,Version=v1.0?");
|
||||
}
|
||||
|
||||
private MigratedBuildComparisonData GetDotnetNewComparisonData(string projectDirectory, string dotnetNewType)
|
||||
{
|
||||
DotnetNew(projectDirectory, dotnetNewType);
|
||||
Restore(projectDirectory);
|
||||
|
||||
var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory);
|
||||
return outputComparisonData;
|
||||
}
|
||||
|
||||
private void VerifyAllMSBuildOutputsRunnable(string projectDirectory)
|
||||
{
|
||||
var dllFileName = Path.GetFileName(projectDirectory) + ".dll";
|
||||
|
||||
var runnableDlls = Directory.EnumerateFiles(Path.Combine(projectDirectory, "bin"), dllFileName,
|
||||
SearchOption.AllDirectories);
|
||||
|
||||
foreach (var dll in runnableDlls)
|
||||
{
|
||||
new TestCommand("dotnet").ExecuteWithCapturedOutput(dll).Should().Pass();
|
||||
}
|
||||
}
|
||||
|
||||
private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory)
|
||||
{
|
||||
BuildProjectJson(projectDirectory);
|
||||
var projectJsonBuildOutputs = new HashSet<string>(CollectBuildOutputs(projectDirectory));
|
||||
CleanBinObj(projectDirectory);
|
||||
|
||||
MigrateProject(projectDirectory);
|
||||
Restore(projectDirectory);
|
||||
BuildMSBuild(projectDirectory);
|
||||
|
||||
var msbuildBuildOutputs = new HashSet<string>(CollectBuildOutputs(projectDirectory));
|
||||
|
||||
return new MigratedBuildComparisonData(projectJsonBuildOutputs, msbuildBuildOutputs);
|
||||
}
|
||||
|
||||
private IEnumerable<string> CollectBuildOutputs(string projectDirectory)
|
||||
{
|
||||
var fullBinPath = Path.GetFullPath(Path.Combine(projectDirectory, "bin"));
|
||||
|
||||
return Directory.EnumerateFiles(fullBinPath, "*", SearchOption.AllDirectories)
|
||||
.Select(p => Path.GetFullPath(p).Substring(fullBinPath.Length));
|
||||
}
|
||||
|
||||
private void CleanBinObj(string projectDirectory)
|
||||
{
|
||||
var dirs = new string[] { Path.Combine(projectDirectory, "bin"), Path.Combine(projectDirectory, "obj") };
|
||||
|
||||
foreach (var dir in dirs)
|
||||
{
|
||||
Directory.Delete(dir, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildProjectJson(string projectDirectory)
|
||||
{
|
||||
var projectFile = Path.Combine(projectDirectory, "project.json");
|
||||
var result = new BuildCommand(projectPath: projectFile)
|
||||
.ExecuteWithCapturedOutput();
|
||||
|
||||
result.Should().Pass();
|
||||
}
|
||||
|
||||
private void MigrateProject(string projectDirectory)
|
||||
{
|
||||
var result =
|
||||
MigrateCommand.Run(new [] { "-p", projectDirectory });
|
||||
|
||||
result.Should().Be(0);
|
||||
}
|
||||
|
||||
private void DotnetNew(string projectDirectory, string dotnetNewType)
|
||||
{
|
||||
new NewCommand().WithWorkingDirectory(projectDirectory)
|
||||
.ExecuteWithCapturedOutput($"-t {dotnetNewType}")
|
||||
.Should()
|
||||
.Pass();
|
||||
}
|
||||
|
||||
private void Restore(string projectDirectory)
|
||||
{
|
||||
new TestCommand("dotnet")
|
||||
.WithWorkingDirectory(projectDirectory)
|
||||
.Execute("restore")
|
||||
.Should()
|
||||
.Pass();
|
||||
}
|
||||
|
||||
private string BuildMSBuild(string projectDirectory, string configuration="Debug")
|
||||
{
|
||||
var result = new Build3Command()
|
||||
.WithWorkingDirectory(projectDirectory)
|
||||
.ExecuteWithCapturedOutput($"/p:Configuration={configuration}");
|
||||
|
||||
result
|
||||
.Should()
|
||||
.Pass();
|
||||
|
||||
return result.StdOut;
|
||||
}
|
||||
|
||||
private void OutputDiagnostics(MigratedBuildComparisonData comparisonData)
|
||||
{
|
||||
OutputDiagnostics(comparisonData.MSBuildBuildOutputs, comparisonData.ProjectJsonBuildOutputs);
|
||||
}
|
||||
|
||||
private void OutputDiagnostics(HashSet<string> msbuildBuildOutputs, HashSet<string> projectJsonBuildOutputs)
|
||||
{
|
||||
Console.WriteLine("Project.json Outputs:");
|
||||
Console.WriteLine(string.Join("\n", projectJsonBuildOutputs));
|
||||
|
||||
Console.WriteLine("");
|
||||
|
||||
Console.WriteLine("MSBuild Outputs:");
|
||||
Console.WriteLine(string.Join("\n", msbuildBuildOutputs));
|
||||
}
|
||||
|
||||
private class MigratedBuildComparisonData
|
||||
{
|
||||
public HashSet<string> ProjectJsonBuildOutputs { get; }
|
||||
public HashSet<string> MSBuildBuildOutputs { get; }
|
||||
|
||||
public MigratedBuildComparisonData(HashSet<string> projectJsonBuildOutputs,
|
||||
HashSet<string> msBuildBuildOutputs)
|
||||
{
|
||||
ProjectJsonBuildOutputs = projectJsonBuildOutputs;
|
||||
MSBuildBuildOutputs = msBuildBuildOutputs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
test/dotnet-migrate.Tests/MSBuild.exe
Normal file
1
test/dotnet-migrate.Tests/MSBuild.exe
Normal file
|
@ -0,0 +1 @@
|
|||
https://github.com/Microsoft/msbuild/issues/927
|
1
test/dotnet-migrate.Tests/MSBuild.exe.config
Normal file
1
test/dotnet-migrate.Tests/MSBuild.exe.config
Normal file
|
@ -0,0 +1 @@
|
|||
https://github.com/Microsoft/msbuild/issues/927
|
21
test/dotnet-migrate.Tests/dotnet-migrate.Tests.xproj
Normal file
21
test/dotnet-migrate.Tests/dotnet-migrate.Tests.xproj
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>1F2EF070-AC5F-4078-AFB0-65745AC691B9</ProjectGuid>
|
||||
<RootNamespace>Microsoft.DotNet.ProjectJsonMigration.Tests</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
39
test/dotnet-migrate.Tests/project.json
Normal file
39
test/dotnet-migrate.Tests/project.json
Normal file
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"buildOptions": {
|
||||
"copyToOutput": ["MSBuild.exe", "MSBuild.exe.config"]
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"Microsoft.DotNet.ProjectJsonMigration": {
|
||||
"target": "project"
|
||||
},
|
||||
"xunit": "2.2.0-beta3-build3330",
|
||||
"dotnet-test-xunit": "1.0.0-rc2-318883-21",
|
||||
"FluentAssertions": "4.0.0",
|
||||
"moq.netcore": "4.4.0-beta8",
|
||||
"Microsoft.DotNet.Tools.Tests.Utilities": {
|
||||
"target": "project"
|
||||
},
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"target": "project"
|
||||
},
|
||||
"dotnet": {
|
||||
"target":"project"
|
||||
}
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [
|
||||
"netstandardapp1.5",
|
||||
"dotnet5.4",
|
||||
"portable-net451+win8"
|
||||
]
|
||||
}
|
||||
},
|
||||
"testRunner": "xunit"
|
||||
}
|
Loading…
Reference in a new issue