Skip to content

Commit 1a090ec

Browse files
authored
Pruning should account for missing VersionRange (#7124)
1 parent f5f8cb7 commit 1a090ec

3 files changed

Lines changed: 96 additions & 0 deletions

File tree

src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,7 @@ static Dictionary<string, List<string>> GetPrunableDirectPackages(PackageSpec pr
864864
foreach (var dependency in framework.Dependencies)
865865
{
866866
if (framework.PackagesToPrune.TryGetValue(dependency.Name, out PrunePackageReference packageToPrune)
867+
&& dependency.LibraryRange.VersionRange != null
867868
&& dependency.LibraryRange.VersionRange.Satisfies(packageToPrune.VersionRange.MaxVersion!))
868869
{
869870
prunedDirectPackages ??= new(StringComparer.OrdinalIgnoreCase);

src/NuGet.Core/NuGet.Commands/RestoreCommand/Utility/IncludeFlagUtils.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ internal static Dictionary<string, LibraryIncludeFlags> FlattenDependencyTypes(
6565
static bool IsDependencyPruned(LibraryDependency dependency, IReadOnlyDictionary<string, PrunePackageReference> packagesToPrune)
6666
{
6767
if (packagesToPrune?.TryGetValue(dependency.Name, out PrunePackageReference packageToPrune) == true
68+
&& dependency.LibraryRange.VersionRange != null
6869
&& dependency.LibraryRange.VersionRange.Satisfies(packageToPrune.VersionRange.MaxVersion))
6970
{
7071
return true;

test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommand_PrunePackageReference.cs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Collections.Immutable;
67
using System.IO;
78
using System.Linq;
89
using System.Threading;
910
using System.Threading.Tasks;
1011
using FluentAssertions;
1112
using NuGet.Commands.Test;
1213
using NuGet.Common;
14+
using NuGet.Frameworks;
1315
using NuGet.LibraryModel;
1416
using NuGet.Packaging;
1517
using NuGet.ProjectModel;
@@ -1452,6 +1454,98 @@ public void AnalyzePruningResults_WithMultiTargetingProjectAndVariousVersions_Wa
14521454
testEvent["Pruning.Pruned.Direct.Count"].Should().Be(1);
14531455
}
14541456

1457+
[Fact]
1458+
public void AnalyzePruningResults_WithCPMAndNullVersionRange_HandlesItGracefully()
1459+
{
1460+
var projectSpec = new PackageSpec(
1461+
[
1462+
new() {
1463+
FrameworkName = NuGetFramework.Parse("net10.0"),
1464+
TargetAlias = "net10.0",
1465+
Dependencies = ImmutableArray.Create(new LibraryDependency
1466+
{
1467+
LibraryRange = new LibraryRange("A", null, LibraryDependencyTarget.Package)
1468+
}),
1469+
PackagesToPrune = new Dictionary<string, PrunePackageReference>
1470+
{
1471+
{ "A", new PrunePackageReference("A", VersionRange.Parse("(,1.0.0]")) }
1472+
}
1473+
}
1474+
])
1475+
{
1476+
Name = "Project1",
1477+
FilePath = Path.Combine(Path.GetTempPath(), "Project1.csproj")
1478+
}.WithTestRestoreMetadata();
1479+
1480+
var testLogger = new TestLogger();
1481+
var testEvent = new TelemetryEvent("dummyEvent");
1482+
1483+
RestoreCommand.AnalyzePruningResults(projectSpec, testEvent, testLogger);
1484+
1485+
testLogger.WarningMessages.Should().BeEmpty();
1486+
testEvent["Pruning.Pruned.Direct.Count"].Should().Be(0);
1487+
}
1488+
1489+
[Fact]
1490+
public async Task RestoreCommand_WithCPMAndMissingVersion_HandlesItGracefully()
1491+
{
1492+
using var pathContext = new SimpleTestPathContext();
1493+
1494+
// Setup packages
1495+
var packageA = new SimpleTestPackageContext("A", "1.0.0");
1496+
1497+
await SimpleTestPackageUtility.CreateFolderFeedV3Async(
1498+
pathContext.PackageSource,
1499+
PackageSaveMode.Defaultv3,
1500+
packageA);
1501+
1502+
var rootProject = @"
1503+
{
1504+
""restore"": {
1505+
""centralPackageVersionsManagementEnabled"": true,
1506+
""CentralPackageTransitivePinningEnabled"": true,
1507+
},
1508+
""frameworks"": {
1509+
""net10.0"": {
1510+
""dependencies"": {
1511+
""A"": {
1512+
""version"": ""[1.0.0,)"",
1513+
""target"": ""Package"",
1514+
""versionCentrallyManaged"": true
1515+
},
1516+
},
1517+
""packagesToPrune"": {
1518+
""A"" : ""(,1.0.0]""
1519+
},
1520+
""centralPackageVersions"": {
1521+
}
1522+
}
1523+
}
1524+
}";
1525+
1526+
// Setup project using the standard pattern
1527+
var projectSpec = ProjectTestHelpers.GetPackageSpecWithProjectNameAndSpec("Project1", pathContext.SolutionRoot, rootProject);
1528+
1529+
// Modify to simulate CPM without version - create new framework with null version range
1530+
var originalFramework = projectSpec.TargetFrameworks[0];
1531+
var newFramework = new TargetFrameworkInformation(originalFramework)
1532+
{
1533+
Dependencies = [new LibraryDependency
1534+
{
1535+
LibraryRange = new LibraryRange("A", null, LibraryDependencyTarget.Package),
1536+
VersionCentrallyManaged = true,
1537+
}],
1538+
};
1539+
projectSpec.TargetFrameworks[0] = newFramework;
1540+
var testLogger = new TestLogger();
1541+
1542+
var result = await RunRestoreAsync(pathContext, testLogger, projectSpec);
1543+
1544+
result.Success.Should().BeFalse();
1545+
result.LockFile.LogMessages.Should().HaveCount(1);
1546+
result.LockFile.LogMessages[0].Code.Should().Be(NuGetLogCode.NU1010);
1547+
}
1548+
14551549
// A 1.0.0 -> B 1.0.0
14561550
// C 1.0.0
14571551
private static async Task SetupCommonPackagesAsync(SimpleTestPathContext pathContext)

0 commit comments

Comments
 (0)