diff --git a/.gitignore b/.gitignore index 6a8559370..b06878e45 100644 --- a/.gitignore +++ b/.gitignore @@ -356,4 +356,6 @@ MigrationBackup/ # Local testing files **/*/launchSettings.json -**/*/FolderProfile.pubxml \ No newline at end of file +**/*/FolderProfile.pubxml + +.tools/* \ No newline at end of file diff --git a/eng/Versions.props b/eng/Versions.props index 21b4c2a90..7dc1cdbc3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -2,7 +2,7 @@ 0 - 5 + 6 @@ -11,21 +11,21 @@ --> 1.2.6 - 16.0.461 - 4.7.0 - 12.0.2 - 5.5.0 - 1.5.0 - 2.0.0-beta1.20214.1 - 4.7.0 - 4.7.0 + 16.7 + 5.0.0-rc.1.20451.14 + 12.0.3 + 5.8.0-preview.3.6823 + 5.0.0-rc.1.20451.14 + 2.0.0-beta1.20371.2 + 5.0.0-rc.1.20451.14 + 5.0.0-rc.1.20451.14 - 1.0.1 - 4.13.0 + 1.3.0 + 4.14.6 true diff --git a/src/MSBuild.Abstractions/BaselineProject.cs b/src/MSBuild.Abstractions/BaselineProject.cs index 6a1eb317a..1c7609ea5 100644 --- a/src/MSBuild.Abstractions/BaselineProject.cs +++ b/src/MSBuild.Abstractions/BaselineProject.cs @@ -12,27 +12,46 @@ public struct BaselineProject public readonly UnconfiguredProject Project; public readonly ProjectStyle ProjectStyle; public readonly ProjectOutputType OutputType; + public readonly string TargetTFM; - public BaselineProject(UnconfiguredProject project, ImmutableArray globalProperties, ProjectStyle projectStyle, ProjectOutputType outputType) : this() + public BaselineProject(UnconfiguredProject project, ImmutableArray globalProperties, ProjectStyle projectStyle, ProjectOutputType outputType, string candidateTargetTFM, bool keepCurrentTFMs) : this() { GlobalProperties = globalProperties; Project = project ?? throw new ArgumentNullException(nameof(project)); ProjectStyle = projectStyle; OutputType = outputType; + TargetTFM = keepCurrentTFMs + ? GetCurrentTFM(globalProperties, project) + : AdjustTargetTFM(projectStyle, outputType, candidateTargetTFM); } - public string GetTfm() + private static string AdjustTargetTFM(ProjectStyle projectStyle, ProjectOutputType outputType, string candidateTargetTFM) { - if (GlobalProperties.Contains(MSBuildFacts.TargetFrameworkNodeName, StringComparer.OrdinalIgnoreCase)) + if (candidateTargetTFM.ContainsIgnoreCase(MSBuildFacts.Net5) && projectStyle == ProjectStyle.WindowsDesktop) + { + return MSBuildFacts.Net5Windows; + } + + if (outputType == ProjectOutputType.Library) + { + return MSBuildFacts.NetStandard20; + } + + return candidateTargetTFM; + } + + private static string GetCurrentTFM(ImmutableArray globalProperties, UnconfiguredProject project) + { + if (globalProperties.Contains(MSBuildFacts.TargetFrameworkNodeName, StringComparer.OrdinalIgnoreCase)) { // The original project had a TargetFramework property. No need to add it again. - return GlobalProperties.First(p => p.Equals(MSBuildFacts.TargetFrameworkNodeName, StringComparison.OrdinalIgnoreCase)); + return globalProperties.First(p => p.Equals(MSBuildFacts.TargetFrameworkNodeName, StringComparison.OrdinalIgnoreCase)); } - var rawTFM = Project.FirstConfiguredProject.GetProperty(MSBuildFacts.TargetFrameworkNodeName)?.EvaluatedValue; + var rawTFM = project.FirstConfiguredProject.GetProperty(MSBuildFacts.TargetFrameworkNodeName)?.EvaluatedValue; if (rawTFM == null) { throw new InvalidOperationException( - $"{MSBuildFacts.TargetFrameworkNodeName} is not set in {nameof(Project.FirstConfiguredProject)}"); + $"{MSBuildFacts.TargetFrameworkNodeName} is not set in {nameof(project.FirstConfiguredProject)}"); } // This is pretty much never gonna happen, but it was cheap to write the code diff --git a/src/MSBuild.Abstractions/MSBuildConversionWorkspace.cs b/src/MSBuild.Abstractions/MSBuildConversionWorkspace.cs index 1a7225095..c379a6129 100644 --- a/src/MSBuild.Abstractions/MSBuildConversionWorkspace.cs +++ b/src/MSBuild.Abstractions/MSBuildConversionWorkspace.cs @@ -15,7 +15,7 @@ public class MSBuildConversionWorkspace { public ImmutableArray WorkspaceItems { get; } - public MSBuildConversionWorkspace(ImmutableArray paths, bool noBackup) + public MSBuildConversionWorkspace(ImmutableArray paths, bool noBackup, string tfm, bool keepCurrentTFMs) { var items = ImmutableArray.CreateBuilder(); @@ -49,7 +49,7 @@ public MSBuildConversionWorkspace(ImmutableArray paths, bool noBackup) var unconfiguredProject = new UnconfiguredProject(configurations); unconfiguredProject.LoadProjects(collection, globalProperties, path); - var baseline = CreateSdkBaselineProject(path, unconfiguredProject.FirstConfiguredProject, root, configurations); + var baseline = CreateSdkBaselineProject(path, unconfiguredProject.FirstConfiguredProject, root, configurations, tfm, keepCurrentTFMs); root.Reload(throwIfUnsavedChanges: false, preserveFormatting: true); var item = new MSBuildConversionWorkspaceItem(root, unconfiguredProject, baseline); @@ -90,7 +90,7 @@ public ImmutableDictionary> Determin /// We need to use the same name as the original csproj and same path so that all the default that derive /// from name\path get the right values (there are a lot of them). /// - private BaselineProject CreateSdkBaselineProject(string projectFilePath, IProject project, IProjectRootElement root, ImmutableDictionary> configurations) + private BaselineProject CreateSdkBaselineProject(string projectFilePath, IProject project, IProjectRootElement root, ImmutableDictionary> configurations, string tfm, bool keepCurrentTFMs) { var projectStyle = GetProjectStyle(root); var outputType = GetProjectOutputType(root); @@ -105,7 +105,10 @@ private BaselineProject CreateSdkBaselineProject(string projectFilePath, IProjec rootElement.Sdk = MSBuildFacts.DefaultSDKAttribute; break; case ProjectStyle.WindowsDesktop: - rootElement.Sdk = DesktopFacts.WinSDKAttribute; + rootElement.Sdk = + tfm.ContainsIgnoreCase(MSBuildFacts.Net5) + ? MSBuildFacts.DefaultSDKAttribute + : DesktopFacts.WinSDKAttribute; // pre-.NET 5 apps need a special SDK attribute. break; default: throw new NotSupportedException($"This project has custom imports in a manner that's not supported. '{projectFilePath}'"); @@ -158,7 +161,12 @@ private BaselineProject CreateSdkBaselineProject(string projectFilePath, IProjec propertiesInTheBaseline = propertiesInTheBaseline.Add(DesktopFacts.UseWPFPropertyName); } - return new BaselineProject(newProject, propertiesInTheBaseline, projectStyle, outputType); + tfm = + projectStyle == ProjectStyle.WindowsDesktop && tfm.ContainsIgnoreCase(MSBuildFacts.Net5) + ? MSBuildFacts.Net5Windows + : tfm; + + return new BaselineProject(newProject, propertiesInTheBaseline, projectStyle, outputType, tfm, keepCurrentTFMs); } private bool IsSupportedOutputType(ProjectOutputType type) => diff --git a/src/MSBuild.Abstractions/MSBuildConversionWorkspaceLoader.cs b/src/MSBuild.Abstractions/MSBuildConversionWorkspaceLoader.cs index fb544f744..76a465d52 100644 --- a/src/MSBuild.Abstractions/MSBuildConversionWorkspaceLoader.cs +++ b/src/MSBuild.Abstractions/MSBuildConversionWorkspaceLoader.cs @@ -29,7 +29,7 @@ public MSBuildConversionWorkspaceLoader(string workspacePath, MSBuildConversionW _workspaceType = workspaceType; } - public MSBuildConversionWorkspace LoadWorkspace(string path, bool noBackup) + public MSBuildConversionWorkspace LoadWorkspace(string path, bool noBackup, string tfm, bool keepCurrentTFMs) { var projectPaths = _workspaceType switch @@ -42,7 +42,7 @@ public MSBuildConversionWorkspace LoadWorkspace(string path, bool noBackup) _ => throw new InvalidOperationException("Somehow, an enum that isn't possible was passed in here.") }; - return new MSBuildConversionWorkspace(projectPaths, noBackup); + return new MSBuildConversionWorkspace(projectPaths, noBackup, tfm, keepCurrentTFMs); static bool IsSupportedSolutionItemType(ProjectInSolution project) { diff --git a/src/MSBuild.Abstractions/MSBuildHelpers.cs b/src/MSBuild.Abstractions/MSBuildHelpers.cs index 03e1b77ae..2f64efd27 100644 --- a/src/MSBuild.Abstractions/MSBuildHelpers.cs +++ b/src/MSBuild.Abstractions/MSBuildHelpers.cs @@ -3,7 +3,6 @@ using System.Collections.Immutable; using System.IO; using System.Linq; -using System.Reflection; using System.Text.RegularExpressions; using Microsoft.Build.Construction; @@ -173,7 +172,14 @@ public static IEnumerable GetAllProjectTypeGuids(IProjectRootElement roo public static bool IsWPF(IProjectRootElement projectRoot) { var references = projectRoot.ItemGroups.SelectMany(GetReferences)?.Select(elem => elem.Include.Split(',').First()); - return DesktopFacts.KnownWPFReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase)); + if (references is null) + { + return false; + } + else + { + return DesktopFacts.KnownWPFReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase)); + } } /// @@ -182,7 +188,14 @@ public static bool IsWPF(IProjectRootElement projectRoot) public static bool IsWinForms(IProjectRootElement projectRoot) { var references = projectRoot.ItemGroups.SelectMany(GetReferences)?.Select(elem => elem.Include.Split(',').First()); - return DesktopFacts.KnownWinFormsReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase)); + if (references is null) + { + return false; + } + else + { + return DesktopFacts.KnownWinFormsReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase)); + } } /// @@ -191,7 +204,14 @@ public static bool IsWinForms(IProjectRootElement projectRoot) public static bool IsDesktop(IProjectRootElement projectRoot) { var references = projectRoot.ItemGroups.SelectMany(GetReferences)?.Select(elem => elem.Include.Split(',').First()); - return DesktopFacts.KnownDesktopReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase)); + if (references is null) + { + return false; + } + else + { + return DesktopFacts.KnownDesktopReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase)); + } } /// @@ -202,7 +222,14 @@ public static bool IsDesktop(IProjectRootElement projectRoot) public static bool IsNETFrameworkMSTestProject(IProjectRootElement projectRoot) { var references = projectRoot.ItemGroups.SelectMany(GetReferences)?.Select(elem => elem.Include.Split(',').First()); - return MSTestFacts.MSTestReferences.All(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase)); + if (references is null) + { + return false; + } + else + { + return MSTestFacts.MSTestReferences.All(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase)); + } } public static bool HasWPFOrWinForms(ProjectPropertyGroupElement propGroup) @@ -221,7 +248,7 @@ public static bool IsNotNetFramework(string tfm) => /// /// Finds the item group where a packages.config is included. Assumes only one. /// - public static ProjectItemGroupElement GetPackagesConfigItemGroup(IProjectRootElement root) => + public static ProjectItemGroupElement? GetPackagesConfigItemGroup(IProjectRootElement root) => root.ItemGroups.FirstOrDefault(pige => pige.Items.Any(pe => pe.Include.Equals(PackageFacts.PackagesConfigIncludeName, StringComparison.OrdinalIgnoreCase))); /// diff --git a/src/MSBuild.Abstractions/ProjectExtensions.cs b/src/MSBuild.Abstractions/ProjectExtensions.cs index d6e358a01..5197cc82c 100644 --- a/src/MSBuild.Abstractions/ProjectExtensions.cs +++ b/src/MSBuild.Abstractions/ProjectExtensions.cs @@ -83,7 +83,13 @@ private static string GetTargetFrameworkFromProjectJson(IProject project) var json = JObject.Parse(projectJsonContents); var frameworks = json["frameworks"]; + if (frameworks is null) + { + throw new InvalidOperationException($"No target framework set in this 'project.json' file located at '{projectJsonPath}'."); + } + var tf = ((JProperty)frameworks.Single()).Name; + return tf; } } diff --git a/src/MSBuild.Abstractions/ProjectItemHelpers.cs b/src/MSBuild.Abstractions/ProjectItemHelpers.cs index ac59d5b7a..056bd88ba 100644 --- a/src/MSBuild.Abstractions/ProjectItemHelpers.cs +++ b/src/MSBuild.Abstractions/ProjectItemHelpers.cs @@ -31,7 +31,8 @@ public static bool IsSpecificPacakgeReference(ProjectItemElement element, string public static bool DesktopReferencesNeedsRemoval(ProjectItemElement item) => DesktopFacts.ReferencesThatNeedRemoval.Contains(item.Include, StringComparer.OrdinalIgnoreCase) || DesktopFacts.KnownWPFReferences.Contains(item.Include, StringComparer.OrdinalIgnoreCase) - || DesktopFacts.KnownWinFormsReferences.Contains(item.Include, StringComparer.OrdinalIgnoreCase); + || DesktopFacts.KnownWinFormsReferences.Contains(item.Include, StringComparer.OrdinalIgnoreCase) + || DesktopFacts.KnownDesktopReferences.Contains(item.Include, StringComparer.OrdinalIgnoreCase); /// /// Checks if a given item is a desktop item that is globbed, so long as the metadata is a form type. diff --git a/src/MSBuild.Conversion.Facts/MSBuildFacts.cs b/src/MSBuild.Conversion.Facts/MSBuildFacts.cs index b96b721e7..00428ad21 100644 --- a/src/MSBuild.Conversion.Facts/MSBuildFacts.cs +++ b/src/MSBuild.Conversion.Facts/MSBuildFacts.cs @@ -227,8 +227,10 @@ public static class MSBuildFacts public const string TargetsSuffix = ".targets"; public const string PropsSuffix = ".props"; public const string PackagesSubstring = @"\packages"; - public const string Netstandard20 = "netstandard2.0"; - public const string Netcoreapp31 = "netcoreapp3.1"; + public const string NetStandard20 = "netstandard2.0"; + public const string NetCoreApp31 = "netcoreapp3.1"; + public const string Net5 = "net5.0"; + public const string Net5Windows = "net5.0-windows"; public const string AppConfig = "App.config"; } } diff --git a/src/MSBuild.Conversion.Project/Converter.cs b/src/MSBuild.Conversion.Project/Converter.cs index 54ea20f76..a863d6786 100644 --- a/src/MSBuild.Conversion.Project/Converter.cs +++ b/src/MSBuild.Conversion.Project/Converter.cs @@ -5,8 +5,6 @@ using System.Xml.Linq; using MSBuild.Abstractions; -using MSBuild.Conversion.Facts; -using MSBuild.Conversion.SDK; namespace MSBuild.Conversion.Project { @@ -25,65 +23,30 @@ public Converter(UnconfiguredProject project, BaselineProject sdkBaselineProject _differs = GetDiffers(); } - public void Convert(string outputPath, string? specifiedTFM, bool keepCurrentTfm, bool usePreviewSDK) + public void Convert(string outputPath) { - ConvertProjectFile(specifiedTFM, keepCurrentTfm, usePreviewSDK); + ConvertProjectFile(); CleanUpProjectFile(outputPath); } - internal IProjectRootElement? ConvertProjectFile(string? specifiedTFM, bool keepCurrentTfm, bool usePreviewSDK) + internal IProjectRootElement? ConvertProjectFile() { - var tfm = GetBestTFM(_sdkBaselineProject, keepCurrentTfm, specifiedTFM, usePreviewSDK); - return _projectRootElement // Let's convert packages first, since that's what you should do manually anyways - .ConvertAndAddPackages(_sdkBaselineProject.ProjectStyle, tfm) + .ConvertAndAddPackages(_sdkBaselineProject.ProjectStyle, _sdkBaselineProject.TargetTFM) // Now we can convert the project over .ChangeImportsAndAddSdkAttribute(_sdkBaselineProject) .RemoveDefaultedProperties(_sdkBaselineProject, _differs) .RemoveUnnecessaryPropertiesNotInSDKByDefault(_sdkBaselineProject.ProjectStyle) - .AddTargetFrameworkProperty(_sdkBaselineProject, tfm) + .AddTargetFrameworkProperty(_sdkBaselineProject, _sdkBaselineProject.TargetTFM) .AddGenerateAssemblyInfoAsFalse() .AddDesktopProperties(_sdkBaselineProject) .AddCommonPropertiesToTopLevelPropertyGroup() - .RemoveOrUpdateItems(_differs, _sdkBaselineProject, tfm) + .RemoveOrUpdateItems(_differs, _sdkBaselineProject, _sdkBaselineProject.TargetTFM) .AddItemRemovesForIntroducedItems(_differs) .RemoveUnnecessaryTargetsIfTheyExist() .ModifyProjectElement(); - - static string GetBestTFM(BaselineProject baselineProject, bool keepCurrentTfm, string? specifiedTFM, bool usePreviewSDK) - { - if (string.IsNullOrWhiteSpace(specifiedTFM)) - { - // Let's figure this out, friends - var tfmForApps = TargetFrameworkHelper.FindHighestInstalledTargetFramework(usePreviewSDK); - - if (keepCurrentTfm) - { - specifiedTFM = baselineProject.GetTfm(); - } - else if (baselineProject.ProjectStyle == ProjectStyle.WindowsDesktop || baselineProject.ProjectStyle == ProjectStyle.MSTest) - { - specifiedTFM = tfmForApps; - } - else if (baselineProject.OutputType == ProjectOutputType.Library) - { - specifiedTFM = MSBuildFacts.Netstandard20; - } - else if (baselineProject.OutputType == ProjectOutputType.Exe) - { - specifiedTFM = tfmForApps; - } - else - { - // Default is to just use what exists in the project - specifiedTFM = baselineProject.GetTfm(); - } - } - - return specifiedTFM; - } } internal ImmutableDictionary GetDiffers() => @@ -97,7 +60,14 @@ private void CleanUpProjectFile(string outputPath) projectXml.Descendants().Attributes().Where(x => x.IsNamespaceDeclaration).Remove(); foreach (var element in projectXml.Descendants()) { - element.Name = element.Name.LocalName; + if (element is null) + { + continue; + } + + // Appears to be a nullability bug? + // Also the diagnostic doesn't show in the editor + element.Name = element.Name.LocalName!; } // remove all use of ProductVersion diff --git a/src/MSBuild.Conversion.Project/ProjectRootElementExtensionsForConversion.cs b/src/MSBuild.Conversion.Project/ProjectRootElementExtensionsForConversion.cs index 3ca53bd95..c7a294dcc 100644 --- a/src/MSBuild.Conversion.Project/ProjectRootElementExtensionsForConversion.cs +++ b/src/MSBuild.Conversion.Project/ProjectRootElementExtensionsForConversion.cs @@ -14,21 +14,18 @@ public static class ProjectRootElementExtensionsForConversion { public static IProjectRootElement ChangeImportsAndAddSdkAttribute(this IProjectRootElement projectRootElement, BaselineProject baselineProject) { - switch (baselineProject.ProjectStyle) + foreach (var import in projectRootElement.Imports) { - case ProjectStyle.Default: - case ProjectStyle.DefaultSubset: - case ProjectStyle.WindowsDesktop: - case ProjectStyle.MSTest: - foreach (var import in projectRootElement.Imports) - { - projectRootElement.RemoveChild(import); - } + projectRootElement.RemoveChild(import); + } - projectRootElement.Sdk = MSBuildHelpers.IsWinForms(projectRootElement) || MSBuildHelpers.IsWPF(projectRootElement) || MSBuildHelpers.IsDesktop(projectRootElement) - ? DesktopFacts.WinSDKAttribute - : MSBuildFacts.DefaultSDKAttribute; - break; + if (baselineProject.ProjectStyle is ProjectStyle.WindowsDesktop && baselineProject.TargetTFM is MSBuildFacts.NetCoreApp31) + { + projectRootElement.Sdk = DesktopFacts.WinSDKAttribute; + } + else + { + projectRootElement.Sdk = MSBuildFacts.DefaultSDKAttribute; } return projectRootElement; diff --git a/src/MSBuild.Conversion.SDK/TargetFrameworkHelper.cs b/src/MSBuild.Conversion.SDK/TargetFrameworkHelper.cs index 00934bc5e..aa96292f7 100644 --- a/src/MSBuild.Conversion.SDK/TargetFrameworkHelper.cs +++ b/src/MSBuild.Conversion.SDK/TargetFrameworkHelper.cs @@ -68,11 +68,19 @@ public static string FindHighestInstalledTargetFramework(bool usePreviewSDK) // read the template.json file to see what the tfm is called var doc = JsonDocument.ParseAsync(templatesJson).GetAwaiter().GetResult(); - return doc.RootElement.GetProperty("baselines").GetProperty("app").GetProperty("defaultOverrides").GetProperty("Framework").GetString(); + var tfm = doc.RootElement.GetProperty("baselines").GetProperty("app").GetProperty("defaultOverrides").GetProperty("Framework").GetString(); + if (string.IsNullOrEmpty(tfm)) + { + return MSBuildFacts.Net5; + } + else + { + return tfm; + } } catch (Exception) { - return MSBuildFacts.Netcoreapp31; + return MSBuildFacts.NetCoreApp31; } } diff --git a/src/try-convert/Program.cs b/src/try-convert/Program.cs index 8fcf05f09..129e94ccd 100644 --- a/src/try-convert/Program.cs +++ b/src/try-convert/Program.cs @@ -19,7 +19,7 @@ private static async Task Main(string[] args) var rootCommand = new RootCommand { Name = "try-convert", - Handler = CommandHandler.Create(typeof(Program).GetMethod(nameof(Run))) + Handler = CommandHandler.Create(typeof(Program).GetMethod(nameof(Run))!) }; var parser = @@ -44,7 +44,7 @@ private static async Task Main(string[] args) return await parser.InvokeAsync(args).ConfigureAwait(false); } - public static int Run(string? project, string? workspace, string? msbuildPath, string? tfm, bool allowPreviews, bool diffOnly, bool noBackup, bool keepCurrentTfms) + public static int Run(string? project, string? workspace, string? msbuildPath, string? tfm, bool preview, bool diffOnly, bool noBackup, bool keepCurrentTfms) { if (!string.IsNullOrWhiteSpace(project) && !string.IsNullOrWhiteSpace(workspace)) { @@ -76,6 +76,10 @@ public static int Run(string? project, string? workspace, string? msbuildPath, s return -1; } } + else + { + tfm = TargetFrameworkHelper.FindHighestInstalledTargetFramework(preview); + } var workspacePath = string.Empty; MSBuildConversionWorkspaceType workspaceType; @@ -95,19 +99,27 @@ public static int Run(string? project, string? workspace, string? msbuildPath, s var workspaceLoader = new MSBuildConversionWorkspaceLoader(workspacePath, workspaceType); // do not create backup if --diff-only specified noBackup = noBackup || diffOnly; - var msbuildWorkspace = workspaceLoader.LoadWorkspace(workspacePath, noBackup); + var msbuildWorkspace = workspaceLoader.LoadWorkspace(workspacePath, noBackup, tfm, keepCurrentTfms); foreach (var item in msbuildWorkspace.WorkspaceItems) { if (diffOnly) { var differ = new Differ(item.UnconfiguredProject.FirstConfiguredProject, item.SdkBaselineProject.Project.FirstConfiguredProject); - differ.GenerateReport(Directory.GetParent(workspacePath).FullName); + var parent = Directory.GetParent(workspacePath); + if (parent is null) + { + differ.GenerateReport(workspacePath); + } + else + { + differ.GenerateReport(parent.FullName); + } } else { var converter = new Converter(item.UnconfiguredProject, item.SdkBaselineProject, item.ProjectRootElement); - converter.Convert(item.ProjectRootElement.FullPath, tfm, keepCurrentTfms, allowPreviews); + converter.Convert(item.ProjectRootElement.FullPath); } } } diff --git a/tests/TestData/SmokeTests.FSharpConsoleBaseline/SmokeTests.FSharpConsoleBaselineNetCoreApp31.fsproj b/tests/TestData/SmokeTests.FSharpConsoleBaseline/SmokeTests.FSharpConsoleBaselineNetCoreApp31.fsproj new file mode 100644 index 000000000..f88a79e94 --- /dev/null +++ b/tests/TestData/SmokeTests.FSharpConsoleBaseline/SmokeTests.FSharpConsoleBaselineNetCoreApp31.fsproj @@ -0,0 +1,18 @@ + + + net472 + Exe + false + + + + + + + \ No newline at end of file diff --git a/tests/TestData/SmokeTests.WinformsCoreBaseline/SmokeTests.WinformsCoreBaseline.csproj b/tests/TestData/SmokeTests.WinformsCoreBaseline/SmokeTests.WinformsCoreBaseline.csproj index 2466621f4..32f9f8823 100644 --- a/tests/TestData/SmokeTests.WinformsCoreBaseline/SmokeTests.WinformsCoreBaseline.csproj +++ b/tests/TestData/SmokeTests.WinformsCoreBaseline/SmokeTests.WinformsCoreBaseline.csproj @@ -1,12 +1,14 @@ - - + + netcoreapp3.1 WinExe false true + + diff --git a/tests/TestData/SmokeTests.WinformsNet5Baseline/Form1.Designer.cs b/tests/TestData/SmokeTests.WinformsNet5Baseline/Form1.Designer.cs new file mode 100644 index 000000000..21ac9bde3 --- /dev/null +++ b/tests/TestData/SmokeTests.WinformsNet5Baseline/Form1.Designer.cs @@ -0,0 +1,41 @@ + +namespace SmokeTests.WinformsNet5Baseline +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Text = "Form1"; + } + + #endregion + } +} + diff --git a/tests/TestData/SmokeTests.WinformsNet5Baseline/Form1.cs b/tests/TestData/SmokeTests.WinformsNet5Baseline/Form1.cs new file mode 100644 index 000000000..a18c68dba --- /dev/null +++ b/tests/TestData/SmokeTests.WinformsNet5Baseline/Form1.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace SmokeTests.WinformsNet5Baseline +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + + } +} diff --git a/tests/TestData/SmokeTests.WinformsNet5Baseline/Program.cs b/tests/TestData/SmokeTests.WinformsNet5Baseline/Program.cs new file mode 100644 index 000000000..884a80d93 --- /dev/null +++ b/tests/TestData/SmokeTests.WinformsNet5Baseline/Program.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace SmokeTests.WinformsNet5Baseline +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/tests/TestData/SmokeTests.WinformsNet5Baseline/SmokeTests.WinformsNet5Baseline.csproj b/tests/TestData/SmokeTests.WinformsNet5Baseline/SmokeTests.WinformsNet5Baseline.csproj new file mode 100644 index 000000000..5aea6d572 --- /dev/null +++ b/tests/TestData/SmokeTests.WinformsNet5Baseline/SmokeTests.WinformsNet5Baseline.csproj @@ -0,0 +1,14 @@ + + + + net5.0-windows + WinExe + false + true + + + + + + + \ No newline at end of file diff --git a/tests/TestData/SmokeTests.WpfCoreBaseline/SmokeTests.WpfCoreBaseline.csproj b/tests/TestData/SmokeTests.WpfCoreBaseline/SmokeTests.WpfCoreBaseline.csproj index 82da8037c..1d23e15e5 100644 --- a/tests/TestData/SmokeTests.WpfCoreBaseline/SmokeTests.WpfCoreBaseline.csproj +++ b/tests/TestData/SmokeTests.WpfCoreBaseline/SmokeTests.WpfCoreBaseline.csproj @@ -1,14 +1,16 @@ - - + + netcoreapp3.1 WinExe false true + 4.5.0 + diff --git a/tests/TestData/SmokeTests.WpfNet5Baseline/App.xaml b/tests/TestData/SmokeTests.WpfNet5Baseline/App.xaml new file mode 100644 index 000000000..59f5e60ff --- /dev/null +++ b/tests/TestData/SmokeTests.WpfNet5Baseline/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/tests/TestData/SmokeTests.WpfNet5Baseline/App.xaml.cs b/tests/TestData/SmokeTests.WpfNet5Baseline/App.xaml.cs new file mode 100644 index 000000000..bbf3f84de --- /dev/null +++ b/tests/TestData/SmokeTests.WpfNet5Baseline/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SmokeTests.WpfNet5Baseline +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/tests/TestData/SmokeTests.WpfNet5Baseline/AssemblyInfo.cs b/tests/TestData/SmokeTests.WpfNet5Baseline/AssemblyInfo.cs new file mode 100644 index 000000000..8b5504ecf --- /dev/null +++ b/tests/TestData/SmokeTests.WpfNet5Baseline/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/tests/TestData/SmokeTests.WpfNet5Baseline/MainWindow.xaml b/tests/TestData/SmokeTests.WpfNet5Baseline/MainWindow.xaml new file mode 100644 index 000000000..130667dfb --- /dev/null +++ b/tests/TestData/SmokeTests.WpfNet5Baseline/MainWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/tests/TestData/SmokeTests.WpfNet5Baseline/MainWindow.xaml.cs b/tests/TestData/SmokeTests.WpfNet5Baseline/MainWindow.xaml.cs new file mode 100644 index 000000000..13b20389e --- /dev/null +++ b/tests/TestData/SmokeTests.WpfNet5Baseline/MainWindow.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace SmokeTests.WpfNet5Baseline +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + } +} diff --git a/tests/TestData/SmokeTests.WpfNet5Baseline/SmokeTests.WpfNet5Baseline.csproj b/tests/TestData/SmokeTests.WpfNet5Baseline/SmokeTests.WpfNet5Baseline.csproj new file mode 100644 index 000000000..43bcb9158 --- /dev/null +++ b/tests/TestData/SmokeTests.WpfNet5Baseline/SmokeTests.WpfNet5Baseline.csproj @@ -0,0 +1,16 @@ + + + + net5.0-windows + WinExe + false + true + + + + + 4.5.0 + + + + diff --git a/tests/end-to-end/Smoke.Tests/BasicConversions.cs b/tests/end-to-end/Smoke.Tests/BasicConversions.cs index 63a52faf3..4319d94a6 100644 --- a/tests/end-to-end/Smoke.Tests/BasicConversions.cs +++ b/tests/end-to-end/Smoke.Tests/BasicConversions.cs @@ -27,47 +27,71 @@ public BasicSmokeTests(SolutionPathFixture solutionPathFixture, MSBuildFixture m } [Fact(Skip = "Legacy F# support is not installed on any build machines")] - public void ConvertsLegacyFSharpConsole() + public void ConvertsLegacyFSharpConsoleToNetCoreApp31() { var projectToConvertPath = GetFSharpProjectPath("SmokeTests.LegacyFSharpConsole"); var projectBaselinePath = GetFSharpProjectPath("SmokeTests.FSharpConsoleBaseline"); - AssertConversionWorks(projectToConvertPath, projectBaselinePath); + AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1"); + } + + [Fact(Skip = "Legacy F# support is not installed on any build machines")] + public void ConvertsLegacyFSharpConsoleToNet50() + { + var projectToConvertPath = GetFSharpProjectPath("SmokeTests.LegacyFSharpConsole"); + var projectBaselinePath = GetFSharpProjectPath("SmokeTests.FSharpConsoleBaseline"); + AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1"); } [Fact] - public void ConvertsWpfFrameworkTemplate() + public void ConvertsWpfFrameworkTemplateForNetCoreApp31() { var projectToConvertPath = GetCSharpProjectPath("SmokeTests.WpfFramework"); var projectBaselinePath = GetCSharpProjectPath("SmokeTests.WpfCoreBaseline"); - AssertConversionWorks(projectToConvertPath, projectBaselinePath); + AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1"); } [Fact] - public void ConvertsWinformsFrameworkTemplate() + public void ConvertsWpfFrameworkTemplateForNet50() + { + var projectToConvertPath = GetCSharpProjectPath("SmokeTests.WpfFramework"); + var projectBaselinePath = GetCSharpProjectPath("SmokeTests.WpfNet5Baseline"); + AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0-windows"); + } + + [Fact] + public void ConvertsWinformsFrameworkTemplateForNetCoreApp31() { var projectToConvertPath = GetCSharpProjectPath("SmokeTests.WinformsFramework"); var projectBaselinePath = GetCSharpProjectPath("SmokeTests.WinformsCoreBaseline"); - AssertConversionWorks(projectToConvertPath, projectBaselinePath); + AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1"); + } + + [Fact] + public void ConvertsWinformsFrameworkTemplateForNet50() + { + var projectToConvertPath = GetCSharpProjectPath("SmokeTests.WinformsFramework"); + var projectBaselinePath = GetCSharpProjectPath("SmokeTests.WinformsNet5Baseline"); + AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0-windows"); } - private void AssertConversionWorks(string projectToConvertPath, string projectBaselinePath) + private void AssertConversionWorks(string projectToConvertPath, string projectBaselinePath, string targetTFM) { - var (baselineRootElement, convertedRootElement) = GetRootElementsForComparison(projectToConvertPath, projectBaselinePath); + var (baselineRootElement, convertedRootElement) = GetRootElementsForComparison(projectToConvertPath, projectBaselinePath, targetTFM); AssertPropsEqual(baselineRootElement, convertedRootElement); AssertItemsEqual(baselineRootElement, convertedRootElement); } - private static (IProjectRootElement baselineRootElement, IProjectRootElement convertedRootElement) GetRootElementsForComparison(string projectToConvertPath, string projectBaselinePath) + private static (IProjectRootElement baselineRootElement, IProjectRootElement convertedRootElement) GetRootElementsForComparison(string projectToConvertPath, string projectBaselinePath, string targetTFM) { var conversionLoader = new MSBuildConversionWorkspaceLoader(projectToConvertPath, MSBuildConversionWorkspaceType.Project); - var conversionWorkspace = conversionLoader.LoadWorkspace(projectToConvertPath, noBackup: true); + var conversionWorkspace = conversionLoader.LoadWorkspace(projectToConvertPath, noBackup: true, targetTFM, false); var baselineLoader = new MSBuildConversionWorkspaceLoader(projectBaselinePath, MSBuildConversionWorkspaceType.Project); var baselineRootElement = baselineLoader.GetRootElementFromProjectFile(projectBaselinePath); var item = conversionWorkspace.WorkspaceItems.Single(); var converter = new Converter(item.UnconfiguredProject, item.SdkBaselineProject, item.ProjectRootElement); - var convertedRootElement = converter.ConvertProjectFile("netcoreapp3.1", keepCurrentTfm: false, usePreviewSDK: false); + var convertedRootElement = converter.ConvertProjectFile(); return (baselineRootElement, convertedRootElement); } @@ -83,7 +107,7 @@ private void AssertPropsEqual(IProjectRootElement baselineRootElement, IProjectR if (baselinePropGroups.Count > 0) { for (var i = 0; i < baselinePropGroups.Count; i++) - { + { var baselineProps = new List(baselinePropGroups[i].Properties); var convertedProps = new List(convertedPropGroups[i].Properties); diff --git a/try-convert.sln b/try-convert.sln index 78e2e3fab..a221e553e 100644 --- a/try-convert.sln +++ b/try-convert.sln @@ -1,29 +1,29 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30605.207 MinimumVisualStudioVersion = 15.0.26124.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{FEF77564-1629-42D5-9183-18EF3C31AFE5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "try-convert", "src\try-convert\try-convert.csproj", "{861A048E-B8C9-4079-A1D2-4851DA080648}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "try-convert", "src\try-convert\try-convert.csproj", "{861A048E-B8C9-4079-A1D2-4851DA080648}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSBuild.Conversion.Project", "src\MSBuild.Conversion.Project\MSBuild.Conversion.Project.csproj", "{E52FB3B5-193A-4B97-BC12-3E5A71F66405}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuild.Conversion.Project", "src\MSBuild.Conversion.Project\MSBuild.Conversion.Project.csproj", "{E52FB3B5-193A-4B97-BC12-3E5A71F66405}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSBuild.Conversion.Facts", "src\MSBuild.Conversion.Facts\MSBuild.Conversion.Facts.csproj", "{43A09B9A-E593-4CD0-8054-C6B26C858FC1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuild.Conversion.Facts", "src\MSBuild.Conversion.Facts\MSBuild.Conversion.Facts.csproj", "{43A09B9A-E593-4CD0-8054-C6B26C858FC1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSBuild.Abstractions", "src\MSBuild.Abstractions\MSBuild.Abstractions.csproj", "{BBFD697D-0D71-4C11-87BD-0628439EA160}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuild.Abstractions", "src\MSBuild.Abstractions\MSBuild.Abstractions.csproj", "{BBFD697D-0D71-4C11-87BD-0628439EA160}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSBuild.Conversion.Package", "src\MSBuild.Conversion.Package\MSBuild.Conversion.Package.csproj", "{5580495A-5A6D-444F-9985-16098C78793E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuild.Conversion.Package", "src\MSBuild.Conversion.Package\MSBuild.Conversion.Package.csproj", "{5580495A-5A6D-444F-9985-16098C78793E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{8F861E7D-283E-46F9-9A6A-DBF1BE8BC978}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectConversion.Tests", "tests\unit\ProjectConversion.Tests\ProjectConversion.Tests.csproj", "{30EE0DE2-7BED-4868-AE20-4BD27553380B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectConversion.Tests", "tests\unit\ProjectConversion.Tests\ProjectConversion.Tests.csproj", "{30EE0DE2-7BED-4868-AE20-4BD27553380B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PackageConversion.Tests", "tests\unit\PackageConversion.Tests\PackageConversion.Tests.csproj", "{A3DDB4B7-F48E-40FA-A638-B03EECB48255}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageConversion.Tests", "tests\unit\PackageConversion.Tests\PackageConversion.Tests.csproj", "{A3DDB4B7-F48E-40FA-A638-B03EECB48255}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Smoke.Tests", "tests\end-to-end\Smoke.Tests\Smoke.Tests.csproj", "{26176B40-732E-425C-A5F8-70B738C4778A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Smoke.Tests", "tests\end-to-end\Smoke.Tests\Smoke.Tests.csproj", "{26176B40-732E-425C-A5F8-70B738C4778A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSBuild.Conversion.SDK", "src\MSBuild.Conversion.SDK\MSBuild.Conversion.SDK.csproj", "{B56755BA-7992-4D2C-98E4-86F1C75A19B2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuild.Conversion.SDK", "src\MSBuild.Conversion.SDK\MSBuild.Conversion.SDK.csproj", "{B56755BA-7992-4D2C-98E4-86F1C75A19B2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -34,9 +34,6 @@ Global Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {861A048E-B8C9-4079-A1D2-4851DA080648}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {861A048E-B8C9-4079-A1D2-4851DA080648}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -147,6 +144,9 @@ Global {B56755BA-7992-4D2C-98E4-86F1C75A19B2}.Release|x86.ActiveCfg = Release|Any CPU {B56755BA-7992-4D2C-98E4-86F1C75A19B2}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection GlobalSection(NestedProjects) = preSolution {861A048E-B8C9-4079-A1D2-4851DA080648} = {FEF77564-1629-42D5-9183-18EF3C31AFE5} {E52FB3B5-193A-4B97-BC12-3E5A71F66405} = {FEF77564-1629-42D5-9183-18EF3C31AFE5} @@ -158,4 +158,7 @@ Global {26176B40-732E-425C-A5F8-70B738C4778A} = {8F861E7D-283E-46F9-9A6A-DBF1BE8BC978} {B56755BA-7992-4D2C-98E4-86F1C75A19B2} = {FEF77564-1629-42D5-9183-18EF3C31AFE5} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {68B47EDA-66C8-46F5-A57F-1129A8EF7F4F} + EndGlobalSection EndGlobal