diff --git a/Directory.Build.props b/Directory.Build.props
index d3ca50c..7a32adb 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -10,7 +10,7 @@
Copyright Hans van Bakel
Tool for converting a MSBuild project file to VS2017 format and beyond.
dotnet csproj fsproj vbproj msbuild conversion vs2015 vs14 vs15 vs2017
- 4.1.0-beta.4
+ 4.1.0-beta.5
4.1.0.0
diff --git a/Project2015To2017.Core/Definition/Project.cs b/Project2015To2017.Core/Definition/Project.cs
index fbd54c4..ec130d7 100644
--- a/Project2015To2017.Core/Definition/Project.cs
+++ b/Project2015To2017.Core/Definition/Project.cs
@@ -88,5 +88,35 @@ public DirectoryInfo NuGetPackagesPath
public IReadOnlyList AssemblyAttributeProperties { get; set; } = Array.Empty();
public IReadOnlyList IntermediateOutputPaths { get; set; }
+
+ private sealed class ProjectNameFilePathEqualityComparer : IEqualityComparer
+ {
+ public bool Equals(Project x, Project y)
+ {
+ if (ReferenceEquals(x, y)) return true;
+ if (x is null) return false;
+ if (y is null) return false;
+ if (x.GetType() != y.GetType()) return false;
+ return string.Equals(x.ProjectName, y.ProjectName, StringComparison.InvariantCultureIgnoreCase) &&
+ string.Equals(x.FilePath.FullName, y.FilePath.FullName,
+ StringComparison.InvariantCultureIgnoreCase);
+ }
+
+ public int GetHashCode(Project obj)
+ {
+ var a = obj.ProjectName != null
+ ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(obj.ProjectName)
+ : 0;
+ var b = obj.FilePath != null
+ ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(obj.FilePath.FullName)
+ : 0;
+ unchecked
+ {
+ return (a * 397) ^ b;
+ }
+ }
+ }
+
+ public static IEqualityComparer ProjectNameFilePathComparer { get; } = new ProjectNameFilePathEqualityComparer();
}
}
diff --git a/Project2015To2017.Core/Definition/Solution.cs b/Project2015To2017.Core/Definition/Solution.cs
index 87ab9d5..a603689 100644
--- a/Project2015To2017.Core/Definition/Solution.cs
+++ b/Project2015To2017.Core/Definition/Solution.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.IO;
using NuGet.Configuration;
@@ -31,5 +32,24 @@ public DirectoryInfo NuGetPackagesPath
return new DirectoryInfo(Extensions.MaybeAdjustFilePath(path, solutionFolder));
}
}
+
+ private sealed class FilePathEqualityComparer : IEqualityComparer
+ {
+ public bool Equals(Solution x, Solution y)
+ {
+ if (ReferenceEquals(x, y)) return true;
+ if (x is null) return false;
+ if (y is null) return false;
+ if (x.GetType() != y.GetType()) return false;
+ return string.Equals(x.FilePath.FullName, y.FilePath.FullName, StringComparison.InvariantCultureIgnoreCase);
+ }
+
+ public int GetHashCode(Solution obj)
+ {
+ return (obj.FilePath != null ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(obj.FilePath.FullName) : 0);
+ }
+ }
+
+ public static IEqualityComparer FilePathComparer { get; } = new FilePathEqualityComparer();
}
}
diff --git a/Project2015To2017.Core/Extensions.cs b/Project2015To2017.Core/Extensions.cs
index aba6392..d4a1eef 100644
--- a/Project2015To2017.Core/Extensions.cs
+++ b/Project2015To2017.Core/Extensions.cs
@@ -1,12 +1,7 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
using System.Xml.Linq;
-using Microsoft.Extensions.Logging;
-using Project2015To2017.Transforms;
namespace Project2015To2017
{
diff --git a/Project2015To2017.Core/Transforms/BasicSimplifyTransformationSet.cs b/Project2015To2017.Core/Transforms/BasicSimplifyTransformationSet.cs
index 4e876b8..4cc229b 100644
--- a/Project2015To2017.Core/Transforms/BasicSimplifyTransformationSet.cs
+++ b/Project2015To2017.Core/Transforms/BasicSimplifyTransformationSet.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Text;
using Microsoft.Extensions.Logging;
namespace Project2015To2017.Transforms
@@ -22,6 +21,7 @@ public IReadOnlyCollection Transformations(
{
new PropertyDeduplicationTransformation(),
new PropertySimplificationTransformation(targetVisualStudioVersion),
+ new ServiceFilterTransformation(targetVisualStudioVersion),
new PrimaryProjectPropertiesUpdateTransformation(),
new EmptyGroupRemoveTransformation(),
};
diff --git a/Project2015To2017.Core/Transforms/PropertySimplificationTransformation.cs b/Project2015To2017.Core/Transforms/PropertySimplificationTransformation.cs
index 494c454..6b33557 100644
--- a/Project2015To2017.Core/Transforms/PropertySimplificationTransformation.cs
+++ b/Project2015To2017.Core/Transforms/PropertySimplificationTransformation.cs
@@ -9,7 +9,7 @@
namespace Project2015To2017.Transforms
{
- public sealed class PropertySimplificationTransformation : ILegacyOnlyProjectTransformation
+ public sealed class PropertySimplificationTransformation : ITransformation
{
private static readonly string[] IgnoreProjectNameValues =
{
@@ -17,16 +17,7 @@ public sealed class PropertySimplificationTransformation : ILegacyOnlyProjectTra
"$(ProjectName)"
};
- private static readonly string[] KnownTestFrameworkIds =
- {
- "Microsoft.NET.Test.Sdk",
- "xUnit.Core",
- "xUnit",
- "NUnit",
- };
-
private readonly Version targetVisualStudioVersion;
- private static readonly Version Vs15TestServiceFixVersion = new Version(15, 7);
public PropertySimplificationTransformation(Version targetVisualStudioVersion = null)
{
@@ -196,7 +187,6 @@ when ValidateDefaultValue("{fae04ec0-301f-11d3-bf4b-00c04f79efbc}"):
case "AssemblyName" when IsDefaultProjectNameValued():
case "TargetName" when IsDefaultProjectNameValued():
case "ProjectGuid" when ProjectGuidMatchesSolutionProjectGuid():
- case "Service" when IncludeMatchesSpecificGuid():
{
removeQueue.Add(child);
break;
@@ -273,24 +263,6 @@ bool IsDefaultProjectNameValued()
IgnoreProjectNameValues.Contains(child.Value)
);
}
-
- bool IncludeMatchesSpecificGuid()
- {
- // This is not required as of VS15.7 and above, but we might target VS15.0
- if (targetVisualStudioVersion < Vs15TestServiceFixVersion)
- if (!project.PackageReferences.Any(IsKnownTestProvider))
- return false;
-
- return child.Attribute("Include")?.Value == "{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}";
-
- bool IsKnownTestProvider(PackageReference x)
- {
- // In theory, we should be checking versions of these test frameworks
- // to see, if they have the fix included.
-
- return KnownTestFrameworkIds.Contains(x.Id);
- }
- }
}
// we cannot remove elements correctly while iterating through elements, 2nd pass is needed
diff --git a/Project2015To2017.Core/Transforms/ServiceFilterTransformation.cs b/Project2015To2017.Core/Transforms/ServiceFilterTransformation.cs
new file mode 100644
index 0000000..eebde78
--- /dev/null
+++ b/Project2015To2017.Core/Transforms/ServiceFilterTransformation.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Linq;
+using System.Xml.Linq;
+using Project2015To2017.Definition;
+
+namespace Project2015To2017.Transforms
+{
+ public sealed class ServiceFilterTransformation : ITransformation
+ {
+ private static readonly string[] KnownTestFrameworkIds =
+ {
+ "Microsoft.NET.Test.Sdk",
+ "xUnit.Core",
+ "xUnit",
+ "NUnit",
+ };
+
+ private static readonly Version Vs15TestServiceFixVersion = new Version(15, 7);
+
+ private readonly Version targetVisualStudioVersion;
+
+ public ServiceFilterTransformation(Version targetVisualStudioVersion)
+ {
+ this.targetVisualStudioVersion = targetVisualStudioVersion ?? throw new ArgumentNullException(nameof(targetVisualStudioVersion));
+ }
+
+ public void Transform(Project definition)
+ {
+ var removeQueue = definition.ItemGroups.ElementsAnyNamespace("Service").Where(IncludeMatchesSpecificGuid).ToArray();
+
+ foreach (var element in removeQueue)
+ {
+ element.Remove();
+ }
+
+ bool IncludeMatchesSpecificGuid(XElement child)
+ {
+ if (string.Equals(child.Attribute("Include")?.Value, "{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}",
+ StringComparison.InvariantCultureIgnoreCase))
+ {
+ // Fix is included with VS15.7 and above, but we might target VS15.0
+ // All known test providers also have a fix included
+ return targetVisualStudioVersion >= Vs15TestServiceFixVersion || definition.PackageReferences.Any(IsKnownTestProvider);
+ }
+
+ return false;
+ }
+ }
+
+ private static bool IsKnownTestProvider(PackageReference x)
+ {
+ // In theory, we should be checking versions of these test frameworks
+ // to see, if they have the fix included.
+
+ return KnownTestFrameworkIds.Contains(x.Id);
+ }
+ }
+}
diff --git a/Project2015To2017.Migrate2017.Library/Transforms/FrameworkReferencesTransformation.cs b/Project2015To2017.Migrate2017.Library/Transforms/FrameworkReferencesTransformation.cs
index 39f0efa..44f87c1 100644
--- a/Project2015To2017.Migrate2017.Library/Transforms/FrameworkReferencesTransformation.cs
+++ b/Project2015To2017.Migrate2017.Library/Transforms/FrameworkReferencesTransformation.cs
@@ -8,7 +8,7 @@ namespace Project2015To2017.Migrate2017.Transforms
{
public sealed class FrameworkReferencesTransformation : ILegacyOnlyProjectTransformation
{
- private const string SdkExtrasVersion = "MSBuild.Sdk.Extras/1.6.65";
+ private const string SdkExtrasVersion = "MSBuild.Sdk.Extras/1.6.68";
private static readonly Guid XamarinAndroid = Guid.ParseExact("EFBA0AD7-5A72-4C68-AF49-83D382785DCF", "D");
private static readonly Guid XamarinIos = Guid.ParseExact("6BC8ED88-2882-458C-8E55-DFD12B67127B", "D");
private static readonly Guid Uap = Guid.ParseExact("A5A43C5B-DE2A-4C0C-9213-0A381AF9435A", "D");
diff --git a/Project2015To2017.Migrate2017.Library/Transforms/UpgradeTestServiceTransformation.cs b/Project2015To2017.Migrate2017.Library/Transforms/UpgradeTestServiceTransformation.cs
index 32198a9..bf4d2aa 100644
--- a/Project2015To2017.Migrate2017.Library/Transforms/UpgradeTestServiceTransformation.cs
+++ b/Project2015To2017.Migrate2017.Library/Transforms/UpgradeTestServiceTransformation.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Immutable;
using System.Linq;
using Project2015To2017.Definition;
using Project2015To2017.Transforms;
@@ -10,10 +9,10 @@ public sealed class UpgradeTestServiceTransformation : ITransformation
{
public void Transform(Project definition)
{
- var removeQueue = definition.PropertyGroups
+ var removeQueue = definition.ItemGroups
.ElementsAnyNamespace("Service")
.Where(x => !string.IsNullOrEmpty(x.Value) && string.Equals(x.Value, "{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}", StringComparison.OrdinalIgnoreCase))
- .ToImmutableArray();
+ .ToArray();
foreach (var element in removeQueue)
{
diff --git a/Project2015To2017.Migrate2017.Tool/CommandLogic.cs b/Project2015To2017.Migrate2017.Tool/CommandLogic.cs
deleted file mode 100644
index 6d3443f..0000000
--- a/Project2015To2017.Migrate2017.Tool/CommandLogic.cs
+++ /dev/null
@@ -1,370 +0,0 @@
-using System;
-using DotNet.Globbing;
-using Serilog;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.IO;
-using System.Linq;
-using System.Xml;
-using System.Xml.Linq;
-using Microsoft.Extensions.Logging;
-using Project2015To2017.Analysis;
-using Project2015To2017.Definition;
-using Project2015To2017.Transforms;
-using Project2015To2017.Writing;
-using Project2015To2017.Migrate2017;
-
-namespace Project2015To2017.Migrate2017.Tool
-{
- public class CommandLogic
- {
- private readonly PatternProcessor globProcessor = (converter, pattern, callback, self) =>
- {
- Log.Verbose("Falling back to globbing");
- self.DoProcessableFileSearch();
- var glob = Glob.Parse(pattern);
- Log.Verbose("Parsed glob {Glob}", glob);
- foreach (var (path, extension) in self.Files)
- {
- if (!glob.IsMatch(path)) continue;
- var file = new FileInfo(path);
- callback(file, extension);
- }
-
- return true;
- };
-
- private readonly MigrationFacility facility;
-
- public CommandLogic()
- {
- var genericLogger = new Serilog.Extensions.Logging.SerilogLoggerProvider().CreateLogger(nameof(Serilog));
- facility = new MigrationFacility(genericLogger, globProcessor);
- }
-
- public void ExecuteEvaluate(
- IReadOnlyCollection items,
- ConversionOptions conversionOptions)
- {
- facility.ExecuteEvaluate(items, conversionOptions);
- }
-
- public void ExecuteMigrate(
- IReadOnlyCollection items,
- bool noBackup,
- ConversionOptions conversionOptions)
- {
- var writeOptions = new ProjectWriteOptions { MakeBackups = !noBackup };
- facility.ExecuteMigrate(items, conversionOptions, writeOptions);
- }
-
- public void ExecuteAnalyze(
- IReadOnlyCollection items,
- ConversionOptions conversionOptions)
- {
- facility.ExecuteAnalyze(items, conversionOptions);
- }
-
- public void ExecuteWizard(
- IReadOnlyCollection items,
- ConversionOptions conversionOptions)
- {
- conversionOptions.UnknownTargetFrameworkCallback = WizardUnknownTargetFrameworkCallback;
-
- var (projects, solutions) =
- facility.ParseProjects(items, BasicReadTransformationSet.Instance, conversionOptions);
-
- if (projects.Count == 0)
- {
- Log.Information("No projects have been found to match your criteria.");
- return;
- }
-
- var (modern, legacy) = projects.Split(x => x.IsModernProject);
- foreach (var projectPath in modern.Select(x => x.FilePath))
- {
- Log.Information("Project {ProjectPath} is already CPS-based", projectPath);
- }
-
- foreach (var projectPath in solutions.SelectMany(x => x.UnsupportedProjectPaths))
- {
- Log.Warning("Project {ProjectPath} migration is not supported at the moment",
- projectPath);
- }
-
- facility.DoAnalysis(projects, new AnalysisOptions(DiagnosticSet.All));
-
- if (legacy.Count > 0)
- {
- var doBackups = AskBinaryChoice("Would you like to create backups?");
-
- var writer = new ProjectWriter(facility.Logger, new ProjectWriteOptions { MakeBackups = doBackups });
-
- var transformations = new ChainTransformationSet(
- new BasicSimplifyTransformationSet(Vs15TransformationSet.TargetVisualStudioVersion),
- Vs15TransformationSet.TrueInstance)
- .CollectAndOrderTransformations(facility.Logger, conversionOptions);
-
- foreach (var project in legacy)
- {
- using (facility.Logger.BeginScope(project.FilePath))
- {
- var projectName = Path.GetFileNameWithoutExtension(project.FilePath.Name);
- Log.Information("Converting {ProjectName}...", projectName);
-
- if (!project.Valid)
- {
- Log.Error("Project {ProjectName} is marked as invalid, skipping...", projectName);
- continue;
- }
-
- foreach (var transformation in transformations.WhereSuitable(project, conversionOptions))
- {
- try
- {
- transformation.Transform(project);
- }
- catch (Exception e)
- {
- Log.Error(e, "Transformation {Item} has thrown an exception, skipping...",
- transformation.GetType().Name);
- }
- }
-
- if (!writer.TryWrite(project))
- continue;
- Log.Information("Project {ProjectName} has been converted", projectName);
- }
- }
- }
- else
- {
- var writer = new ProjectWriter(facility.Logger, new ProjectWriteOptions());
-
- Log.Information("It appears you already have everything converted to CPS.");
- if (AskBinaryChoice("Would you like to process CPS projects to clean up and reformat them?"))
- {
- var transformations =
- new BasicSimplifyTransformationSet(Vs15TransformationSet.TargetVisualStudioVersion)
- .CollectAndOrderTransformations(facility.Logger, conversionOptions);
-
- foreach (var project in modern)
- {
- using (facility.Logger.BeginScope(project.FilePath))
- {
- var projectName = Path.GetFileNameWithoutExtension(project.FilePath.Name);
- Log.Information("Processing {ProjectName}...", projectName);
-
- if (!project.Valid)
- {
- Log.Error("Project {ProjectName} is marked as invalid, skipping...", projectName);
- continue;
- }
-
- foreach (var transformation in transformations.WhereSuitable(project, conversionOptions))
- {
- try
- {
- transformation.Transform(project);
- }
- catch (Exception e)
- {
- Log.Error(e, "Transformation {Item} has thrown an exception, skipping...",
- transformation.GetType().Name);
- }
- }
-
- if (!writer.TryWrite(project))
- continue;
- Log.Information("Project {ProjectName} has been processed", projectName);
- }
- }
- }
- }
-
- conversionOptions.ProjectCache?.Purge();
-
- (projects, _) = facility.ParseProjects(items, BasicReadTransformationSet.Instance, conversionOptions);
-
- Log.Information("Modernization can be progressed a little further, but it might lead to unexpected behavioral changes.");
- if (AskBinaryChoice("Would you like to modernize projects?"))
- {
- var doBackups = AskBinaryChoice("Would you like to create backups?");
-
- var writer = new ProjectWriter(facility.Logger, new ProjectWriteOptions { MakeBackups = doBackups });
-
- var transformations = new ChainTransformationSet(
- new BasicSimplifyTransformationSet(Vs15TransformationSet.TargetVisualStudioVersion),
- Vs15ModernizationTransformationSet.TrueInstance)
- .CollectAndOrderTransformations(facility.Logger, conversionOptions);
-
- foreach (var project in projects)
- {
- using (facility.Logger.BeginScope(project.FilePath))
- {
- var projectName = Path.GetFileNameWithoutExtension(project.FilePath.Name);
- Log.Information("Modernizing {ProjectName}...", projectName);
-
- if (!project.Valid)
- {
- Log.Error("Project {ProjectName} is marked as invalid, skipping...", projectName);
- continue;
- }
-
- foreach (var transformation in transformations.WhereSuitable(project, conversionOptions))
- {
- try
- {
- transformation.Transform(project);
- }
- catch (Exception e)
- {
- Log.Error(e, "Transformation {Item} has thrown an exception, skipping...",
- transformation.GetType().Name);
- }
- }
-
- if (!writer.TryWrite(project))
- continue;
- Log.Information("Project {ProjectName} has been modernized", projectName);
- }
- }
-
- conversionOptions.ProjectCache?.Purge();
-
- (projects, _) = facility.ParseProjects(items, BasicReadTransformationSet.Instance, conversionOptions);
- }
-
- var diagnostics = new DiagnosticSet(Vs15DiagnosticSet.All);
- diagnostics.ExceptWith(DiagnosticSet.All);
- facility.DoAnalysis(projects, new AnalysisOptions(diagnostics));
- }
-
- private readonly List<(ImmutableHashSet<(string when, string tfms)> variant, ImmutableArray answer)>
- previousFrameworkResolutionAnswers =
- new List<(ImmutableHashSet<(string, string)>, ImmutableArray)>();
-
- private bool WizardUnknownTargetFrameworkCallback(Project project,
- IReadOnlyList<(IReadOnlyList frameworks, XElement source, string condition)> foundTargetFrameworks)
- {
- Log.Warning("Cannot unambiguously determine target frameworks for {ProjectName}.", project.FilePath);
-
- var currentVariant = new HashSet<(string when, string tfms)>();
-
- if (foundTargetFrameworks.Count > 0)
- {
- Log.Information("Found {Count} possible variants:", foundTargetFrameworks.Count);
- foreach (var (frameworks, source, condition) in foundTargetFrameworks)
- {
- if (source is IXmlLineInfo elementOnLine && elementOnLine.HasLineInfo())
- {
- Log.Information("{Line}: {TFMs} ({When})", elementOnLine.LineNumber, frameworks, condition);
- }
- else
- {
- Log.Information("{TFMs} ({When})", frameworks, condition);
- }
-
- currentVariant.Add((condition,
- string.Join(";", frameworks.ToImmutableSortedSet()).ToLowerInvariant()));
- }
-
- foreach (var (variant, answer) in previousFrameworkResolutionAnswers)
- {
- if (!currentVariant.SetEquals(variant))
- continue;
-
- Log.Information("You have previously selected {FormerChoice} for that combination.", answer);
- if (AskBinaryChoice("Would you like to use this framework set?"))
- {
- foreach (var tfm in answer)
- {
- project.TargetFrameworks.Add(tfm);
- }
-
- return true;
- }
-
- break;
- }
- }
-
- Log.Information("Please, enter target frameworks to use (comma or space separated):");
- Console.Out.Flush();
- var tfms = Console.ReadLine()
- ?.Trim()
- .Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(s => !string.IsNullOrWhiteSpace(s))
- .ToImmutableArray() ?? ImmutableArray.Empty;
-
- if (tfms.IsDefaultOrEmpty)
- {
- Log.Warning("You didn't specify any TFMs to use.");
- return AskBinaryChoice("Attempt to continue without specifying them?", defaultChoiceIsYes: false);
- }
-
- if (foundTargetFrameworks.Count > 0)
- {
- previousFrameworkResolutionAnswers.Add((currentVariant.ToImmutableHashSet(), tfms));
- }
-
- foreach (var tfm in tfms)
- {
- project.TargetFrameworks.Add(tfm);
- }
-
- return true;
- }
-
- private static bool AskBinaryChoice(string question, string yes = "Yes", string no = "No",
- bool defaultChoiceIsYes = true)
- {
- Console.Out.Flush();
- var yesCharLower = char.ToLowerInvariant(yes[0]);
- var noCharLower = char.ToLowerInvariant(no[0]);
- var yesChar = defaultChoiceIsYes ? char.ToUpperInvariant(yes[0]) : yesCharLower;
- var noChar = defaultChoiceIsYes ? noCharLower : char.ToUpperInvariant(no[0]);
- Console.Write($"{question} ({yesChar}/{noChar}) ");
- Console.Out.Flush();
- bool? result = null;
- while (!result.HasValue)
- {
- result = DetermineKeyChoice(Console.ReadKey(true), yesCharLower, noCharLower, defaultChoiceIsYes);
- }
-
- var realResult = result.Value;
- Console.WriteLine(realResult ? yes : no);
- Console.Out.Flush();
- return realResult;
- }
-
- private static bool? DetermineKeyChoice(ConsoleKeyInfo info, char yesChar, char noChar, bool defaultChoice)
- {
- switch (char.ToLowerInvariant(info.KeyChar))
- {
- case 'y':
- case 't':
- case '1':
- case char c when c == yesChar:
- return true;
- case 'n':
- case 'f':
- case '0':
- case char c when c == noChar:
- return false;
- }
-
- switch (info.Key)
- {
- case ConsoleKey.LeftArrow:
- return true;
- case ConsoleKey.RightArrow:
- return false;
- case ConsoleKey.Enter:
- return defaultChoice;
- }
-
- return null;
- }
- }
-}
\ No newline at end of file
diff --git a/Project2015To2017.Migrate2017.Tool/Program.cs b/Project2015To2017.Migrate2017.Tool/Program.cs
index 66b0977..a801256 100644
--- a/Project2015To2017.Migrate2017.Tool/Program.cs
+++ b/Project2015To2017.Migrate2017.Tool/Program.cs
@@ -1,11 +1,10 @@
+using System;
using Microsoft.DotNet.Cli.CommandLine;
+using Project2015To2017.Analysis;
using Project2015To2017.Caching;
+using Project2015To2017.Transforms;
using Serilog;
-using Serilog.Core;
using Serilog.Events;
-using System;
-using System.IO;
-using System.Linq;
using static Microsoft.DotNet.Cli.CommandLine.Accept;
using static Microsoft.DotNet.Cli.CommandLine.Create;
@@ -13,14 +12,9 @@ namespace Project2015To2017.Migrate2017.Tool
{
internal static class Program
{
- static int Main(string[] args)
+ private static int Main(string[] args)
{
- Log.Logger = new LoggerConfiguration()
- .Enrich.FromLogContext()
- .Enrich.WithDemystifiedStackTraces()
- .MinimumLevel.ControlledBy(verbosity)
- .WriteTo.Console()
- .CreateLogger();
+ ProgramBase.CreateLogger();
try
{
@@ -51,40 +45,13 @@ static int Main(string[] args)
}
}
- private static readonly LoggingLevelSwitch verbosity = new LoggingLevelSwitch();
-
private static int ProcessArgs(ParseResult result)
{
result.ShowHelpOrErrorIfAppropriate();
var command = result.AppliedCommand();
- var verbosityValue = result["dotnet-migrate-2017"].ValueOrDefault("verbosity")?.Trim().ToLowerInvariant() ?? "normal";
- switch (verbosityValue)
- {
- case "q":
- case "quiet":
- verbosity.MinimumLevel = LogEventLevel.Fatal + 1;
- break;
- case "m":
- case "minimal":
- verbosity.MinimumLevel = LogEventLevel.Warning;
- break;
- case "n":
- case "normal":
- verbosity.MinimumLevel = LogEventLevel.Information;
- break;
- case "d":
- case "detailed":
- verbosity.MinimumLevel = LogEventLevel.Debug;
- break;
- // ReSharper disable once StringLiteralTypo
- case "diag":
- case "diagnostic":
- verbosity.MinimumLevel = LogEventLevel.Verbose;
- break;
- default:
- throw new CommandParsingException($"Unknown verbosity level '{verbosityValue}'.", result.Command().HelpView().TrimEnd());
- }
+ var globalOptions = result["dotnet-migrate-2017"];
+ ProgramBase.ApplyVerbosity(result, globalOptions);
Log.Verbose(result.Diagram());
@@ -111,13 +78,28 @@ private static int ProcessArgs(ParseResult result)
switch (command.Name)
{
case "wizard":
- logic.ExecuteWizard(items, conversionOptions);
+ var diagnostics = new DiagnosticSet(Vs15DiagnosticSet.All);
+ diagnostics.ExceptWith(DiagnosticSet.All);
+ var sets = new WizardTransformationSets
+ {
+ MigrateSet = new ChainTransformationSet(
+ new BasicSimplifyTransformationSet(Vs15TransformationSet.TargetVisualStudioVersion),
+ Vs15TransformationSet.TrueInstance),
+ ModernCleanUpSet = new BasicSimplifyTransformationSet(
+ Vs15TransformationSet.TargetVisualStudioVersion),
+ ModernizeSet = new ChainTransformationSet(
+ new BasicSimplifyTransformationSet(Vs15TransformationSet.TargetVisualStudioVersion),
+ Vs15ModernizationTransformationSet.TrueInstance),
+ Diagnostics = diagnostics
+ };
+
+ logic.ExecuteWizard(items, conversionOptions, sets);
break;
case "evaluate":
- logic.ExecuteEvaluate(items, conversionOptions);
+ logic.ExecuteEvaluate(items, conversionOptions, Vs15TransformationSet.Instance, new AnalysisOptions(Vs15DiagnosticSet.All));
break;
case "analyze":
- logic.ExecuteAnalyze(items, conversionOptions);
+ logic.ExecuteAnalyze(items, conversionOptions, new AnalysisOptions(Vs15DiagnosticSet.All));
break;
case "migrate":
conversionOptions.AppendTargetFrameworkToOutputPath = !command.ValueOrDefault("old-output-path");
@@ -126,155 +108,24 @@ private static int ProcessArgs(ParseResult result)
if (forceTransformations != null)
conversionOptions.ForceDefaultTransforms = forceTransformations;
- logic.ExecuteMigrate(items, command.ValueOrDefault("no-backup"), conversionOptions);
+ logic.ExecuteMigrate(items, command.ValueOrDefault("no-backup"), conversionOptions, Vs15TransformationSet.Instance);
break;
}
return result.Execute().Code;
}
- private static readonly Parser Instance = new Parser(options: RootCommand());
-
- private static ArgumentsRule DefaultToCurrentDirectory(this ArgumentsRule rule) =>
- rule.With(defaultValue: () => NuGet.Common.PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory()));
-
private static Command RootCommand() =>
Command("dotnet-migrate-2017",
".NET Project Migration Tool",
NoArguments(),
- Wizard(),
- Evaluate(),
- Migrate(),
- Analyze(),
- HelpOption(),
- VerbosityOption());
-
- private static ArgumentsRule ItemsArgument => ZeroOrMoreArguments()
- .With("Project/solution file paths or glob patterns", "items")
- .DefaultToCurrentDirectory();
-
- private static Option TargetFrameworksOption => Option(
- "-t|--target-frameworks",
- "Override project target frameworks with ones specified. Specify multiple times for multiple target frameworks.",
- OneOrMoreArguments()
- .With("Target frameworks to be used instead of the ones in source projects", "frameworks"));
-
- private static Option KeepAssemblyInfoOption => Option("-a|--keep-assembly-info",
- "Keep assembly attributes in AssemblyInfo file instead of moving them to project file.");
-
- private static Option ForceOption => Option("-f|--force",
- "Force a conversion even if not all preconditions are met.");
-
- private static Command Evaluate() =>
- Command("evaluate",
- "Examine the projects potential to be converted before actual migration",
- ItemsArgument,
- TargetFrameworksOption,
- HelpOption());
-
- private static Command Migrate() =>
- Command("migrate",
- "Migrate projects to VS2017+ CPS format (non-interactive)",
- ItemsArgument,
- Option("-n|--no-backup",
- "Skip moving project.json, global.json, and *.xproj to a `Backup` directory after successful migration."),
- ForceOption,
- KeepAssemblyInfoOption,
- TargetFrameworksOption,
- Option("-o|--old-output-path",
- "Preserve legacy behavior by not creating a subfolder with the target framework in the output path."),
- Option(
- "-ft|--force-transformations",
- "Force execution of transformations despite project conversion state by their specified names. " +
- "Specify multiple times for multiple enforced transformations.",
- OneOrMoreArguments()
- .With("Transformation names to enforce execution", "names")),
- HelpOption());
-
- private static Command Analyze() =>
- Command("analyze",
- "Do the analysis run and output diagnostics",
- ItemsArgument,
- HelpOption());
-
- private static Command Wizard() =>
- Command("wizard",
- "Launch interactive migration wizard (recommended)",
- ItemsArgument,
- ForceOption,
- KeepAssemblyInfoOption,
- HelpOption());
-
- private static Option HelpOption() =>
- Option("-h|--help",
- "Show help information",
- NoArguments());
-
- private static Option VerbosityOption() =>
- Option("-v|--verbosity",
- // ReSharper disable StringLiteralTypo
- "Set the verbosity level of the command. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]",
- // ReSharper restore StringLiteralTypo
- AnyOneOf("q", "quiet",
- "m", "minimal",
- "n", "normal",
- "d", "detailed",
- // ReSharper disable once StringLiteralTypo
- "diag", "diagnostic")
- .With(name: "LEVEL"));
-
- public static void ShowHelpOrErrorIfAppropriate(this ParseResult parseResult)
- {
- parseResult.ShowHelpIfRequested();
+ ProgramBase.Wizard(),
+ ProgramBase.Evaluate(),
+ ProgramBase.Migrate(),
+ ProgramBase.Analyze(),
+ ProgramBase.HelpOption(),
+ ProgramBase.VerbosityOption());
- if (parseResult.Errors.Any())
- {
- throw new CommandParsingException(
- string.Join(Environment.NewLine,
- parseResult.Errors.Select(e => e.Message)),
- parseResult.Command()?.HelpView().TrimEnd());
- }
- }
-
- private static void ShowHelpIfRequested(this ParseResult parseResult)
- {
- var appliedCommand = parseResult.AppliedCommand();
-
- if (appliedCommand.HasOption("help") ||
- appliedCommand.Arguments.Contains("-?") ||
- appliedCommand.Arguments.Contains("/?"))
- {
- throw new HelpException(parseResult.Command().HelpView().TrimEnd());
- }
- }
-
- public static T ValueOrDefault(this AppliedOption parseResult, string alias)
- {
- return parseResult
- .AppliedOptions
- .Where(o => o.HasAlias(alias))
- .Select(o => o.Value())
- .SingleOrDefault();
- }
-
- /// Allows control flow to be interrupted in order to display help in the console.
- public sealed class HelpException : Exception
- {
- public HelpException(string message) : base(message)
- {
- }
- }
-
- private sealed class CommandParsingException : Exception
- {
- public CommandParsingException(
- string message,
- string helpText = null) : base(message)
- {
- HelpText = helpText ?? "";
- }
-
- public string HelpText { get; }
- }
+ private static readonly Parser Instance = new Parser(options: RootCommand());
}
}
\ No newline at end of file
diff --git a/Project2015To2017.Migrate2017.Tool/Project2015To2017.Migrate2017.Tool.csproj b/Project2015To2017.Migrate2017.Tool/Project2015To2017.Migrate2017.Tool.csproj
index 39fc6a2..9c96e94 100644
--- a/Project2015To2017.Migrate2017.Tool/Project2015To2017.Migrate2017.Tool.csproj
+++ b/Project2015To2017.Migrate2017.Tool/Project2015To2017.Migrate2017.Tool.csproj
@@ -1,4 +1,4 @@
-
+
net461;netcoreapp2.1
@@ -19,6 +19,8 @@
+
+
diff --git a/Project2015To2017.Migrate2019.Library/Transforms/Vs16FrameworkReferencesTransformation.cs b/Project2015To2017.Migrate2019.Library/Transforms/Vs16FrameworkReferencesTransformation.cs
index e6cedc0..3245bba 100644
--- a/Project2015To2017.Migrate2019.Library/Transforms/Vs16FrameworkReferencesTransformation.cs
+++ b/Project2015To2017.Migrate2019.Library/Transforms/Vs16FrameworkReferencesTransformation.cs
@@ -8,7 +8,7 @@ namespace Project2015To2017.Migrate2019.Library.Transforms
{
public sealed class Vs16FrameworkReferencesTransformation : ILegacyOnlyProjectTransformation
{
- private const string SdkExtrasVersion = "MSBuild.Sdk.Extras/2.0.0-preview.21";
+ private const string SdkExtrasVersion = "MSBuild.Sdk.Extras/2.0.31";
private const string WindowsDesktopVersion = "Microsoft.NET.Sdk.WindowsDesktop";
private static readonly Guid XamarinAndroid = Guid.ParseExact("EFBA0AD7-5A72-4C68-AF49-83D382785DCF", "D");
private static readonly Guid XamarinIos = Guid.ParseExact("6BC8ED88-2882-458C-8E55-DFD12B67127B", "D");
diff --git a/Project2015To2017.Migrate2019.Library/Vs16DiagnosticSet.cs b/Project2015To2017.Migrate2019.Library/Vs16DiagnosticSet.cs
new file mode 100644
index 0000000..5ef8910
--- /dev/null
+++ b/Project2015To2017.Migrate2019.Library/Vs16DiagnosticSet.cs
@@ -0,0 +1,15 @@
+using Project2015To2017.Analysis;
+using Project2015To2017.Migrate2017;
+
+namespace Project2015To2017.Migrate2019.Library
+{
+ public static class Vs16DiagnosticSet
+ {
+ public static readonly DiagnosticSet All = new DiagnosticSet();
+
+ static Vs16DiagnosticSet()
+ {
+ All.UnionWith(Vs15DiagnosticSet.All);
+ }
+ }
+}
diff --git a/Project2015To2017.Migrate2019.Library/Vs16TransformationSet.cs b/Project2015To2017.Migrate2019.Library/Vs16TransformationSet.cs
index 31adb8f..b5e051b 100644
--- a/Project2015To2017.Migrate2019.Library/Vs16TransformationSet.cs
+++ b/Project2015To2017.Migrate2019.Library/Vs16TransformationSet.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using Project2015To2017.Migrate2017.Transforms;
+using Project2015To2017.Migrate2019.Library.Transforms;
using Project2015To2017.Transforms;
namespace Project2015To2017.Migrate2019.Library
@@ -31,8 +32,8 @@ public IReadOnlyCollection Transformations(
new TargetFrameworkReplaceTransformation(
conversionOptions.TargetFrameworks,
conversionOptions.AppendTargetFrameworkToOutputPath),
- // VS15 migration
- new FrameworkReferencesTransformation(),
+ // VS16 migration
+ new Vs16FrameworkReferencesTransformation(),
new TestProjectPackageReferenceTransformation(logger),
new AssemblyFilterPackageReferencesTransformation(),
new AssemblyFilterHintedPackageReferencesTransformation(),
diff --git a/Project2015To2017.Migrate2019.Tool/Program.cs b/Project2015To2017.Migrate2019.Tool/Program.cs
new file mode 100644
index 0000000..cfdcbf8
--- /dev/null
+++ b/Project2015To2017.Migrate2019.Tool/Program.cs
@@ -0,0 +1,133 @@
+using System;
+using Microsoft.DotNet.Cli.CommandLine;
+using Project2015To2017.Analysis;
+using Project2015To2017.Caching;
+using Project2015To2017.Migrate2017.Tool;
+using Project2015To2017.Migrate2019.Library;
+using Project2015To2017.Transforms;
+using Serilog;
+using Serilog.Events;
+using static Microsoft.DotNet.Cli.CommandLine.Accept;
+using static Microsoft.DotNet.Cli.CommandLine.Create;
+
+namespace Project2015To2017.Migrate2019.Tool
+{
+ internal static class Program
+ {
+ private static int Main(string[] args)
+ {
+ ProgramBase.CreateLogger();
+
+ try
+ {
+ var result = Instance.Parse(args);
+ return ProcessArgs(result);
+ }
+ catch (HelpException e)
+ {
+ Log.Information(e.Message);
+ return 0;
+ }
+ catch (Exception e)
+ {
+ if (Log.IsEnabled(LogEventLevel.Debug))
+ Log.Fatal(e, "Fatal exception occurred");
+ else
+ Log.Fatal(e.Message);
+ if (e is CommandParsingException commandParsingException)
+ {
+ Log.Information(commandParsingException.HelpText);
+ }
+
+ return 1;
+ }
+ finally
+ {
+ Log.CloseAndFlush();
+ }
+ }
+
+ private static int ProcessArgs(ParseResult result)
+ {
+ result.ShowHelpOrErrorIfAppropriate();
+
+ var command = result.AppliedCommand();
+ var globalOptions = result["dotnet-migrate-2019"];
+ ProgramBase.ApplyVerbosity(result, globalOptions);
+
+ Log.Verbose(result.Diagram());
+
+ var items = command.Value();
+
+ var conversionOptions = new ConversionOptions
+ {
+ ProjectCache = new DefaultProjectCache(),
+ Force = command.ValueOrDefault("force"),
+ KeepAssemblyInfo = command.ValueOrDefault("keep-assembly-info")
+ };
+
+ switch (command.Name)
+ {
+ case "evaluate":
+ case "migrate":
+ var frameworks = command.ValueOrDefault("target-frameworks");
+ if (frameworks != null)
+ conversionOptions.TargetFrameworks = frameworks;
+ break;
+ }
+
+ var logic = new CommandLogic();
+ switch (command.Name)
+ {
+ case "wizard":
+ var diagnostics = new DiagnosticSet(Vs16DiagnosticSet.All);
+ diagnostics.ExceptWith(DiagnosticSet.All);
+ var sets = new WizardTransformationSets
+ {
+ MigrateSet = new ChainTransformationSet(
+ new BasicSimplifyTransformationSet(Vs16TransformationSet.TargetVisualStudioVersion),
+ Vs16TransformationSet.TrueInstance),
+ ModernCleanUpSet = new BasicSimplifyTransformationSet(
+ Vs16TransformationSet.TargetVisualStudioVersion),
+ ModernizeSet = new ChainTransformationSet(
+ new BasicSimplifyTransformationSet(Vs16TransformationSet.TargetVisualStudioVersion),
+ Vs16ModernizationTransformationSet.TrueInstance),
+ Diagnostics = diagnostics
+ };
+
+ logic.ExecuteWizard(items, conversionOptions, sets);
+ break;
+ case "evaluate":
+ logic.ExecuteEvaluate(items, conversionOptions, Vs16TransformationSet.Instance, new AnalysisOptions(Vs16DiagnosticSet.All));
+ break;
+ case "analyze":
+ logic.ExecuteAnalyze(items, conversionOptions, new AnalysisOptions(Vs16DiagnosticSet.All));
+ break;
+ case "migrate":
+ conversionOptions.AppendTargetFrameworkToOutputPath = !command.ValueOrDefault("old-output-path");
+
+ var forceTransformations = command.ValueOrDefault("force-transformations");
+ if (forceTransformations != null)
+ conversionOptions.ForceDefaultTransforms = forceTransformations;
+
+ logic.ExecuteMigrate(items, command.ValueOrDefault("no-backup"), conversionOptions, Vs16TransformationSet.Instance);
+ break;
+ }
+
+ return result.Execute().Code;
+ }
+
+ private static Command RootCommand() =>
+ Command("dotnet-migrate-2019",
+ ".NET Project Migration Tool",
+ NoArguments(),
+ ProgramBase.Wizard(),
+ ProgramBase.Evaluate(),
+ ProgramBase.Migrate(),
+ ProgramBase.Analyze(),
+ ProgramBase.HelpOption(),
+ ProgramBase.VerbosityOption());
+
+ private static readonly Parser Instance = new Parser(options: RootCommand());
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.Migrate2019.Tool/Project2015To2017.Migrate2019.Tool.csproj b/Project2015To2017.Migrate2019.Tool/Project2015To2017.Migrate2019.Tool.csproj
new file mode 100644
index 0000000..95cb583
--- /dev/null
+++ b/Project2015To2017.Migrate2019.Tool/Project2015To2017.Migrate2019.Tool.csproj
@@ -0,0 +1,34 @@
+
+
+
+ net461;netcoreapp2.1
+ netcoreapp2.1
+ True
+
+ dotnet-migrate-2019
+ Project2015To2017.Migrate2019.Tool
+ Project2015To2017.Migrate2019.Tool
+ Exe
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Project2015To2017.MigrateXXXX.Tool/CommandExceptions.cs b/Project2015To2017.MigrateXXXX.Tool/CommandExceptions.cs
new file mode 100644
index 0000000..0a4b4d8
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/CommandExceptions.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ /// Allows control flow to be interrupted in order to display help in the console.
+ internal sealed class HelpException : Exception
+ {
+ public HelpException(string message) : base(message)
+ {
+ }
+ }
+
+ internal sealed class CommandParsingException : Exception
+ {
+ public CommandParsingException(
+ string message,
+ string helpText = null) : base(message)
+ {
+ HelpText = helpText ?? "";
+ }
+
+ public string HelpText { get; }
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/CommandLogic.AskBinaryChoice.cs b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.AskBinaryChoice.cs
new file mode 100644
index 0000000..7687da6
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.AskBinaryChoice.cs
@@ -0,0 +1,58 @@
+using System;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ public partial class CommandLogic
+ {
+ private static bool AskBinaryChoice(string question, string yes = "Yes", string no = "No",
+ bool defaultChoiceIsYes = true)
+ {
+ Console.Out.Flush();
+ var yesCharLower = char.ToLowerInvariant(yes[0]);
+ var noCharLower = char.ToLowerInvariant(no[0]);
+ var yesChar = defaultChoiceIsYes ? char.ToUpperInvariant(yes[0]) : yesCharLower;
+ var noChar = defaultChoiceIsYes ? noCharLower : char.ToUpperInvariant(no[0]);
+ Console.Write($"{question} ({yesChar}/{noChar}) ");
+ Console.Out.Flush();
+ bool? result = null;
+ while (!result.HasValue)
+ {
+ result = DetermineKeyChoice(Console.ReadKey(true), yesCharLower, noCharLower, defaultChoiceIsYes);
+ }
+
+ var realResult = result.Value;
+ Console.WriteLine(realResult ? yes : no);
+ Console.Out.Flush();
+ return realResult;
+ }
+
+ private static bool? DetermineKeyChoice(ConsoleKeyInfo info, char yesChar, char noChar, bool defaultChoice)
+ {
+ switch (char.ToLowerInvariant(info.KeyChar))
+ {
+ case 'y':
+ case 't':
+ case '1':
+ case char c when c == yesChar:
+ return true;
+ case 'n':
+ case 'f':
+ case '0':
+ case char c when c == noChar:
+ return false;
+ }
+
+ switch (info.Key)
+ {
+ case ConsoleKey.LeftArrow:
+ return true;
+ case ConsoleKey.RightArrow:
+ return false;
+ case ConsoleKey.Enter:
+ return defaultChoice;
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/CommandLogic.Wizard.UnknownTargetFramework.cs b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.Wizard.UnknownTargetFramework.cs
new file mode 100644
index 0000000..87a731a
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.Wizard.UnknownTargetFramework.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Xml;
+using System.Xml.Linq;
+using Project2015To2017.Definition;
+using Serilog;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ public partial class CommandLogic
+ {
+ private readonly List<(ImmutableHashSet<(string when, string tfms)> variant, ImmutableArray answer)>
+ previousFrameworkResolutionAnswers =
+ new List<(ImmutableHashSet<(string, string)>, ImmutableArray)>();
+
+
+ private bool shownFrameworkInputExamples = false;
+
+ private bool WizardUnknownTargetFrameworkCallback(Project project,
+ IReadOnlyList<(IReadOnlyList frameworks, XElement source, string condition)> foundTargetFrameworks)
+ {
+ Log.Warning("Cannot unambiguously determine target frameworks for {ProjectName}.", project.FilePath);
+
+ var currentVariant = new HashSet<(string when, string tfms)>();
+
+ if (foundTargetFrameworks.Count > 0)
+ {
+ Log.Information("Found {Count} possible variants:", foundTargetFrameworks.Count);
+ foreach (var (frameworks, source, condition) in foundTargetFrameworks)
+ {
+ if (source is IXmlLineInfo elementOnLine && elementOnLine.HasLineInfo())
+ {
+ Log.Information("{Line}: {TFMs} ({When})", elementOnLine.LineNumber, frameworks, condition);
+ }
+ else
+ {
+ Log.Information("{TFMs} ({When})", frameworks, condition);
+ }
+
+ currentVariant.Add((condition,
+ string.Join(";", frameworks.ToImmutableSortedSet()).ToLowerInvariant()));
+ }
+
+ foreach (var (variant, answer) in previousFrameworkResolutionAnswers)
+ {
+ if (!currentVariant.SetEquals(variant))
+ continue;
+
+ Log.Information("You have previously selected {FormerChoice} for that combination.", answer);
+ if (AskBinaryChoice("Would you like to use this framework set?"))
+ {
+ foreach (var tfm in answer)
+ {
+ project.TargetFrameworks.Add(tfm);
+ }
+
+ return true;
+ }
+
+ break;
+ }
+ }
+
+ Log.Information("Please, enter target frameworks to use (comma or space separated):");
+
+ if (!shownFrameworkInputExamples)
+ {
+ Log.Information("e.g.: {Example}", string.Join(" ", "net48", "netstandard2.1", "netcoreapp3.0"));
+ shownFrameworkInputExamples = true;
+ }
+
+ Console.Out.Flush();
+
+ var tfms = Console.ReadLine()
+ ?.Trim()
+ .Split(new[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries)
+ .Where(s => !string.IsNullOrWhiteSpace(s))
+ .Select(x => x.Trim())
+ .ToImmutableArray() ?? ImmutableArray.Empty;
+
+ if (tfms.IsDefaultOrEmpty)
+ {
+ Log.Warning("You didn't specify any TFMs to use.");
+ return AskBinaryChoice("Attempt to continue without specifying them?", defaultChoiceIsYes: false);
+ }
+
+ if (foundTargetFrameworks.Count > 0)
+ {
+ previousFrameworkResolutionAnswers.Add((currentVariant.ToImmutableHashSet(), tfms));
+ }
+
+ foreach (var tfm in tfms)
+ {
+ project.TargetFrameworks.Add(tfm);
+ }
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/CommandLogic.WizardMigrate.cs b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.WizardMigrate.cs
new file mode 100644
index 0000000..531459b
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.WizardMigrate.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Project2015To2017.Definition;
+using Project2015To2017.Writing;
+using Serilog;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ public partial class CommandLogic
+ {
+ private void WizardMigrate(IReadOnlyList legacy, ITransformationSet transformationSet,
+ ConversionOptions conversionOptions)
+ {
+ var transformations = transformationSet.CollectAndOrderTransformations(facility.Logger, conversionOptions);
+
+ var doBackups = AskBinaryChoice("Would you like to create backups?");
+
+ var writer = new ProjectWriter(facility.Logger, new ProjectWriteOptions {MakeBackups = doBackups});
+
+ foreach (var project in legacy)
+ {
+ using (facility.Logger.BeginScope(project.FilePath))
+ {
+ var projectName = Path.GetFileNameWithoutExtension(project.FilePath.Name);
+ Log.Information("Converting {ProjectName}...", projectName);
+
+ if (!project.Valid)
+ {
+ Log.Error("Project {ProjectName} is marked as invalid, skipping...", projectName);
+ continue;
+ }
+
+ foreach (var transformation in transformations.WhereSuitable(project, conversionOptions))
+ {
+ try
+ {
+ transformation.Transform(project);
+ }
+ catch (Exception e)
+ {
+ Log.Error(e, "Transformation {Item} has thrown an exception, skipping...",
+ transformation.GetType().Name);
+ }
+ }
+
+ if (!writer.TryWrite(project))
+ continue;
+ Log.Information("Project {ProjectName} has been converted", projectName);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/CommandLogic.WizardModernCleanUp.cs b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.WizardModernCleanUp.cs
new file mode 100644
index 0000000..b4898a3
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.WizardModernCleanUp.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Project2015To2017.Definition;
+using Project2015To2017.Writing;
+using Serilog;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ public partial class CommandLogic
+ {
+ private void WizardModernCleanUp(IReadOnlyList modern, ITransformationSet transformationSet,
+ ConversionOptions conversionOptions)
+ {
+ var transformations = transformationSet.CollectAndOrderTransformations(facility.Logger, conversionOptions);
+
+ var writer = new ProjectWriter(facility.Logger, new ProjectWriteOptions());
+
+ foreach (var project in modern)
+ {
+ using (facility.Logger.BeginScope(project.FilePath))
+ {
+ var projectName = Path.GetFileNameWithoutExtension(project.FilePath.Name);
+ Log.Information("Processing {ProjectName}...", projectName);
+
+ if (!project.Valid)
+ {
+ Log.Error("Project {ProjectName} is marked as invalid, skipping...", projectName);
+ continue;
+ }
+
+ foreach (var transformation in transformations.WhereSuitable(project, conversionOptions))
+ {
+ try
+ {
+ transformation.Transform(project);
+ }
+ catch (Exception e)
+ {
+ Log.Error(e, "Transformation {Item} has thrown an exception, skipping...",
+ transformation.GetType().Name);
+ }
+ }
+
+ if (!writer.TryWrite(project))
+ continue;
+ Log.Information("Project {ProjectName} has been processed", projectName);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/CommandLogic.WizardModernize.cs b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.WizardModernize.cs
new file mode 100644
index 0000000..dd22337
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.WizardModernize.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Project2015To2017.Definition;
+using Project2015To2017.Writing;
+using Serilog;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ public partial class CommandLogic
+ {
+ private void WizardModernize(IReadOnlyCollection projects, ITransformationSet transformationSet,
+ ConversionOptions conversionOptions)
+ {
+ var transformations = transformationSet.CollectAndOrderTransformations(facility.Logger, conversionOptions);
+
+ var doBackups = AskBinaryChoice("Would you like to create backups?");
+
+ var writer = new ProjectWriter(facility.Logger, new ProjectWriteOptions {MakeBackups = doBackups});
+
+ foreach (var project in projects)
+ {
+ using (facility.Logger.BeginScope(project.FilePath))
+ {
+ var projectName = Path.GetFileNameWithoutExtension(project.FilePath.Name);
+ Log.Information("Modernizing {ProjectName}...", projectName);
+
+ if (!project.Valid)
+ {
+ Log.Error("Project {ProjectName} is marked as invalid, skipping...", projectName);
+ continue;
+ }
+
+ foreach (var transformation in transformations.WhereSuitable(project, conversionOptions))
+ {
+ try
+ {
+ transformation.Transform(project);
+ }
+ catch (Exception e)
+ {
+ Log.Error(e, "Transformation {Item} has thrown an exception, skipping...",
+ transformation.GetType().Name);
+ }
+ }
+
+ if (!writer.TryWrite(project))
+ continue;
+ Log.Information("Project {ProjectName} has been modernized", projectName);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/CommandLogic.cs b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.cs
new file mode 100644
index 0000000..ce2164c
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/CommandLogic.cs
@@ -0,0 +1,131 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using DotNet.Globbing;
+using Project2015To2017.Analysis;
+using Project2015To2017.Transforms;
+using Project2015To2017.Writing;
+using Serilog;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ public partial class CommandLogic
+ {
+ private readonly PatternProcessor globProcessor = (converter, pattern, callback, self) =>
+ {
+ Log.Verbose("Falling back to globbing");
+ self.DoProcessableFileSearch();
+ var glob = Glob.Parse(pattern);
+ Log.Verbose("Parsed glob {Glob}", glob);
+ foreach (var (path, extension) in self.Files)
+ {
+ if (!glob.IsMatch(path)) continue;
+ var file = new FileInfo(path);
+ callback(file, extension);
+ }
+
+ return true;
+ };
+
+ private readonly MigrationFacility facility;
+
+ public CommandLogic()
+ {
+ var genericLogger = new Serilog.Extensions.Logging.SerilogLoggerProvider().CreateLogger(nameof(Serilog));
+ facility = new MigrationFacility(genericLogger, globProcessor);
+ }
+
+ public void ExecuteEvaluate(
+ IReadOnlyCollection items,
+ ConversionOptions conversionOptions,
+ ITransformationSet transformationSet,
+ AnalysisOptions analysisOptions)
+ {
+ facility.ExecuteEvaluate(items, conversionOptions, transformationSet, analysisOptions);
+ }
+
+ public void ExecuteMigrate(
+ IReadOnlyCollection items,
+ bool noBackup,
+ ConversionOptions conversionOptions,
+ ITransformationSet transformationSet)
+ {
+ var writeOptions = new ProjectWriteOptions { MakeBackups = !noBackup };
+ facility.ExecuteMigrate(items, transformationSet, conversionOptions, writeOptions);
+ }
+
+ public void ExecuteAnalyze(
+ IReadOnlyCollection items,
+ ConversionOptions conversionOptions,
+ AnalysisOptions analysisOptions)
+ {
+ facility.ExecuteAnalyze(items, conversionOptions, analysisOptions);
+ }
+
+ public void ExecuteWizard(
+ IReadOnlyCollection items,
+ ConversionOptions conversionOptions,
+ WizardTransformationSets sets)
+ {
+ if (sets.MigrateSet == null || sets.ModernCleanUpSet == null || sets.ModernizeSet == null)
+ {
+ Log.Fatal("Wrong API usage: all transformation sets must be supplied");
+ return;
+ }
+
+ conversionOptions.UnknownTargetFrameworkCallback = WizardUnknownTargetFrameworkCallback;
+
+ var (projects, solutions) =
+ facility.ParseProjects(items, BasicReadTransformationSet.Instance, conversionOptions);
+
+ if (projects.Count == 0)
+ {
+ Log.Information("No projects have been found to match your criteria.");
+ return;
+ }
+
+ var (modern, legacy) = projects.Split(x => x.IsModernProject);
+ foreach (var projectPath in modern.Select(x => x.FilePath))
+ {
+ Log.Information("Project {ProjectPath} is already CPS-based", projectPath);
+ }
+
+ foreach (var projectPath in solutions.SelectMany(x => x.UnsupportedProjectPaths))
+ {
+ Log.Warning("Project {ProjectPath} migration is not supported at the moment",
+ projectPath);
+ }
+
+ facility.DoAnalysis(projects, new AnalysisOptions(DiagnosticSet.All));
+
+ if (legacy.Count > 0)
+ {
+ WizardMigrate(legacy, sets.MigrateSet, conversionOptions);
+ }
+ else
+ {
+ Log.Information("It appears you already have everything converted to CPS.");
+ if (AskBinaryChoice("Would you like to process CPS projects to clean up and reformat them?"))
+ {
+ WizardModernCleanUp(modern, sets.ModernCleanUpSet, conversionOptions);
+ }
+ }
+
+ conversionOptions.ProjectCache?.Purge();
+
+ (projects, _) = facility.ParseProjects(items, BasicReadTransformationSet.Instance, conversionOptions);
+
+ Log.Information("Modernization can be progressed a little further, but it might lead to unexpected behavioral changes.");
+ if (AskBinaryChoice("Would you like to modernize projects?"))
+ {
+ WizardModernize(projects, sets.ModernizeSet, conversionOptions);
+
+ conversionOptions.ProjectCache?.Purge();
+
+ (projects, _) = facility.ParseProjects(items, BasicReadTransformationSet.Instance, conversionOptions);
+ }
+
+ facility.DoAnalysis(projects, new AnalysisOptions(sets.Diagnostics));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Accept.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Accept.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Accept.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Accept.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOption.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOption.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOption.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOption.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOptionExtensions.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOptionExtensions.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOptionExtensions.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOptionExtensions.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOptionSet.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOptionSet.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOptionSet.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/AppliedOptionSet.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ArgumentsRule.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ArgumentsRule.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ArgumentsRule.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ArgumentsRule.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ArgumentsRuleExtensions.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ArgumentsRuleExtensions.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ArgumentsRuleExtensions.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ArgumentsRuleExtensions.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Command.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Command.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Command.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Command.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/CommandExecutionResult.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/CommandExecutionResult.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/CommandExecutionResult.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/CommandExecutionResult.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Create.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Create.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Create.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Create.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/DefaultHelpViewText.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/DefaultHelpViewText.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/DefaultHelpViewText.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/DefaultHelpViewText.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/DefaultValidationMessages.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/DefaultValidationMessages.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/DefaultValidationMessages.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/DefaultValidationMessages.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/EnumerableExtensions.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/EnumerableExtensions.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/EnumerableExtensions.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/EnumerableExtensions.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/HelpViewExtensions.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/HelpViewExtensions.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/HelpViewExtensions.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/HelpViewExtensions.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/IValidationMessages.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/IValidationMessages.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/IValidationMessages.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/IValidationMessages.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Option.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Option.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Option.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Option.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/OptionError.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/OptionError.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/OptionError.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/OptionError.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/OptionExtensions.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/OptionExtensions.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/OptionExtensions.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/OptionExtensions.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/OptionSet.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/OptionSet.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/OptionSet.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/OptionSet.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/OptionSet{T}.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/OptionSet{T}.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/OptionSet{T}.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/OptionSet{T}.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ParseException.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ParseException.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ParseException.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ParseException.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ParseResult.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ParseResult.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ParseResult.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ParseResult.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ParseResultExtensions.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ParseResultExtensions.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ParseResultExtensions.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ParseResultExtensions.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Parser.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Parser.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Parser.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Parser.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ParserConfiguration.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ParserConfiguration.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ParserConfiguration.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ParserConfiguration.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ParserExtensions.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ParserExtensions.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ParserExtensions.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ParserExtensions.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/StringExtensions.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/StringExtensions.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/StringExtensions.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/StringExtensions.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Suggest.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Suggest.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Suggest.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Suggest.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Token.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Token.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/Token.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/Token.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/TokenType.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/TokenType.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/TokenType.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/TokenType.cs
diff --git a/Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ValidationMessages.cs b/Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ValidationMessages.cs
similarity index 100%
rename from Project2015To2017.Migrate2017.Tool/Microsoft.DotNet.Cli.CommandLine/ValidationMessages.cs
rename to Project2015To2017.MigrateXXXX.Tool/Microsoft.DotNet.Cli.CommandLine/ValidationMessages.cs
diff --git a/Project2015To2017.MigrateXXXX.Tool/ProgramBase.ApplyVerbosity.cs b/Project2015To2017.MigrateXXXX.Tool/ProgramBase.ApplyVerbosity.cs
new file mode 100644
index 0000000..9a1cd7b
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/ProgramBase.ApplyVerbosity.cs
@@ -0,0 +1,41 @@
+using Microsoft.DotNet.Cli.CommandLine;
+using Serilog.Events;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ internal static partial class ProgramBase
+ {
+ public static void ApplyVerbosity(ParseResult result, AppliedOption globalOptions)
+ {
+ var verbosityValue = globalOptions.ValueOrDefault("verbosity")?.Trim().ToLowerInvariant() ??
+ "normal";
+ switch (verbosityValue)
+ {
+ case "q":
+ case "quiet":
+ verbosity.MinimumLevel = LogEventLevel.Fatal + 1;
+ break;
+ case "m":
+ case "minimal":
+ verbosity.MinimumLevel = LogEventLevel.Warning;
+ break;
+ case "n":
+ case "normal":
+ verbosity.MinimumLevel = LogEventLevel.Information;
+ break;
+ case "d":
+ case "detailed":
+ verbosity.MinimumLevel = LogEventLevel.Debug;
+ break;
+ // ReSharper disable once StringLiteralTypo
+ case "diag":
+ case "diagnostic":
+ verbosity.MinimumLevel = LogEventLevel.Verbose;
+ break;
+ default:
+ throw new CommandParsingException($"Unknown verbosity level '{verbosityValue}'.",
+ result.Command().HelpView().TrimEnd());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/ProgramBase.Common.cs b/Project2015To2017.MigrateXXXX.Tool/ProgramBase.Common.cs
new file mode 100644
index 0000000..85fc728
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/ProgramBase.Common.cs
@@ -0,0 +1,20 @@
+using Microsoft.DotNet.Cli.CommandLine;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ internal static partial class ProgramBase
+ {
+ private static ArgumentsRule ItemsArgument => Accept.ZeroOrMoreArguments()
+ .With("Project/solution file paths or glob patterns", "items")
+ .DefaultToCurrentDirectory();
+
+ private static Option TargetFrameworksOption => Create.Option(
+ "-t|--target-frameworks",
+ "Override project target frameworks with ones specified. Specify multiple times for multiple target frameworks.",
+ Accept.OneOrMoreArguments()
+ .With("Target frameworks to be used instead of the ones in source projects", "frameworks"));
+
+ private static Option KeepAssemblyInfoOption => Create.Option("-a|--keep-assembly-info",
+ "Keep assembly attributes in AssemblyInfo file instead of moving them to project file.");
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/ProgramBase.Options.cs b/Project2015To2017.MigrateXXXX.Tool/ProgramBase.Options.cs
new file mode 100644
index 0000000..f9f2908
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/ProgramBase.Options.cs
@@ -0,0 +1,83 @@
+using System;
+using System.IO;
+using System.Linq;
+using Microsoft.DotNet.Cli.CommandLine;
+using NuGet.Common;
+using Serilog;
+using Serilog.Core;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ internal static partial class ProgramBase
+ {
+ internal static readonly LoggingLevelSwitch verbosity = new LoggingLevelSwitch();
+
+ private static ArgumentsRule DefaultToCurrentDirectory(this ArgumentsRule rule) =>
+ rule.With(defaultValue: () => PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory()));
+
+ internal static Option ForceOption => Create.Option("-f|--force",
+ "Force a conversion even if not all preconditions are met.");
+
+ internal static Option HelpOption() =>
+ Create.Option("-h|--help",
+ "Show help information",
+ Accept.NoArguments());
+
+ internal static Option VerbosityOption() =>
+ Create.Option("-v|--verbosity",
+ // ReSharper disable StringLiteralTypo
+ "Set the verbosity level of the command. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]",
+ // ReSharper restore StringLiteralTypo
+ Accept.AnyOneOf("q", "quiet",
+ "m", "minimal",
+ "n", "normal",
+ "d", "detailed",
+ // ReSharper disable once StringLiteralTypo
+ "diag", "diagnostic")
+ .With(name: "LEVEL"));
+
+ internal static void ShowHelpOrErrorIfAppropriate(this ParseResult parseResult)
+ {
+ parseResult.ShowHelpIfRequested();
+
+ if (parseResult.Errors.Any())
+ {
+ throw new CommandParsingException(
+ String.Join(Environment.NewLine,
+ parseResult.Errors.Select(e => e.Message)),
+ parseResult.Command()?.HelpView().TrimEnd());
+ }
+ }
+
+ private static void ShowHelpIfRequested(this ParseResult parseResult)
+ {
+ var appliedCommand = parseResult.AppliedCommand();
+
+ if (appliedCommand.HasOption("help") ||
+ appliedCommand.Arguments.Contains("-?") ||
+ appliedCommand.Arguments.Contains("/?"))
+ {
+ throw new HelpException(parseResult.Command().HelpView().TrimEnd());
+ }
+ }
+
+ public static T ValueOrDefault(this AppliedOption parseResult, string alias)
+ {
+ return parseResult
+ .AppliedOptions
+ .Where(o => o.HasAlias(alias))
+ .Select(o => o.Value())
+ .SingleOrDefault();
+ }
+
+ internal static void CreateLogger()
+ {
+ Log.Logger = new LoggerConfiguration()
+ .Enrich.FromLogContext()
+ .Enrich.WithDemystifiedStackTraces()
+ .MinimumLevel.ControlledBy(ProgramBase.verbosity)
+ .WriteTo.Console()
+ .CreateLogger();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/ProgramBase.PrimaryCommands.cs b/Project2015To2017.MigrateXXXX.Tool/ProgramBase.PrimaryCommands.cs
new file mode 100644
index 0000000..731d5c3
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/ProgramBase.PrimaryCommands.cs
@@ -0,0 +1,47 @@
+using Microsoft.DotNet.Cli.CommandLine;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ internal static partial class ProgramBase
+ {
+ internal static Command Evaluate() =>
+ Create.Command("evaluate",
+ "Examine the projects potential to be converted before actual migration",
+ ItemsArgument,
+ TargetFrameworksOption,
+ HelpOption());
+
+ internal static Command Migrate() =>
+ Create.Command("migrate",
+ "Migrate projects to modern Visual Studio CPS format (non-interactive)",
+ ItemsArgument,
+ Create.Option("-n|--no-backup",
+ "Skip moving project.json, global.json, and *.xproj to a `Backup` directory after successful migration."),
+ ForceOption,
+ KeepAssemblyInfoOption,
+ TargetFrameworksOption,
+ Create.Option("-o|--old-output-path",
+ "Preserve legacy behavior by not creating a subfolder with the target framework in the output path."),
+ Create.Option(
+ "-ft|--force-transformations",
+ "Force execution of transformations despite project conversion state by their specified names. " +
+ "Specify multiple times for multiple enforced transformations.",
+ Accept.OneOrMoreArguments()
+ .With("Transformation names to enforce execution", "names")),
+ HelpOption());
+
+ internal static Command Analyze() =>
+ Create.Command("analyze",
+ "Do the analysis run and output diagnostics",
+ ItemsArgument,
+ HelpOption());
+
+ internal static Command Wizard() =>
+ Create.Command("wizard",
+ "Launch interactive migration wizard (recommended)",
+ ItemsArgument,
+ ForceOption,
+ KeepAssemblyInfoOption,
+ HelpOption());
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/Project2015To2017.MigrateXXXX.Tool.proj b/Project2015To2017.MigrateXXXX.Tool/Project2015To2017.MigrateXXXX.Tool.proj
new file mode 100644
index 0000000..0744f3a
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/Project2015To2017.MigrateXXXX.Tool.proj
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Project2015To2017.MigrateXXXX.Tool/WizardTransformationSets.cs b/Project2015To2017.MigrateXXXX.Tool/WizardTransformationSets.cs
new file mode 100644
index 0000000..e1994d4
--- /dev/null
+++ b/Project2015To2017.MigrateXXXX.Tool/WizardTransformationSets.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Project2015To2017.Analysis;
+
+namespace Project2015To2017.Migrate2017.Tool
+{
+ public sealed class WizardTransformationSets
+ {
+ public ITransformationSet MigrateSet { get; set; }
+ public ITransformationSet ModernCleanUpSet { get; set; }
+ public ITransformationSet ModernizeSet { get; set; }
+ public HashSet Diagnostics { get; set; }
+ }
+}
diff --git a/Project2015To2017.Tests/PropertySimplificationTransformationTest.cs b/Project2015To2017.Tests/PropertySimplificationTransformationTest.cs
index e9c0e41..394c411 100644
--- a/Project2015To2017.Tests/PropertySimplificationTransformationTest.cs
+++ b/Project2015To2017.Tests/PropertySimplificationTransformationTest.cs
@@ -365,99 +365,6 @@ public void RemovesVisualStudioVersion()
Assert.IsTrue(!project.ProjectDocument.Descendants().Any(x => x.Name.LocalName == "VisualStudioVersion"));
}
- [TestMethod]
- public void RemovesServiceTagWithKnownTestFramework()
- {
- var guid = Guid.NewGuid();
- var xml = @"
-
-
- Debug
- AnyCPU
- {" + guid.ToString() + @"}
- Library
- Properties
- ClassLibrary1
- ClassLibrary1
- v4.6.1
- 512
- SAK
- SAK
- SAK
- SAK
- 10.0
-
-
-
-
-
- ";
-
- var project = ParseAndTransform(xml, projectName: "Class1");
- var name = "someproject";
- project.ProjectName = name;
- project.Solution = new Solution
- {
- ProjectPaths = new[]
- {
- new ProjectReference
- {
- ProjectName = name,
- ProjectGuid = guid
- }
- }
- };
-
- new PropertySimplificationTransformation().Transform(project);
-
- Assert.IsFalse(project.ProjectDocument.Descendants().Any(x => x.Name.LocalName == "Service"));
- }
-
- [TestMethod]
- public void DoesNotRemoveServiceTag()
- {
- var guid = Guid.NewGuid();
- var xml = @"
-
-
- Debug
- AnyCPU
- {" + guid.ToString() + @"}
- Library
- Properties
- ClassLibrary1
- ClassLibrary1
- v4.6.1
- 512
- SAK
- SAK
- SAK
- SAK
- 10.0
-
-
- ";
-
- var project = ParseAndTransform(xml, projectName: "Class1");
- var name = "someproject";
- project.ProjectName = name;
- project.Solution = new Solution
- {
- ProjectPaths = new[]
- {
- new ProjectReference
- {
- ProjectName = name,
- ProjectGuid = guid
- }
- }
- };
-
- new PropertySimplificationTransformation().Transform(project);
-
- Assert.IsTrue(project.ProjectDocument.Descendants().Any(x => x.Name.LocalName == "Service"));
- }
-
private static Project ParseAndTransform(
string xml,
[System.Runtime.CompilerServices.CallerMemberName]
diff --git a/Project2015To2017.Tests/ServiceFilterTransformationTest.cs b/Project2015To2017.Tests/ServiceFilterTransformationTest.cs
new file mode 100644
index 0000000..bbaf0f3
--- /dev/null
+++ b/Project2015To2017.Tests/ServiceFilterTransformationTest.cs
@@ -0,0 +1,188 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Project2015To2017.Definition;
+using Project2015To2017.Reading;
+using Project2015To2017.Transforms;
+
+namespace Project2015To2017.Tests
+{
+ [TestClass]
+ public class ServiceFilterTransformationTest
+ {
+ [DataRow(0, 0)]
+ [DataRow(15, 0)]
+ [DataRow(15, 6)]
+ [DataRow(15, 7)]
+ [DataRow(16, 0)]
+ [TestMethod]
+ public void RemovesServiceTagWithKnownTestFramework(int visualStudioVersionMajor, int visualStudioVersionMinor)
+ {
+ var guid = Guid.NewGuid();
+ var xml = @"
+
+
+ Debug
+ AnyCPU
+ {" + guid.ToString() + @"}
+ Library
+ Properties
+ ClassLibrary1
+ ClassLibrary1
+ v4.6.1
+ 512
+ SAK
+ SAK
+ SAK
+ SAK
+ 10.0
+
+
+
+
+
+ ";
+
+ var project = ParseAndTransform(xml, projectName: "Class1");
+ var name = "someproject";
+ project.ProjectName = name;
+ project.Solution = new Solution
+ {
+ ProjectPaths = new[]
+ {
+ new ProjectReference
+ {
+ ProjectName = name,
+ ProjectGuid = guid
+ }
+ }
+ };
+
+ new ServiceFilterTransformation(new Version(visualStudioVersionMajor, visualStudioVersionMinor)).Transform(project);
+
+ Assert.IsFalse(project.ProjectDocument.Descendants().Any(x => x.Name.LocalName == "Service"));
+ }
+
+ [DataRow(0, 0, true)]
+ [DataRow(15, 0, true)]
+ [DataRow(15, 6, true)]
+ [DataRow(15, 7, false)]
+ [DataRow(16, 0, false)]
+ [TestMethod]
+ public void RemovesServiceTagWithVisualStudioVersion(int visualStudioVersionMajor, int visualStudioVersionMinor, bool expected)
+ {
+ var guid = Guid.NewGuid();
+ var xml = @"
+
+
+ Debug
+ AnyCPU
+ {" + guid.ToString() + @"}
+ Library
+ Properties
+ ClassLibrary1
+ ClassLibrary1
+ v4.6.1
+ 512
+ SAK
+ SAK
+ SAK
+ SAK
+ 10.0
+
+
+
+
+ ";
+
+ var project = ParseAndTransform(xml, projectName: "Class1");
+ var name = "someproject";
+ project.ProjectName = name;
+ project.Solution = new Solution
+ {
+ ProjectPaths = new[]
+ {
+ new ProjectReference
+ {
+ ProjectName = name,
+ ProjectGuid = guid
+ }
+ }
+ };
+
+ new ServiceFilterTransformation(new Version(visualStudioVersionMajor, visualStudioVersionMinor)).Transform(project);
+
+ Assert.AreEqual(expected, project.ProjectDocument.Descendants().Any(x => x.Name.LocalName == "Service"));
+ }
+
+ [DataRow(0, 0)]
+ [DataRow(15, 0)]
+ [DataRow(15, 6)]
+ [DataRow(15, 7)]
+ [DataRow(16, 0)]
+ [TestMethod]
+ public void DoesNotRemoveServiceTag(int visualStudioVersionMajor, int visualStudioVersionMinor)
+ {
+ var guid = Guid.NewGuid();
+ var xml = @"
+
+
+ Debug
+ AnyCPU
+ {" + guid.ToString() + @"}
+ Library
+ Properties
+ ClassLibrary1
+ ClassLibrary1
+ v4.6.1
+ 512
+ SAK
+ SAK
+ SAK
+ SAK
+ 10.0
+
+
+ ";
+
+ var project = ParseAndTransform(xml, projectName: "Class1");
+ var name = "someproject";
+ project.ProjectName = name;
+ project.Solution = new Solution
+ {
+ ProjectPaths = new[]
+ {
+ new ProjectReference
+ {
+ ProjectName = name,
+ ProjectGuid = guid
+ }
+ }
+ };
+
+ new ServiceFilterTransformation(new Version(visualStudioVersionMajor, visualStudioVersionMinor)).Transform(project);
+
+ Assert.IsTrue(project.ProjectDocument.Descendants().Any(x => x.Name.LocalName == "Service"));
+ }
+
+ private static Project ParseAndTransform(
+ string xml,
+ [System.Runtime.CompilerServices.CallerMemberName]
+ string memberName = "",
+ string projectName = null
+ )
+ {
+ var testCsProjFile = $"{memberName}_test.csproj";
+
+ File.WriteAllText(testCsProjFile, xml, Encoding.UTF8);
+
+ var project = new ProjectReader().Read(testCsProjFile);
+ project.ProjectName = projectName;
+ project.FilePath = null;
+
+ return project;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Project2015To2017.sln b/Project2015To2017.sln
index 69f407e..6261156 100644
--- a/Project2015To2017.sln
+++ b/Project2015To2017.sln
@@ -25,6 +25,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Project2015To2017.Migrate20
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Project2015To2017.Migrate2019.Library", "Project2015To2017.Migrate2019.Library\Project2015To2017.Migrate2019.Library.csproj", "{69EB7F70-ACFD-43F7-829E-2FC340A27E41}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Project2015To2017.Migrate2019.Tool", "Project2015To2017.Migrate2019.Tool\Project2015To2017.Migrate2019.Tool.csproj", "{9B6CF418-64C3-4630-9838-5605EFAA5822}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -59,6 +61,10 @@ Global
{69EB7F70-ACFD-43F7-829E-2FC340A27E41}.Debug|Any CPU.Build.0 = Debug|Any CPU
{69EB7F70-ACFD-43F7-829E-2FC340A27E41}.Release|Any CPU.ActiveCfg = Release|Any CPU
{69EB7F70-ACFD-43F7-829E-2FC340A27E41}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9B6CF418-64C3-4630-9838-5605EFAA5822}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9B6CF418-64C3-4630-9838-5605EFAA5822}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9B6CF418-64C3-4630-9838-5605EFAA5822}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9B6CF418-64C3-4630-9838-5605EFAA5822}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Project2015To2017/MigrationFacility.cs b/Project2015To2017/MigrationFacility.cs
index 0b61c9a..0900996 100644
--- a/Project2015To2017/MigrationFacility.cs
+++ b/Project2015To2017/MigrationFacility.cs
@@ -139,7 +139,7 @@ public void DoAnalysis(IEnumerable projects, AnalysisOptions options =
}
}
- return (convertedProjects, convertedSolutions);
+ return (convertedProjects.Distinct(Project.ProjectNameFilePathComparer).ToArray(), convertedSolutions.Distinct(Solution.FilePathComparer).ToArray());
void ProcessSingleItem(FileInfo file, string extension)
{
@@ -176,9 +176,31 @@ void ProcessSingleItem(FileInfo file, string extension)
public void ExecuteEvaluate(
IReadOnlyCollection items,
- ConversionOptions conversionOptions)
+ ConversionOptions conversionOptions = null,
+ ITransformationSet transformationSet = null,
+ AnalysisOptions analysisOptions = null)
{
- var (projects, solutions) = ParseProjects(items, Vs15TransformationSet.Instance, conversionOptions);
+ if (transformationSet != null && analysisOptions == null)
+ {
+ Logger.LogWarning("You should pass AnalysisOptions if you pass ITransformationSet, falling back to using default diagnostic set");
+ }
+
+ if (transformationSet == null && analysisOptions == null)
+ {
+ Logger.LogDebug("Legacy signature usage, please specify all options instead");
+ analysisOptions = new AnalysisOptions(Vs15DiagnosticSet.All);
+ }
+
+ if (transformationSet == null)
+ {
+ Logger.LogDebug("Using default VS2015 migration transformation set, please specify the one you need instead");
+ transformationSet = Vs15TransformationSet.Instance;
+ }
+
+ conversionOptions = conversionOptions ?? new ConversionOptions();
+ analysisOptions = analysisOptions ?? new AnalysisOptions();
+
+ var (projects, solutions) = ParseProjects(items, transformationSet, conversionOptions);
if (projects.Count == 0)
{
@@ -187,7 +209,7 @@ public void ExecuteEvaluate(
var alreadyConverted = projects.Where(x => x.IsModernProject).ToImmutableArray();
- DoAnalysis(projects, new AnalysisOptions(Vs15DiagnosticSet.All));
+ DoAnalysis(projects, analysisOptions);
Logger.LogInformation("List of modern CPS projects:");
foreach (var projectPath in alreadyConverted.Select(x => x.FilePath))
@@ -205,19 +227,11 @@ public void ExecuteEvaluate(
}
}
- public void ExecuteMigrate(
- IReadOnlyCollection items,
- ITransformationSet transformations
- )
- {
- ExecuteMigrate(items, transformations, new ConversionOptions(), new ProjectWriteOptions());
- }
-
+ [Obsolete]
public void ExecuteMigrate(
IReadOnlyCollection items,
ConversionOptions conversionOptions,
- ProjectWriteOptions writeOptions
- )
+ ProjectWriteOptions writeOptions)
{
ExecuteMigrate(items, Vs15TransformationSet.Instance, conversionOptions, writeOptions);
}
@@ -225,10 +239,13 @@ ProjectWriteOptions writeOptions
public void ExecuteMigrate(
IReadOnlyCollection items,
ITransformationSet transformations,
- ConversionOptions conversionOptions,
- ProjectWriteOptions writeOptions
- )
+ ConversionOptions conversionOptions = null,
+ ProjectWriteOptions writeOptions = null,
+ AnalysisOptions analysisOptions = null)
{
+ conversionOptions = conversionOptions ?? new ConversionOptions();
+ writeOptions = writeOptions ?? new ProjectWriteOptions();
+
var (projects, _) = ParseProjects(items, transformations, conversionOptions);
if (projects.Count == 0)
@@ -246,12 +263,13 @@ ProjectWriteOptions writeOptions
(projects, _) = ParseProjects(items, BasicReadTransformationSet.Instance, conversionOptions);
- DoAnalysis(projects);
+ DoAnalysis(projects, analysisOptions);
}
public void ExecuteAnalyze(
IReadOnlyCollection items,
- ConversionOptions conversionOptions)
+ ConversionOptions conversionOptions,
+ AnalysisOptions analysisOptions = null)
{
var (projects, _) = ParseProjects(items, BasicReadTransformationSet.Instance, conversionOptions);
@@ -260,7 +278,7 @@ public void ExecuteAnalyze(
return;
}
- DoAnalysis(projects);
+ DoAnalysis(projects, analysisOptions);
}
}
}
\ No newline at end of file
diff --git a/appveyor.yml b/appveyor.yml
index 2ee1e41..b3c72b3 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: 4.0.{build}
+version: 4.1.{build}
skip_tags: true
image:
- Visual Studio 2019 Preview
@@ -10,67 +10,72 @@ skip_branch_with_pr: true
environment:
LOGGER: '/l:"C:\Program Files\AppVeyor\BuildAgent\dotnetcore\Appveyor.MSBuildLogger.dll"'
LIBRARY: './Project2015To2017/Project2015To2017.csproj'
- LEGACYCLITOOL: './Project2015To2017.Console/Project2015To2017.Console.csproj'
- CLITOOL: './Project2015To2017.Migrate2017.Tool/Project2015To2017.Migrate2017.Tool.csproj'
+ CLITOOL2017: './Project2015To2017.Migrate2017.Tool/Project2015To2017.Migrate2017.Tool.csproj'
+ CLITOOL2019: './Project2015To2017.Migrate2019.Tool/Project2015To2017.Migrate2019.Tool.csproj'
build_script:
- cmd: dotnet --version
- cmd: dotnet pack %LIBRARY% %LOGGER% -v m -c %configuration% --force /p:Pack=true
- - cmd: dotnet pack %LEGACYCLITOOL% %LOGGER% -v m -c %configuration% --force /p:Pack=true
- - cmd: dotnet pack %CLITOOL% %LOGGER% -v m -c %configuration% --force /p:Pack=true
- - cmd: dotnet publish %CLITOOL% %LOGGER% -v m -c %configuration% -f netcoreapp2.1 -o ./out/netcoreapp2.1
- - cmd: dotnet publish %CLITOOL% %LOGGER% -v m -c %configuration% -f net461 -o ./out/net461
+ - cmd: dotnet pack %CLITOOL2017% %LOGGER% -v m -c %configuration% --force /p:Pack=true
+ - cmd: dotnet publish %CLITOOL2017% %LOGGER% -v m -c %configuration% -f netcoreapp2.1 -o ./out2017/netcoreapp2.1
+ - cmd: dotnet publish %CLITOOL2017% %LOGGER% -v m -c %configuration% -f net461 -o ./out2017/net461
+ - cmd: dotnet pack %CLITOOL2019% %LOGGER% -v m -c %configuration% --force /p:Pack=true
+ - cmd: dotnet publish %CLITOOL2019% %LOGGER% -v m -c %configuration% -f netcoreapp2.1 -o ./out2019/netcoreapp2.1
+ - cmd: dotnet publish %CLITOOL2019% %LOGGER% -v m -c %configuration% -f net461 -o ./out2019/net461
after_build:
- - cmd: 7z a ./dotnet-migrate-2017.zip ./out/*
+ - cmd: 7z a ./dotnet-migrate-2017.zip ./out2017/*
+ - cmd: 7z a ./dotnet-migrate-2019.zip ./out2019/*
test_script:
- cmd: dotnet test Project2015To2017.Tests/Project2015To2017.Tests.csproj -c %configuration% --test-adapter-path:. --logger:Appveyor
artifacts:
- - path: ./Project2015To2017.Console/bin/$(configuration)/Project2015To2017.Cli.**.nupkg
- name: global-tool-legacy
- path: ./Project2015To2017.Migrate2017.Tool/bin/$(configuration)/Project2015To2017.Migrate2017.Tool.**.nupkg
- name: global-tool
+ name: global-tool-2017
+ - path: ./Project2015To2017.Migrate2019.Tool/bin/$(configuration)/Project2015To2017.Migrate2019.Tool.**.nupkg
+ name: global-tool-2019
- path: ./dotnet-migrate-2017.zip
- name: out-zip
+ name: out-zip-2017
+ - path: ./dotnet-migrate-2019.zip
+ name: out-zip-2019
- path: Project2015To2017\bin\$(configuration)\Project2015To2017.**.nupkg
name: nupkg
-
+
deploy:
- provider: NuGet
api_key:
secure: BzG/1VAXhFOoaGkbPFAKE1/D2jV7fbwBoXe2wCJsj5jtIANB1THXwOIcFGmNaQtH
skip_symbols: false
artifact: nupkg
-
+ on:
+ branch: master
+
- provider: NuGet
api_key:
- secure: AwfCakaWfhBSFa7M+QoESC9wuzZSDQ5/hn3Rpgj7b5nPM1zm6ge6crkvbW7L6i7U
+ secure: ONRE7O/9v0W/ZyO0EwYRW7BOFZhVV9h8pxGtaFCO7aNglrElUGZ+MEFbDh0j5A9S
skip_symbols: false
- artifact: global-tool-legacy
-
+ artifact: global-tool-2017
+ on:
+ branch: master
+
- provider: NuGet
api_key:
- secure: ONRE7O/9v0W/ZyO0EwYRW7BOFZhVV9h8pxGtaFCO7aNglrElUGZ+MEFbDh0j5A9S
+ secure: BmoLFLk70U1TUsSiscVfwGFaT8v8N4G9eJNCnPQRvFoXiGKYed6IxYaN6eRr28t3
skip_symbols: false
- artifact: global-tool
-
-#- provider: NuGet
-# api_key:
-# secure: BmoLFLk70U1TUsSiscVfwGFaT8v8N4G9eJNCnPQRvFoXiGKYed6IxYaN6eRr28t3
-# skip_symbols: false
-# artifact: global-tool-2019
+ artifact: global-tool-2019
+ on:
+ branch: master
- provider: GitHub
- release: dotnet-migrate-2017-v$(APPVEYOR_BUILD_VERSION)
+ release: dotnet-migrate-v$(APPVEYOR_BUILD_VERSION)
description: 'Automatically built release v$(APPVEYOR_BUILD_VERSION).'
auth_token:
secure: "LYFGDMnT4oJLpCsZUkhL/oTnG3ZpQnsjaTc10DfTf/jbkXtzctRkXEu2ea3YnyqP"
- artifact: out-zip
+ artifact: out-zip-2017,out-zip-2019
draft: true
prerelease: true
on:
- branch: master # deploy on tag push only
+ branch: master
# build cache to preserve files/folders between builds
cache:
- packages -> **\packages.config # preserve "packages" directory in the root of build folder but will reset it if packages.config is modified
- - '%LocalAppData%\NuGet\Cache'
+ - '%LocalAppData%\NuGet\Cache'
\ No newline at end of file