Skip to content

Commit

Permalink
[TFM Display] Create model for badges and table from compatible frame…
Browse files Browse the repository at this point in the history
…works. (#8881)

* framework product names added.

* PackageFrameworkCompatibility class added.

* Fix supported frameworks to use platforms.

* FIx test with new behavior.

* nit.

* Factory that creates the table and badges is created, along with table test cases.

* Added badges tests and fix.

* Added remaining tests cases.

* nit.

* Added compatible framework to test.

* Documentation added on PackageFrameworkCompatibilityClass.

* PackageFrameworkCompatibilityBadges documentation added.

* added null documentation.

* PackageFrameworkCompatibilityTableData documentation.

* Fixed tests for IsUnsupported and IsPCL.

* Updated parameter name for CreateFrameworkCompatibilityTable method.

* Changed IReadOnlyList to ICollection.

* nit.
  • Loading branch information
dannyjdev committed Nov 18, 2021
1 parent 2d9bd91 commit 33035da
Show file tree
Hide file tree
Showing 10 changed files with 514 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ public ISet<NuGetFramework> GetCompatibleFrameworks(IEnumerable<NuGetFramework>
{
allCompatibleFrameworks.UnionWith(compatibleFrameworks);
}
else
{
allCompatibleFrameworks.Add(packageFramework);
}
}

return allCompatibleFrameworks;
Expand Down
17 changes: 17 additions & 0 deletions src/NuGetGallery.Core/Frameworks/FrameworkProductNames.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace NuGetGallery.Frameworks
{
public static class FrameworkProductNames
{
public const string Net = ".NET";
public const string NetCore = ".NET Core";
public const string NetStandard = ".NET Standard";
public const string NetFramework = ".NET Framework";
public const string NetMicroFramework = ".NET Micro Framework";
public const string UWP = "Universal Windows Platform";
public const string WindowsPhone = "Windows Phone";
public const string WindowsStore = "Windows Store";
}
}
25 changes: 25 additions & 0 deletions src/NuGetGallery.Core/Frameworks/PackageFrameworkCompatibility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

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

namespace NuGetGallery.Frameworks
{
public class PackageFrameworkCompatibility
{
/// <summary>
/// Contains a <see cref="NuGetFramework"/> for each of the .NET product (.NET, .NET Core, .NET Standard, and .NET Framework).
/// </summary>
public PackageFrameworkCompatibilityBadges Badges { get; set; }

/// <summary>
/// Contains a dictionary filled with all the package asset frameworks and all the computed compatible frameworks retrieved from <see cref="FrameworkCompatibilityService"/>.<br></br>
/// </summary>
/// <remarks>
/// Key: Is the <see cref="FrameworkProductNames"/> if resolved on (<seealso cref="PackageFrameworkCompatibilityFactory.ResolveFrameworkProductName(NuGetFramework)"/>) or the <see cref="NuGetFramework.Framework"/>.<br></br>
/// Value: Is an ordered collection containing all the compatible frameworks.
/// </remarks>
public IReadOnlyDictionary<string, ICollection<PackageFrameworkCompatibilityTableData>> Table { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using NuGet.Frameworks;

namespace NuGetGallery.Frameworks
{
/// <summary>
/// Contains a <see cref="NuGetFramework"/> for each of the .NET product (.NET, .NET Core, .NET Standard, and .NET Framework).
/// </summary>
/// <remarks>
/// All these properties are retrieved from the <see cref="PackageFrameworkCompatibility.Table"/>, one for each .NET product.<br></br>
/// Only package asset frameworks are considered. i.e. <see cref="PackageFrameworkCompatibilityTableData.IsComputed"/> <c>= false</c>.<br></br>
/// If there are no package asset frameworks for a particular .NET product, then the value will be <c>null</c>.
/// </remarks>
public class PackageFrameworkCompatibilityBadges
{
public NuGetFramework Net { get; set; }
public NuGetFramework NetCore { get; set; }
public NuGetFramework NetStandard { get; set; }
public NuGetFramework NetFramework { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using NuGet.Frameworks;
using NuGet.Services.Entities;

namespace NuGetGallery.Frameworks
{
public class PackageFrameworkCompatibilityFactory
{
private readonly ISet<Version> WindowsStoreNetCoreVersions = new HashSet<Version> { FrameworkConstants.EmptyVersion, Version.Parse("4.5.0.0"), Version.Parse("4.5.1.0") };
private readonly ISet<Version> WindowsStoreWindowsVersions = new HashSet<Version> { FrameworkConstants.EmptyVersion, Version.Parse("8.0.0.0"), Version.Parse("8.1.0.0") };
private readonly NuGetFrameworkSorter Sorter = new NuGetFrameworkSorter();
private readonly int NetStartingMajorVersion = 5;

private readonly IFrameworkCompatibilityService _compatibilityService;

public PackageFrameworkCompatibilityFactory(IFrameworkCompatibilityService compatibilityService)
{
_compatibilityService = compatibilityService ?? throw new ArgumentNullException();
}

public PackageFrameworkCompatibility Create(ICollection<PackageFramework> packageFrameworks)
{
if (packageFrameworks == null)
{
throw new ArgumentNullException(nameof(packageFrameworks));
}

var filteredPackageFrameworks = packageFrameworks
.Select(pf => pf.FrameworkName)
.Where(f => !f.IsUnsupported && !f.IsPCL)
.ToHashSet();

var table = CreateFrameworkCompatibilityTable(filteredPackageFrameworks);
var badges = CreateFrameworkCompatibilityBadges(table);

return new PackageFrameworkCompatibility
{
Badges = badges,
Table = table
};
}

private IReadOnlyDictionary<string, ICollection<PackageFrameworkCompatibilityTableData>> CreateFrameworkCompatibilityTable(ICollection<NuGetFramework> filteredPackageFrameworks)
{
var compatibleFrameworks = _compatibilityService.GetCompatibleFrameworks(filteredPackageFrameworks);

var table = new Dictionary<string, ICollection<PackageFrameworkCompatibilityTableData>>();

foreach (var compatibleFramework in compatibleFrameworks)
{
var productName = ResolveFrameworkProductName(compatibleFramework);
var data = new PackageFrameworkCompatibilityTableData
{
Framework = compatibleFramework,
IsComputed = !filteredPackageFrameworks.Contains(compatibleFramework)
};

if (table.TryGetValue(productName, out var allCompatibleFrameworks))
{
allCompatibleFrameworks.Add(data);
}
else
{
var newCompatibleFrameworks = new SortedSet<PackageFrameworkCompatibilityTableData>
(Comparer<PackageFrameworkCompatibilityTableData>.Create((a, b) => Sorter.Compare(a.Framework, b.Framework)));

newCompatibleFrameworks.Add(data);
table.Add(productName, newCompatibleFrameworks);
}
}

return table;
}

private string ResolveFrameworkProductName(NuGetFramework framework)
{
// See: https://docs.microsoft.com/en-us/dotnet/standard/frameworks#supported-target-frameworks
switch (framework.Framework)
{
case FrameworkConstants.FrameworkIdentifiers.NetCoreApp:
return framework.Version.Major >= NetStartingMajorVersion ? FrameworkProductNames.Net : FrameworkProductNames.NetCore;
case FrameworkConstants.FrameworkIdentifiers.NetStandard:
case FrameworkConstants.FrameworkIdentifiers.NetStandardApp:
return FrameworkProductNames.NetStandard;
case FrameworkConstants.FrameworkIdentifiers.Net:
return FrameworkProductNames.NetFramework;
case FrameworkConstants.FrameworkIdentifiers.NetMicro:
return FrameworkProductNames.NetMicroFramework;
case FrameworkConstants.FrameworkIdentifiers.WindowsPhoneApp:
case FrameworkConstants.FrameworkIdentifiers.WindowsPhone:
return FrameworkProductNames.WindowsPhone;
case FrameworkConstants.FrameworkIdentifiers.NetCore:
if (framework.Version == FrameworkConstants.Version5)
{
return FrameworkProductNames.UWP;
}

if (WindowsStoreNetCoreVersions.Contains(framework.Version))
{
return FrameworkProductNames.WindowsStore;
}

return FrameworkConstants.FrameworkIdentifiers.NetCore;
case FrameworkConstants.FrameworkIdentifiers.Windows:
if (WindowsStoreWindowsVersions.Contains(framework.Version))
{
return FrameworkProductNames.WindowsStore;
}
return FrameworkConstants.FrameworkIdentifiers.Windows;
case FrameworkConstants.FrameworkIdentifiers.UAP:
return FrameworkProductNames.UWP;
}

return framework.Framework;
}

private PackageFrameworkCompatibilityBadges CreateFrameworkCompatibilityBadges(IReadOnlyDictionary<string, ICollection<PackageFrameworkCompatibilityTableData>> table)
{
var net = GetBadgeFramework(table, FrameworkProductNames.Net);
var netCore = GetBadgeFramework(table, FrameworkProductNames.NetCore);
var netStandard = GetBadgeFramework(table, FrameworkProductNames.NetStandard);
var netFramework = GetBadgeFramework(table, FrameworkProductNames.NetFramework);

return new PackageFrameworkCompatibilityBadges
{
Net = net,
NetCore = netCore,
NetStandard = netStandard,
NetFramework = netFramework
};
}

private NuGetFramework GetBadgeFramework(IReadOnlyDictionary<string, ICollection<PackageFrameworkCompatibilityTableData>> table, string productName)
{
if (table.TryGetValue(productName, out var data))
{
return data
.Where(d => !d.IsComputed)
.Select(d => d.Framework)
.FirstOrDefault();
}

return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using NuGet.Frameworks;

namespace NuGetGallery.Frameworks
{
public class PackageFrameworkCompatibilityTableData
{
/// <summary>
/// Compatible framework.
/// </summary>
public NuGetFramework Framework { get; set; }

/// <summary>
/// <see langword="true"/> if the <see cref="Framework"/> was computed from <see cref="IFrameworkCompatibilityService"/>.<br></br>
/// <see langword="false"/> if the <see cref="Framework"/> was retrieved from the package asset frameworks.
/// </summary>
public bool IsComputed { get; set; }
}
}
16 changes: 8 additions & 8 deletions src/NuGetGallery.Core/Frameworks/SupportedFrameworks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ public static class SupportedFrameworks
public static readonly NuGetFramework MonoTouch = new NuGetFramework(FrameworkIdentifiers.MonoTouch, EmptyVersion);
public static readonly NuGetFramework MonoMac = new NuGetFramework(FrameworkIdentifiers.MonoMac, EmptyVersion);
public static readonly NuGetFramework Net48 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 8, 0, 0));
public static readonly NuGetFramework Net50Windows = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version5, "windows");
public static readonly NuGetFramework Net60Android = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "android");
public static readonly NuGetFramework Net60Ios = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "ios");
public static readonly NuGetFramework Net60MacOs = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "macos");
public static readonly NuGetFramework Net60MacCatalyst = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "maccatalyst");
public static readonly NuGetFramework Net60Tizen = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "tizen");
public static readonly NuGetFramework Net60TvOs = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "tvos");
public static readonly NuGetFramework Net60Windows = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "windows");
public static readonly NuGetFramework Net50Windows = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version5, "windows", EmptyVersion);
public static readonly NuGetFramework Net60Android = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "android", EmptyVersion);
public static readonly NuGetFramework Net60Ios = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "ios", EmptyVersion);
public static readonly NuGetFramework Net60MacOs = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "macos", EmptyVersion);
public static readonly NuGetFramework Net60MacCatalyst = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "maccatalyst", EmptyVersion);
public static readonly NuGetFramework Net60Tizen = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "tizen", EmptyVersion);
public static readonly NuGetFramework Net60TvOs = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "tvos", EmptyVersion);
public static readonly NuGetFramework Net60Windows = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "windows", EmptyVersion);
public static readonly NuGetFramework NetCore = new NuGetFramework(FrameworkIdentifiers.NetCore, EmptyVersion);
public static readonly NuGetFramework NetMf = new NuGetFramework(FrameworkIdentifiers.NetMicro, EmptyVersion);
public static readonly NuGetFramework UAP = new NuGetFramework(FrameworkIdentifiers.UAP, EmptyVersion);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,19 @@ public void EmptyPackageFrameworksReturnsEmptySet()
{
var result = _service.GetCompatibleFrameworks(new List<NuGetFramework>());

Assert.Equal(expected: 0, actual: result.Count);
Assert.Empty(result);
}

[Fact]
public void UnknownSupportedPackageReturnsEmptySet()
public void UnknownSupportedPackageReturnsSetWithSameFramework()
{
var framework = NuGetFramework.Parse("netstandard9.2");
var framework = NuGetFramework.Parse("net45-client");
var frameworks = new List<NuGetFramework>() { framework };
var compatible = _service.GetCompatibleFrameworks(frameworks);

Assert.False(framework.IsUnsupported);
Assert.Equal(expected: 0, compatible.Count);
Assert.Equal(expected: 1, compatible.Count);
Assert.Contains(framework, compatible);
}

[Theory]
Expand Down
Loading

0 comments on commit 33035da

Please sign in to comment.