Skip to content

Commit

Permalink
Merge pull request #11127 from dependabot/dev/brettfo/nuget-sdk-packa…
Browse files Browse the repository at this point in the history
…ge-detection

improve nuget package detection with SDK-managed packages
  • Loading branch information
randhircs authored Jan 9, 2025
2 parents 95ac9a6 + 00a4c8b commit 0c65ca6
Show file tree
Hide file tree
Showing 36 changed files with 1,354 additions and 66 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
path = nuget/helpers/lib/NuGet.Client
url = https://github.com/NuGet/NuGet.Client
branch = release-6.12.x
[submodule "nuget/helpers/lib/dotnet-core"]
path = nuget/helpers/lib/dotnet-core
url = https://github.com/dotnet/core
1 change: 1 addition & 0 deletions nuget/helpers/lib/NuGetUpdater/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ bin/
obj/
Properties/launchSettings.json
NuGetUpdater.sln.DotSettings.user
NuGetUpdater.Core/dotnet-package-correlation.json
*.binlog
1 change: 1 addition & 0 deletions nuget/helpers/lib/NuGetUpdater/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<PackageVersion Include="MSBuild.StructuredLogger" Version="2.2.386" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="NuGet.Core" Version="2.14.0" Aliases="CoreV2" />
<PackageVersion Include="Semver" Version="3.0.0" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.0" />
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(CommonTargetFramework)</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\DotNetPackageCorrelation\DotNetPackageCorrelation.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.CommandLine;
using System.Text.Json;

using DotNetPackageCorrelation;

namespace DotNetPackageCorrelation.Cli;

public class Program
{
public static async Task<int> Main(string[] args)
{
var coreLocationOption = new Option<DirectoryInfo>("--core-location", "The location of the .NET Core source code.") { IsRequired = true };
var outputOption = new Option<FileInfo>("--output", "The location to write the result.") { IsRequired = true };
var command = new Command("build")
{
coreLocationOption,
outputOption,
};
command.TreatUnmatchedTokensAsErrors = true;
command.SetHandler(async (coreLocationDirectory, output) =>
{
// the tool is expected to be given the path to the .NET Core repository, but the correlator only needs a specific subdirectory
var releaseNotesDirectory = new DirectoryInfo(Path.Combine(coreLocationDirectory.FullName, "release-notes"));
var correlator = new Correlator(releaseNotesDirectory);
var (sdkPackages, _warnings) = await correlator.RunAsync();
var json = JsonSerializer.Serialize(sdkPackages, Correlator.SerializerOptions);
await File.WriteAllTextAsync(output.FullName, json);
}, coreLocationOption, outputOption);
var exitCode = await command.InvokeAsync(args);
return exitCode;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using Semver;

using Xunit;

namespace DotNetPackageCorrelation.Tests;

public class CorrelatorTests
{
[Fact]
public async Task FileHandling_AllFilesShapedAppropriately()
{
// the JSON and markdown are shaped as expected
// we're able to determine from `Runtime.Package/8.0.0` that the corresponding version of `Some.Package` is `1.2.3`
var (packageMapper, warnings) = await PackageMapperFromFilesAsync(
("8.0/releases.json", """
{
"releases": [
{
"sdk": {
"version": "8.0.100",
"runtime-version": "8.0.0"
}
}
]
}
"""),
("8.0/8.0.0/8.0.0.md", """
Package name | Version
:-- | :--
Runtime.Package | 8.0.0
Some.Package | 1.2.3
""")
);
Assert.Empty(warnings);
AssertPackageVersion(packageMapper, "Runtime.Package", "8.0.0", "Some.Package", "1.2.3");
}

[Theory]
[InlineData("Some.Package | 1.2.3", "Some.Package", "1.2.3")] // happy path
[InlineData("Some.Package.1.2.3", "Some.Package", "1.2.3")] // looks like a restore directory
[InlineData("Some.Package | 1.2 | 1.2.3.nupkg", "Some.Package", "1.2.3")] // extra columns from a bad filename split
[InlineData("Some.Package | 1.2.3.nupkg", "Some.Package", "1.2.3")] // version contains package extension
[InlineData("Some.Package | 1.2.3.symbols.nupkg", "Some.Package", "1.2.3")] // version contains symbols package extension
[InlineData("some.package.1.2.3.nupkg", "some.package", "1.2.3")] // first column is a filename, second column is missing
[InlineData("some.package.1.2.3.nupkg |", "some.package", "1.2.3")] // first column is a filename, second column is empty
public void PackagesParsedFromMarkdown(string markdownLine, string expectedPackageName, string expectedPackageVersion)
{
var markdownContent = $"""
Package name | Version
:-- | :--
{markdownLine}
""";
var warnings = new List<string>();
var packages = Correlator.GetPackagesFromMarkdown("test.md", markdownContent, warnings);
Assert.Empty(warnings);
var actualpackage = Assert.Single(packages);
Assert.Equal(expectedPackageName, actualpackage.Name);
Assert.Equal(expectedPackageVersion, actualpackage.Version.ToString());
}

private static void AssertPackageVersion(PackageMapper packageMapper, string runtimePackageName, string runtimePackageVersion, string candidatePackageName, string? expectedPackageVersion)
{
var actualPackageVersion = packageMapper.GetPackageVersionThatShippedWithOtherPackage(runtimePackageName, SemVersion.Parse(runtimePackageVersion), candidatePackageName);
if (expectedPackageVersion is null)
{
Assert.Null(actualPackageVersion);
}
else
{
Assert.NotNull(actualPackageVersion);
Assert.Equal(expectedPackageVersion, actualPackageVersion.ToString());
}
}

private static async Task<(PackageMapper PackageMapper, IEnumerable<string> Warnings)> PackageMapperFromFilesAsync(params (string Path, string Content)[] files)
{
var testDirectory = Path.Combine(Path.GetDirectoryName(typeof(CorrelatorTests).Assembly.Location)!, "test-data", Guid.NewGuid().ToString("D"));
Directory.CreateDirectory(testDirectory);

try
{
foreach (var (path, content) in files)
{
var fullPath = Path.Combine(testDirectory, path);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!);
await File.WriteAllTextAsync(fullPath, content);
}

var correlator = new Correlator(new DirectoryInfo(testDirectory));
var (runtimePackages, warnings) = await correlator.RunAsync();
var packageMapper = PackageMapper.Load(runtimePackages);
return (packageMapper, warnings);
}
finally
{
Directory.Delete(testDirectory, recursive: true);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(CommonTargetFramework)</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\DotNetPackageCorrelation\DotNetPackageCorrelation.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Runtime.CompilerServices;

using Semver;

using Xunit;

namespace DotNetPackageCorrelation.Tests;

public class EndToEndTests
{
[Fact]
public async Task IntegrationTest()
{
// arrange
var thisFileDirectory = Path.GetDirectoryName(GetThisFilePath())!;
var dotnetCoreDirectory = Path.Combine(thisFileDirectory, "..", "..", "dotnet-core");
var correlator = new Correlator(new DirectoryInfo(Path.Combine(dotnetCoreDirectory, "release-notes")));

// act
var (runtimePackages, _warnings) = await correlator.RunAsync();
var packageMapper = PackageMapper.Load(runtimePackages);

// assert
// Microsoft.NETCore.App.Ref/8.0.8 didn't ship with System.Text.Json, but the previous version 8.0.7 shipped at the same time as System.Text.Json/8.0.4
var systemTextJsonVersion = packageMapper.GetPackageVersionThatShippedWithOtherPackage("Microsoft.NETCore.App.Ref", SemVersion.Parse("8.0.8"), "System.Text.Json");
Assert.Equal("8.0.4", systemTextJsonVersion?.ToString());
}

private static string GetThisFilePath([CallerFilePath] string? path = null) => path ?? throw new ArgumentNullException(nameof(path));
}
Loading

0 comments on commit 0c65ca6

Please sign in to comment.