Skip to content

Commit

Permalink
Add GetCompatibilePackageTargetFrameworks Task to the new packageVali…
Browse files Browse the repository at this point in the history
…dation package (dotnet#7057)

* add package valiation proj

* adding tests

* address feedback

* delete extra file

* correct typo

* set XUnitPublishTargetFramework to net5.0

* use netcoreapp3.1
  • Loading branch information
Anipik authored and akoeplinger committed Apr 12, 2021
1 parent f2c5d29 commit f8ef0f5
Show file tree
Hide file tree
Showing 9 changed files with 398 additions and 12 deletions.
40 changes: 28 additions & 12 deletions Arcade.sln
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Arcade.Common", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Arcade.Test.Common", "src\Common\Microsoft.Arcade.Test.Common\Microsoft.Arcade.Test.Common.csproj", "{6CA09DC9-E654-4906-A977-1279F6EDC109}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.PackageValidation", "src\Microsoft.DotNet.PackageValidation\Microsoft.DotNet.PackageValidation.csproj", "{B691A17B-B577-431C-AF4D-199BBAC8EC97}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.PackageValidation.Tests", "src\Microsoft.DotNet.PackageValidation.Tests\Microsoft.DotNet.PackageValidation.Tests.csproj", "{8BBF14AC-48F0-4282-910E-48E816021660}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -579,18 +583,6 @@ Global
{6E19C6B6-4ADF-4DD6-86CC-6C1624BCDB71}.Release|x64.Build.0 = Release|Any CPU
{6E19C6B6-4ADF-4DD6-86CC-6C1624BCDB71}.Release|x86.ActiveCfg = Release|Any CPU
{6E19C6B6-4ADF-4DD6-86CC-6C1624BCDB71}.Release|x86.Build.0 = Release|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Debug|x64.ActiveCfg = Debug|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Debug|x64.Build.0 = Debug|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Debug|x86.ActiveCfg = Debug|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Debug|x86.Build.0 = Debug|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Release|Any CPU.Build.0 = Release|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Release|x64.ActiveCfg = Release|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Release|x64.Build.0 = Release|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Release|x86.ActiveCfg = Release|Any CPU
{62B929C4-3D15-4D43-AEFC-2D0BD3CFC20D}.Release|x86.Build.0 = Release|Any CPU
{3376C769-211F-4537-A156-5F841FF7840B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3376C769-211F-4537-A156-5F841FF7840B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3376C769-211F-4537-A156-5F841FF7840B}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -819,6 +811,30 @@ Global
{6CA09DC9-E654-4906-A977-1279F6EDC109}.Release|x64.Build.0 = Release|Any CPU
{6CA09DC9-E654-4906-A977-1279F6EDC109}.Release|x86.ActiveCfg = Release|Any CPU
{6CA09DC9-E654-4906-A977-1279F6EDC109}.Release|x86.Build.0 = Release|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Debug|x64.ActiveCfg = Debug|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Debug|x64.Build.0 = Debug|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Debug|x86.ActiveCfg = Debug|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Debug|x86.Build.0 = Debug|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Release|Any CPU.Build.0 = Release|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Release|x64.ActiveCfg = Release|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Release|x64.Build.0 = Release|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Release|x86.ActiveCfg = Release|Any CPU
{B691A17B-B577-431C-AF4D-199BBAC8EC97}.Release|x86.Build.0 = Release|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Debug|x64.ActiveCfg = Debug|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Debug|x64.Build.0 = Debug|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Debug|x86.ActiveCfg = Debug|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Debug|x86.Build.0 = Debug|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Release|Any CPU.Build.0 = Release|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Release|x64.ActiveCfg = Release|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Release|x64.Build.0 = Release|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Release|x86.ActiveCfg = Release|Any CPU
{8BBF14AC-48F0-4282-910E-48E816021660}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using NuGet.Frameworks;
using System.Collections.Generic;
using Xunit;

namespace Microsoft.DotNet.PackageValidation.Tests
{
public class GetCompatibilePackageTargetFrameworksTests
{
public GetCompatibilePackageTargetFrameworksTests()
{
GetCompatiblePackageTargetFrameworks.Initialize();
}

public static IEnumerable<object[]> PackageTFMData => new List<object[]>
{
// single target framework in package
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetStandard20}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetStandard20, FrameworkConstants.CommonFrameworks.NetCoreApp20, FrameworkConstants.CommonFrameworks.Net463, FrameworkConstants.CommonFrameworks.Net461, FrameworkConstants.CommonFrameworks.Net462} },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp20}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp20} },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp21}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp21} },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.Net461}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.Net461} },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.Net45}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.Net45} },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp30}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp30} },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp31}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp31} },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetStandard21}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetStandard21, FrameworkConstants.CommonFrameworks.NetCoreApp30 } },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetStandard12}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetStandard12, FrameworkConstants.CommonFrameworks.Net451 } },

// two target frameworks in package
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetStandard20, FrameworkConstants.CommonFrameworks.Net461}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetStandard20, FrameworkConstants.CommonFrameworks.NetCoreApp20, FrameworkConstants.CommonFrameworks.Net463, FrameworkConstants.CommonFrameworks.Net461, FrameworkConstants.CommonFrameworks.Net462} },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetStandard20, FrameworkConstants.CommonFrameworks.NetCoreApp30}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetStandard20, FrameworkConstants.CommonFrameworks.NetCoreApp30, FrameworkConstants.CommonFrameworks.NetCoreApp20, FrameworkConstants.CommonFrameworks.Net463, FrameworkConstants.CommonFrameworks.Net461, FrameworkConstants.CommonFrameworks.Net462} },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp30, FrameworkConstants.CommonFrameworks.Net461}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp30, FrameworkConstants.CommonFrameworks.Net461} },
new object[] { new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp30, FrameworkConstants.CommonFrameworks.Net50}, new List<NuGetFramework> { FrameworkConstants.CommonFrameworks.NetCoreApp30, FrameworkConstants.CommonFrameworks.Net50} },
};

[Theory]
[MemberData(nameof(PackageTFMData))]
public void GetCompatibleFrameworks(List<NuGetFramework> packageFrameworks, List<NuGetFramework> expectedTestFrameworks)
{
List<NuGetFramework> actualTestFrameworks = GetCompatiblePackageTargetFrameworks.GetTestFrameworks(packageFrameworks);
CollectionsEqual(expectedTestFrameworks, actualTestFrameworks);
}

private static void CollectionsEqual<T>(IEnumerable<T> T1, IEnumerable<T> T2)
{
foreach (var item in T1)
{
Assert.Contains(item, T2);
}
foreach (var item in T2)
{
Assert.Contains(item, T1);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="$(MicrosoftBuildUtilitiesCoreVersion)" />
<PackageReference Include="NuGet.Frameworks" Version="$(NuGetVersion)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.DotNet.PackageValidation\Microsoft.DotNet.PackageValidation.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.DotNet.Build.Tasks;
using NuGet.Frameworks;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.DotNet.PackageValidation
{
public class GetCompatiblePackageTargetFrameworks : BuildTask
{
private static List<NuGetFramework> allTargetFrameworks = allTargetFrameworks = new();
private static Dictionary<NuGetFramework, HashSet<NuGetFramework>> packageTfmMapping = new();

[Required]
public string[] PackagePaths { get; set; }

[Output]
public ITaskItem[] TestProjects { get; set; }

public override bool Execute()
{
bool result = true;
List<ITaskItem> testProjects = new List<ITaskItem>();

try
{
Initialize();
foreach (var packagePath in PackagePaths)
{
Package package = NupkgParser.CreatePackageObject(packagePath);
List<NuGetFramework> packageTargetFrameworks = package.PackageAssets.Where(t => t.AssetType != AssetType.RuntimeAsset).Select(t => t.TargetFramework).Distinct().ToList();

List<NuGetFramework> frameworksToTest = GetTestFrameworks(packageTargetFrameworks);
testProjects.AddRange(CreateItemFromTestFramework(package.Title, package.Version, frameworksToTest, GetRidsFromPackage(package)));
}

// Removing empty items.
TestProjects = testProjects.Where(tfm => tfm.ItemSpec != "").ToArray();
}
catch (Exception e)
{
Log.LogErrorFromException(e, showStackTrace: false);
}

return result && !Log.HasLoggedErrors;
}

public static List<NuGetFramework> GetTestFrameworks(List<NuGetFramework> packageTargetFrameworks)
{
List<NuGetFramework> frameworksToTest = new List<NuGetFramework>();

// Testing the package installation on all tfms linked with package targetframeworks.
foreach (var item in packageTargetFrameworks)
{
if (packageTfmMapping.ContainsKey(item))
frameworksToTest.AddRange(packageTfmMapping[item].ToList());
}

// Pruning the test matrix by removing the frameworks we dont want to test.
frameworksToTest = frameworksToTest.Where(tfm => allTargetFrameworks.Contains(tfm)).ToList();

// Adding the frameworks in the packages to the test matrix;
frameworksToTest.AddRange(packageTargetFrameworks);
frameworksToTest = frameworksToTest.Distinct().ToList();
return frameworksToTest;
}

public static void Initialize()
{
// Defining the set of known frameworks that we care to test
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetCoreApp20);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetCoreApp21);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetCoreApp30);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetCoreApp31);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.Net50);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.Net45);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.Net451);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.Net452);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.Net46);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.Net461);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.Net462);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.Net463);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetStandard10);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetStandard11);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetStandard12);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetStandard13);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetStandard14);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetStandard15);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetStandard16);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetStandard17);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetStandard20);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.NetStandard21);
allTargetFrameworks.Add(FrameworkConstants.CommonFrameworks.UAP10);

// creating a map framework in package => frameworks to test based on default compatibilty mapping.
foreach (var item in DefaultFrameworkMappings.Instance.CompatibilityMappings)
{
NuGetFramework forwardTfm = item.SupportedFrameworkRange.Max;
NuGetFramework reverseTfm = item.TargetFrameworkRange.Min;
if (packageTfmMapping.ContainsKey(forwardTfm))
{
packageTfmMapping[forwardTfm].Add(reverseTfm);
}
else
{
packageTfmMapping.Add(forwardTfm, new HashSet<NuGetFramework> { reverseTfm });
}
}
}

public List<ITaskItem> CreateItemFromTestFramework(string title, string version, List<NuGetFramework> testFrameworks, string rids)
{
List<ITaskItem> testprojects = new List<ITaskItem>();
foreach (var framework in testFrameworks)
{
var supportedPackage = new TaskItem(title);
supportedPackage.SetMetadata("Version", version);
supportedPackage.SetMetadata("TargetFramework", framework.ToString());
supportedPackage.SetMetadata("TargetFrameworkShort", framework.GetShortFolderName());

if (!String.IsNullOrEmpty(rids))
{
supportedPackage.SetMetadata("RuntimeIdentifiers", rids);
}
testprojects.Add(supportedPackage);
}

return testprojects;
}

public string GetRidsFromPackage(Package package)
{
List<string> rids = new List<string>();
foreach (var item in package.PackageAssets)
{
if (item.AssetType == AssetType.RuntimeAsset)
{
if (!rids.Contains(item.Rid + "-x64"))
rids.Add(item.Rid + "-x64");
}
}
return string.Join(";", rids);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<ExcludeFromSourceBuild>false</ExcludeFromSourceBuild>
<PackageType>MSBuildSdk</PackageType>
<IncludeBuildOutput>false</IncludeBuildOutput>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="$(MicrosoftBuildVersion)" Publish="false" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(MicrosoftBuildTasksCoreVersion)" Publish="false" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(MsbuildTaskMicrosoftCodeAnalysisCSharpVersion)" ExcludeAssets="analyzers" />
<PackageReference Include="NuGet.Frameworks" Version="$(NuGetVersion)" />
<PackageReference Include="NuGet.Packaging" Version="$(NuGetVersion)" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Internal\BuildTask.cs" />
</ItemGroup>

<Import Project="$(RepoRoot)eng\BuildTask.targets" />

</Project>
Loading

0 comments on commit f8ef0f5

Please sign in to comment.