diff --git a/TestAssets/TestProjects/TestAppWithContents/project.json b/TestAssets/TestProjects/TestAppWithContents/project.json index 9bc98a36a..5620a3bc3 100644 --- a/TestAssets/TestProjects/TestAppWithContents/project.json +++ b/TestAssets/TestProjects/TestAppWithContents/project.json @@ -9,7 +9,7 @@ "include": "testcontentfile2.txt" }, "out/": { - "include": ["project.json", "Program.cs"], + "include": ["Program.cs"], "exclude": ["Program.cs"], "includeFiles": ["Program.cs"], "excludeFiles": ["Program.cs"] diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs b/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs index 0c1df605f..2fe047470 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/DefaultMigrationRuleSet.cs @@ -16,6 +16,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration new MigrateRuntimeOptionsRule(), new MigratePublishOptionsRule(), new MigrateProjectDependenciesRule(), + new MigratePackageDependenciesRule(), new MigrateConfigurationsRule(), new MigrateScriptsRule(), new TemporaryMutateProjectJsonRule(), diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationNuGetFrameworkExtensions.cs b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationNuGetFrameworkExtensions.cs new file mode 100644 index 000000000..76d063f38 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationNuGetFrameworkExtensions.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using NuGet.Frameworks; + +namespace Microsoft.DotNet.ProjectJsonMigration +{ + public static class MigrationNuGetFrameworkExtensions + { + public static string GetMSBuildCondition(this NuGetFramework framework) + { + return $" '$(TargetFramework)' == '{framework.GetTwoDigitShortFolderName()}' "; + } + } +} diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationRuleInputs.cs b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationRuleInputs.cs index 330032649..a0a1deebc 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationRuleInputs.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationRuleInputs.cs @@ -18,7 +18,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration public ProjectPropertyGroupElement CommonPropertyGroup { get; } - public IEnumerable ProjectContexts { get; } + public List ProjectContexts { get; } public ProjectContext DefaultProjectContext { @@ -36,7 +36,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration ProjectRootElement projectXproj=null) { ProjectXproj = projectXproj; - ProjectContexts = projectContexts; + ProjectContexts = projectContexts.ToList(); OutputMSBuildProject = outputMSBuildProject; CommonItemGroup = commonItemGroup; CommonPropertyGroup = commonPropertyGroup; diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependency.cs b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependency.cs index 017d123c6..03c780d43 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependency.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependency.cs @@ -11,7 +11,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration public ProjectDependency(string name, string projectFilePath) { Name = name; - ProjectFilePath = projectFilePath; + ProjectFilePath = System.IO.Path.GetFullPath(projectFilePath); } } } diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs index 4be944cae..5a907b902 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs @@ -5,15 +5,17 @@ using System; using System.Collections.Generic; using Microsoft.Build.Construction; using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.ProjectModel.Graph; using System.Linq; using System.IO; using Newtonsoft.Json.Linq; using Microsoft.DotNet.Tools.Common; +using NuGet.Frameworks; using NuGet.LibraryModel; namespace Microsoft.DotNet.ProjectJsonMigration { - public class ProjectDependencyFinder + internal class ProjectDependencyFinder { public IEnumerable ResolveProjectDependencies(string projectDir, string xprojFile = null) { @@ -41,13 +43,57 @@ namespace Microsoft.DotNet.ProjectJsonMigration } } } - - public IEnumerable ResolveProjectDependencies( - ProjectContext projectContext, + public IEnumerable ResolveProjectDependenciesForFramework( + Project project, + NuGetFramework framework, IEnumerable preResolvedProjects=null) { preResolvedProjects = preResolvedProjects ?? new HashSet(); + var possibleProjectDependencies = + FindPossibleProjectDependencies(project.ProjectFilePath); + + var projectDependencies = new List(); + + IEnumerable projectFileDependenciesForFramework; + if (framework == null) + { + projectFileDependenciesForFramework = project.Dependencies; + } + else + { + projectFileDependenciesForFramework = project.GetTargetFramework(framework).Dependencies; + } + + foreach (var projectFileDependency in projectFileDependenciesForFramework) + { + var dependencyName = projectFileDependency.Name; + + ProjectDependency projectDependency; + if (!possibleProjectDependencies.TryGetValue(dependencyName, out projectDependency)) + { + if (projectFileDependency.LibraryRange.TypeConstraint == LibraryDependencyTarget.Project + && !preResolvedProjects.Contains(dependencyName)) + { + MigrationErrorCodes + .MIGRATE1014($"Unresolved project dependency ({dependencyName})").Throw(); + } + else + { + continue; + } + } + + projectDependencies.Add(projectDependency); + } + + return projectDependencies; + } + + public IEnumerable ResolveProjectDependencies(ProjectContext projectContext, IEnumerable preResolvedProjects=null) + { + preResolvedProjects = preResolvedProjects ?? new HashSet(); + var projectExports = projectContext.CreateExporter("_").GetDependencies(); var possibleProjectDependencies = FindPossibleProjectDependencies(projectContext.ProjectFile.ProjectFilePath); diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs index 8f1385f67..b9eae2adc 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs @@ -16,13 +16,6 @@ namespace Microsoft.DotNet.ProjectJsonMigration { public class ProjectMigrator { - // TODO: Migrate PackOptions - // TODO: Migrate Multi-TFM projects - // TODO: Tests - // TODO: Out of Scope - // - Globs that resolve to directories: /some/path/**/somedir - // - Migrating Deprecated project.jsons - private readonly IMigrationRule _ruleSet; private readonly ProjectDependencyFinder _projectDependencyFinder = new ProjectDependencyFinder(); @@ -39,16 +32,34 @@ namespace Microsoft.DotNet.ProjectJsonMigration { throw new ArgumentNullException(); } + Exception exc = null; + IEnumerable projectDependencies = null; + + try + { + projectDependencies = ResolveTransitiveClosureProjectDependencies( + rootSettings.ProjectDirectory, + rootSettings.ProjectXProjFilePath); + } + catch (Exception e) + { + exc = e; + } + + // Verify up front so we can prefer these errors over an unresolved project dependency + VerifyInputs(ComputeMigrationRuleInputs(rootSettings), rootSettings); + if (exc != null) + { + throw exc; + } MigrateProject(rootSettings); - + if (skipProjectReferences) { return; } - var projectDependencies = ResolveTransitiveClosureProjectDependencies(rootSettings.ProjectDirectory, rootSettings.ProjectXProjFilePath); - foreach(var project in projectDependencies) { var projectDir = Path.GetDirectoryName(project.ProjectFilePath); @@ -60,6 +71,22 @@ namespace Microsoft.DotNet.ProjectJsonMigration } } + private void DeleteProjectJsons(MigrationSettings rootsettings, IEnumerable projectDependencies) + { + try + { + File.Delete(Path.Combine(rootsettings.ProjectDirectory, "project.json")); + } catch {} + + foreach (var projectDependency in projectDependencies) + { + try + { + File.Delete(projectDependency.ProjectFilePath); + } catch { } + } + } + private IEnumerable ResolveTransitiveClosureProjectDependencies(string rootProject, string xprojFile) { HashSet projectsMap = new HashSet(new ProjectDependencyComparer()); diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigratePackageDependenciesRule.cs b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigratePackageDependenciesRule.cs new file mode 100644 index 000000000..a619a40ea --- /dev/null +++ b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigratePackageDependenciesRule.cs @@ -0,0 +1,227 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Build.Construction; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ProjectJsonMigration.Transforms; +using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.ProjectModel.Graph; +using Microsoft.DotNet.Tools.Common; +using NuGet.Frameworks; +using NuGet.LibraryModel; + +namespace Microsoft.DotNet.ProjectJsonMigration.Rules +{ + public class MigratePackageDependenciesRule : IMigrationRule + { + private readonly ITransformApplicator _transformApplicator; + private readonly ProjectDependencyFinder _projectDependencyFinder; + private string _projectDirectory; + + public MigratePackageDependenciesRule(ITransformApplicator transformApplicator = null) + { + _transformApplicator = transformApplicator ?? new TransformApplicator(); + _projectDependencyFinder = new ProjectDependencyFinder(); + } + + public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs) + { + CleanExistingPackageReferences(migrationRuleInputs.OutputMSBuildProject); + + _projectDirectory = migrationSettings.ProjectDirectory; + var project = migrationRuleInputs.DefaultProjectContext.ProjectFile; + + var tfmDependencyMap = new Dictionary>(); + var targetFrameworks = project.GetTargetFrameworks(); + + // Inject Sdk dependency + _transformApplicator.Execute( + PackageDependencyInfoTransform.Transform( + new PackageDependencyInfo + { + Name = ConstantPackageNames.CSdkPackageName, + Version = migrationSettings.SdkPackageVersion + }), migrationRuleInputs.CommonItemGroup); + + // Migrate Direct Deps first + MigrateDependencies( + project, + migrationRuleInputs.OutputMSBuildProject, + null, + project.Dependencies, + migrationRuleInputs.ProjectXproj); + + MigrationTrace.Instance.WriteLine($"Migrating {targetFrameworks.Count()} target frameworks"); + foreach (var targetFramework in targetFrameworks) + { + MigrationTrace.Instance.WriteLine($"Migrating framework {targetFramework.FrameworkName.GetShortFolderName()}"); + + MigrateImports(migrationRuleInputs.CommonItemGroup, targetFramework); + + MigrateDependencies( + project, + migrationRuleInputs.OutputMSBuildProject, + targetFramework.FrameworkName, + targetFramework.Dependencies, + migrationRuleInputs.ProjectXproj); + } + } + + private void MigrateImports(ProjectItemGroupElement commonItemGroup, TargetFrameworkInformation targetFramework) + { + var transform = ImportsTransformation.Transform(targetFramework); + if (transform != null) + { + transform.Condition = targetFramework.FrameworkName.GetMSBuildCondition(); + _transformApplicator.Execute(transform, commonItemGroup); + } + } + + private void CleanExistingPackageReferences(ProjectRootElement outputMSBuildProject) + { + var packageRefs = outputMSBuildProject.Items.Where(i => i.ItemType == "PackageReference").ToList(); + + foreach (var packageRef in packageRefs) + { + var parent = packageRef.Parent; + packageRef.Parent.RemoveChild(packageRef); + parent.RemoveIfEmpty(); + } + } + + private void MigrateDependencies( + Project project, + ProjectRootElement output, + NuGetFramework framework, + IEnumerable dependencies, + ProjectRootElement xproj) + { + var projectDependencies = new HashSet(GetAllProjectReferenceNames(project, framework, xproj)); + var packageDependencies = dependencies.Where(d => !projectDependencies.Contains(d.Name)); + + string condition = framework?.GetMSBuildCondition() ?? ""; + var itemGroup = output.ItemGroups.FirstOrDefault(i => i.Condition == condition) + ?? output.AddItemGroup(); + itemGroup.Condition = condition; + + foreach (var packageDependency in packageDependencies) + { + MigrationTrace.Instance.WriteLine(packageDependency.Name); + AddItemTransform transform; + + if (packageDependency.LibraryRange.TypeConstraint == LibraryDependencyTarget.Reference) + { + transform = FrameworkDependencyTransform; + } + else + { + transform = PackageDependencyTransform(); + if (packageDependency.Type == LibraryDependencyType.Build) + { + Console.WriteLine("Build type!!!"); + transform = transform.WithMetadata("PrivateAssets", "all"); + } + else if (packageDependency.SuppressParent != LibraryIncludeFlagUtils.DefaultSuppressParent) + { + var metadataValue = ReadLibraryIncludeFlags(packageDependency.SuppressParent); + transform = transform.WithMetadata("PrivateAssets", metadataValue); + } + + if (packageDependency.IncludeType != LibraryIncludeFlags.All) + { + var metadataValue = ReadLibraryIncludeFlags(packageDependency.IncludeType); + transform = transform.WithMetadata("IncludeAssets", metadataValue); + } + } + + _transformApplicator.Execute(transform.Transform(packageDependency), itemGroup); + } + } + + private string ReadLibraryIncludeFlags(LibraryIncludeFlags includeFlags) + { + if ((includeFlags & LibraryIncludeFlags.All) == LibraryIncludeFlags.All) + { + return "All"; + } + + var flagString = ""; + var allFlagsAndNames = new List> + { + Tuple.Create("Analyzers", LibraryIncludeFlags.Analyzers), + Tuple.Create("Build", LibraryIncludeFlags.Build), + Tuple.Create("Compile", LibraryIncludeFlags.Compile), + Tuple.Create("ContentFiles", LibraryIncludeFlags.ContentFiles), + Tuple.Create("Native", LibraryIncludeFlags.Native), + Tuple.Create("Runtime", LibraryIncludeFlags.Runtime) + }; + + foreach (var flagAndName in allFlagsAndNames) + { + var name = flagAndName.Item1; + var flag = flagAndName.Item2; + + if ((includeFlags & flag) == flag) + { + if (!string.IsNullOrEmpty(flagString)) + { + flagString += ";"; + } + flagString += name; + } + } + + return flagString; + } + + private IEnumerable GetAllProjectReferenceNames(Project project, NuGetFramework framework, ProjectRootElement xproj) + { + var csprojReferenceItems = _projectDependencyFinder.ResolveXProjProjectDependencies(xproj); + var migratedXProjDependencyPaths = csprojReferenceItems.SelectMany(p => p.Includes()); + var migratedXProjDependencyNames = new HashSet(migratedXProjDependencyPaths.Select(p => Path.GetFileNameWithoutExtension( + PathUtility.GetPathWithDirectorySeparator(p)))); + var projectDependencies = _projectDependencyFinder.ResolveProjectDependenciesForFramework( + project, + framework, + preResolvedProjects: migratedXProjDependencyNames); + + return projectDependencies.Select(p => p.Name).Concat(migratedXProjDependencyNames); + } + + private AddItemTransform FrameworkDependencyTransform => new AddItemTransform( + "Reference", + dep => dep.Name, + dep => "", + dep => true); + + private Func> PackageDependencyTransform => () => new AddItemTransform( + "PackageReference", + dep => dep.Name, + dep => "", + dep => true) + .WithMetadata("Version", r => r.LibraryRange.VersionRange.OriginalString); + + private AddItemTransform PackageDependencyInfoTransform => new AddItemTransform( + "PackageReference", + dep => dep.Name, + dep => "", + dep => true) + .WithMetadata("Version", r => r.Version); + + private AddItemTransform ImportsTransformation => new AddItemTransform( + "PackageTargetFallback", + t => $"$(PackageTargetFallback);{string.Join(";", t.Imports)}", + t => "", + t => t.Imports.OrEmptyIfNull().Any()); + + private class PackageDependencyInfo + { + public string Name {get; set;} + public string Version {get; set;} + } + } +} diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/Rules/TemporaryMutateProjectJsonRule.cs b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/TemporaryMutateProjectJsonRule.cs index 3de53b547..c6f6387ad 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/Rules/TemporaryMutateProjectJsonRule.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/TemporaryMutateProjectJsonRule.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Linq; using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; namespace Microsoft.DotNet.ProjectJsonMigration.Rules { @@ -21,73 +22,11 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules { public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs) { - bool shouldRenameOldProject = PathsAreEqual(migrationSettings.OutputDirectory, migrationSettings.ProjectDirectory); - - if (!shouldRenameOldProject && File.Exists(Path.Combine(migrationSettings.OutputDirectory, "project.json"))) - { - // TODO: should there be a setting to overwrite anything in output directory? - throw new Exception("Existing project.json found in output directory."); - } - var sourceProjectFile = Path.Combine(migrationSettings.ProjectDirectory, "project.json"); - var destinationProjectFile = Path.Combine(migrationSettings.OutputDirectory, "project.json"); - if (shouldRenameOldProject) - { - var renamedProjectFile = Path.Combine(migrationSettings.ProjectDirectory, "project.migrated.json"); - File.Move(sourceProjectFile, renamedProjectFile); - sourceProjectFile = renamedProjectFile; - } - var json = CreateDestinationProjectFile(sourceProjectFile, destinationProjectFile); - InjectSdkReference(json, ConstantPackageNames.CSdkPackageName, migrationSettings.SdkPackageVersion); - RemoveRuntimesNode(json); - - File.WriteAllText(destinationProjectFile, json.ToString()); - } - - private JObject CreateDestinationProjectFile(string sourceProjectFile, string destinationProjectFile) - { - File.Copy(sourceProjectFile, destinationProjectFile); - return JObject.Parse(File.ReadAllText(destinationProjectFile)); - } - - private void InjectSdkReference(JObject json, string sdkPackageName, string sdkPackageVersion) - { - JToken dependenciesNode; - if (json.TryGetValue("dependencies", out dependenciesNode)) - { - var dependenciesNodeObject = dependenciesNode.Value(); - dependenciesNodeObject.Add(sdkPackageName, sdkPackageVersion); - } - else - { - var dependenciesNodeObject = new JObject(); - dependenciesNodeObject.Add(sdkPackageName, sdkPackageVersion); - - json.Add("dependencies", dependenciesNodeObject); - } - } - - private void RemoveRuntimesNode(JObject json) - { - json.Remove("runtimes"); - } - - private bool PathsAreEqual(params string[] paths) - { - var normalizedPaths = paths.Select(path => Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar)).ToList(); - - for (int i=1; i("target"); target = LibraryDependencyTargetUtils.Parse(targetStr); } + + IEnumerable strings; + if (TryGetStringEnumerable(dependencyValue["include"], out strings)) + { + dependencyIncludeFlagsValue = LibraryIncludeFlagUtils.GetFlags(strings); + } + + if (TryGetStringEnumerable(dependencyValue["exclude"], out strings)) + { + dependencyExcludeFlagsValue = LibraryIncludeFlagUtils.GetFlags(strings); + } + + if (TryGetStringEnumerable(dependencyValue["suppressParent"], out strings)) + { + // This overrides any settings that came from the type property. + suppressParentFlagsValue = LibraryIncludeFlagUtils.GetFlags(strings); + } } else if (dependencyValue.Type == JTokenType.String) { @@ -327,6 +349,9 @@ namespace Microsoft.DotNet.ProjectModel } } + // the dependency flags are: Include flags - Exclude flags + var includeFlags = dependencyIncludeFlagsValue & ~dependencyExcludeFlagsValue; + var lineInfo = (IJsonLineInfo)dependencyValue; results.Add(new ProjectLibraryDependency { @@ -335,6 +360,8 @@ namespace Microsoft.DotNet.ProjectModel dependencyVersionRange, target), Type = dependencyTypeValue, + IncludeType = includeFlags, + SuppressParent = suppressParentFlagsValue, SourceFilePath = projectPath, SourceLine = lineInfo.LineNumber, SourceColumn = lineInfo.LinePosition @@ -472,7 +499,8 @@ namespace Microsoft.DotNet.ProjectModel Dependencies = new List(), CompilerOptions = compilerOptions, Line = lineInfo.LineNumber, - Column = lineInfo.LinePosition + Column = lineInfo.LinePosition, + Imports = GetImports(frameworkValue) }; var frameworkDependencies = new List(); @@ -508,6 +536,26 @@ namespace Microsoft.DotNet.ProjectModel return true; } + private IEnumerable GetImports(JObject frameworkValue) + { + var prop = frameworkValue.Property("imports"); + if (prop == null) + { + return Enumerable.Empty(); + } + + if (prop.Type == JTokenType.Array) + { + return prop.Value>(); + } + else if (prop.Type == JTokenType.String) + { + return new [] { prop.Value() }; + } + + return null; + } + private static CommonCompilerOptions GetCompilationOptions(JObject rawObject, Project project) { var compilerName = rawObject.Value("compilerName"); @@ -819,5 +867,29 @@ namespace Microsoft.DotNet.ProjectModel lineInfo.LineNumber, lineInfo.LinePosition)); } + + private static bool TryGetStringEnumerable(JToken token, out IEnumerable result) + { + IEnumerable values; + if (token == null) + { + result = null; + return false; + } + else if (token.Type == JTokenType.String) + { + values = new[] + { + token.Value() + }; + } + else + { + values = token.Value(); + } + result = values + .SelectMany(value => value.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries)); + return true; + } } } diff --git a/src/Microsoft.DotNet.ProjectModel/TargetFrameworkInformation.cs b/src/Microsoft.DotNet.ProjectModel/TargetFrameworkInformation.cs index 811135c94..5dd9d9b31 100644 --- a/src/Microsoft.DotNet.ProjectModel/TargetFrameworkInformation.cs +++ b/src/Microsoft.DotNet.ProjectModel/TargetFrameworkInformation.cs @@ -22,5 +22,7 @@ namespace Microsoft.DotNet.ProjectModel public string WrappedProject { get; set; } public string AssemblyPath { get; set; } + + public IEnumerable Imports { get; set; } } } diff --git a/src/dotnet/commands/dotnet-migrate/ProjectRootElementExtensions.cs b/src/dotnet/commands/dotnet-migrate/ProjectRootElementExtensions.cs index e1fc07ac5..262670ad0 100644 --- a/src/dotnet/commands/dotnet-migrate/ProjectRootElementExtensions.cs +++ b/src/dotnet/commands/dotnet-migrate/ProjectRootElementExtensions.cs @@ -8,14 +8,11 @@ namespace Microsoft.DotNet.Tools.Migrate { public static string GetSdkVersion(this ProjectRootElement projectRootElement) { - //TODO: Temporarily pinning the SDK version for Migration. Once we have packageref migration we can remove this. - return "1.0.0-alpha-20160929-1"; - - // return projectRootElement - // .Items - // .Where(i => i.ItemType == "PackageReference") - // .First(i => i.Include == ConstantPackageNames.CSdkPackageName) - // .GetMetadataWithName("version").Value; + return projectRootElement + .Items + .Where(i => i.ItemType == "PackageReference") + .First(i => i.Include == ConstantPackageNames.CSdkPackageName) + .GetMetadataWithName("version").Value; } } } \ No newline at end of file diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackageDependencies.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackageDependencies.cs new file mode 100644 index 000000000..69e80302a --- /dev/null +++ b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigratePackageDependencies.cs @@ -0,0 +1,59 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Build.Construction; +using Microsoft.DotNet.Tools.Test.Utilities; +using System.Linq; +using Xunit; +using FluentAssertions; +using Microsoft.DotNet.ProjectJsonMigration.Rules; +using System; + +namespace Microsoft.DotNet.ProjectJsonMigration.Tests +{ + public class GivenThatIWantToMigratePackageDependencies : TestBase + { + [Fact] + public void It_migrates_basic_PackageReference() + { + var mockProj = RunPackageDependenciesRuleOnPj(@" + { + ""dependencies"": { + ""APackage"" : ""1.0.0-preview"", + ""BPackage"" : ""1.0.0"" + } + }"); + + Console.WriteLine(mockProj.RawXml); + + EmitsPackageReferences(mockProj, Tuple.Create("APackage", "1.0.0-preview", ""), Tuple.Create("BPackage", "1.0.0", "")); + } + + private void EmitsPackageReferences(ProjectRootElement mockProj, params Tuple[] packageSpecs) + { + foreach (var packageSpec in packageSpecs) + { + var packageName = packageSpec.Item1; + var packageVersion = packageSpec.Item2; + var packageTFM = packageSpec.Item3; + + var items = mockProj.Items + .Where(i => i.ItemType == "PackageReference") + .Where(i => string.IsNullOrEmpty(packageTFM) || i.ConditionChain().Any(c => c.Contains(packageTFM))) + .Where(i => i.Include == packageName) + .Where(i => i.GetMetadataWithName("Version").Value == packageVersion); + + items.Should().HaveCount(1); + } + } + + private ProjectRootElement RunPackageDependenciesRuleOnPj(string s, string testDirectory = null) + { + testDirectory = testDirectory ?? Temp.CreateDirectory().Path; + return TemporaryProjectFileRuleRunner.RunRules(new IMigrationRule[] + { + new MigratePackageDependenciesRule() + }, s, testDirectory); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Transforms/GivenAnIncludeContextTransformation.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Transforms/GivenAnIncludeContextTransformation.cs deleted file mode 100644 index 5c69c5f78..000000000 --- a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Transforms/GivenAnIncludeContextTransformation.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.DotNet.ProjectJsonMigration.Transforms; - -namespace Microsoft.DotNet.ProjectJsonMigration.Tests -{ - public class GivenAnIncludeContextTransformation - { - } -} diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs index 89dc2d5d0..655919ac5 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs @@ -47,7 +47,13 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void It_migrates_dotnet_new_console_with_identical_outputs() { - var projectDirectory = Temp.CreateDirectory().Path; + var projectDirectory = Path.Combine(AppContext.BaseDirectory, "newconsoletest"); + if (Directory.Exists(projectDirectory)) + { + Directory.Delete(projectDirectory, true); + } + Directory.CreateDirectory(projectDirectory); + var outputComparisonData = GetDotnetNewComparisonData(projectDirectory, "console"); var outputsIdentical = @@ -60,7 +66,7 @@ namespace Microsoft.DotNet.Migration.Tests VerifyAllMSBuildOutputsRunnable(projectDirectory); } - [Fact] + [Fact(Skip="https://github.com/dotnet/cli/issues/4299")] public void It_migrates_dotnet_new_web_with_outputs_containing_project_json_outputs() { var projectDirectory = Temp.CreateDirectory().Path; @@ -214,7 +220,7 @@ namespace Microsoft.DotNet.Migration.Tests Restore(projectDirectory); var outputComparisonData = - BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectDirectory)); + BuildProjectJsonMigrateBuildMSBuild(projectDirectory); return outputComparisonData; } @@ -231,7 +237,7 @@ namespace Microsoft.DotNet.Migration.Tests } } - private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, string projectName) + private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, string projectName=null) { BuildProjectJson(projectDirectory); var projectJsonBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory)); @@ -241,7 +247,9 @@ namespace Microsoft.DotNet.Migration.Tests File.Delete(Path.Combine(projectDirectory, "project.lock.json")); MigrateProject(projectDirectory); - Restore(projectDirectory); + + DeleteXproj(projectDirectory); + Restore3(projectDirectory, projectName); BuildMSBuild(projectDirectory, projectName); var msbuildBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory)); @@ -304,22 +312,37 @@ namespace Microsoft.DotNet.Migration.Tests .Pass(); } - private void Restore3(string projectDirectory, string projectName) + private void Restore3(string projectDirectory, string projectName=null) { - new Restore3Command() - .WithWorkingDirectory(projectDirectory) - .Execute($"{projectName}.csproj") + var command = new Restore3Command() + .WithWorkingDirectory(projectDirectory); + + if (projectName != null) + { + command.Execute($"{projectName}.csproj") .Should() .Pass(); + } + else + { + command.Execute() + .Should() + .Pass(); + } } private string BuildMSBuild(string projectDirectory, string projectName, string configuration="Debug") { + if (projectName != null) + { + projectName = projectName + ".csproj"; + } + DeleteXproj(projectDirectory); var result = new Build3Command() .WithWorkingDirectory(projectDirectory) - .ExecuteWithCapturedOutput($"{projectName}.csproj /p:Configuration={configuration}"); + .ExecuteWithCapturedOutput($"{projectName} /p:Configuration={configuration}"); result .Should()