Handle added packages in API diff (#20428)
This commit is contained in:
committed by
GitHub
parent
4b071000a4
commit
d034e5f4e8
+101
-12
@@ -304,44 +304,95 @@ public static class ApiDiffHelper
|
||||
{
|
||||
using var packageReader = new PackageArchiveReader(currentArchive);
|
||||
packageId = packageReader.NuspecReader.GetId();
|
||||
|
||||
baselineFolderPath = outputFolderPath / "baseline" / packageId;
|
||||
Directory.CreateDirectory(baselineFolderPath);
|
||||
|
||||
currentFolderPath = outputFolderPath / "current" / packageId;
|
||||
Directory.CreateDirectory(currentFolderPath);
|
||||
|
||||
currentFolderNames = ExtractDiffableAssembliesFromPackage(currentArchive, currentFolderPath);
|
||||
}
|
||||
|
||||
// Download baseline package
|
||||
memoryStream.Position = 0L;
|
||||
memoryStream.SetLength(0L);
|
||||
await DownloadBaselinePackageAsync(memoryStream, downloadContext, packageId, baselineVersion);
|
||||
memoryStream.Position = 0L;
|
||||
var packageExists = await downloadContext.FindPackageByIdResource.DoesPackageExistAsync(
|
||||
packageId,
|
||||
baselineVersion,
|
||||
downloadContext.CacheContext,
|
||||
NullLogger.Instance,
|
||||
CancellationToken.None);
|
||||
|
||||
// Extract baseline package
|
||||
using (var baselineArchive = new ZipArchive(memoryStream, ZipArchiveMode.Read, leaveOpen: true))
|
||||
if (packageExists)
|
||||
{
|
||||
baselineFolderPath = outputFolderPath / "baseline" / packageId;
|
||||
// Download baseline package
|
||||
memoryStream.Position = 0L;
|
||||
memoryStream.SetLength(0L);
|
||||
await DownloadBaselinePackageAsync(memoryStream, downloadContext, packageId, baselineVersion);
|
||||
memoryStream.Position = 0L;
|
||||
|
||||
// Extract baseline package
|
||||
using var baselineArchive = new ZipArchive(memoryStream, ZipArchiveMode.Read, leaveOpen: true);
|
||||
baselineFolderNames = ExtractDiffableAssembliesFromPackage(baselineArchive, baselineFolderPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Information("Baseline package {Id} {Version} does not exist. Assuming new package.", packageId, baselineVersion);
|
||||
baselineFolderNames = [];
|
||||
}
|
||||
|
||||
if (currentFolderNames.Count == 0 && baselineFolderNames.Count == 0)
|
||||
continue;
|
||||
|
||||
var frameworkDiffs = new List<FrameworkDiffInfo>();
|
||||
|
||||
// Match frameworks
|
||||
foreach (var (framework, currentFolderName) in currentFolderNames)
|
||||
{
|
||||
// Ignore new frameworks that didn't exist in the baseline package. Empty folders make the ApiDiff tool crash.
|
||||
if (!baselineFolderNames.TryGetValue(framework, out var baselineFolderName))
|
||||
continue;
|
||||
baselineFolderName = currentFolderName;
|
||||
|
||||
frameworkDiffs.Add(new FrameworkDiffInfo(
|
||||
var frameworkDiff = new FrameworkDiffInfo(
|
||||
framework,
|
||||
baselineFolderPath / FolderLib / baselineFolderName,
|
||||
currentFolderPath / FolderLib / currentFolderName));
|
||||
currentFolderPath / FolderLib / currentFolderName);
|
||||
|
||||
EnsureAssemblies(frameworkDiff);
|
||||
|
||||
frameworkDiffs.Add(frameworkDiff);
|
||||
}
|
||||
|
||||
packageDiffs.Add(new PackageDiffInfo(packageId, [..frameworkDiffs]));
|
||||
}
|
||||
|
||||
return new GlobalDiffInfo(baselineVersion, currentVersion, packageDiffs.DrainToImmutable());
|
||||
|
||||
// Ensure that both sides of a framework diff have matching assemblies.
|
||||
// For any missing, generate an empty assembly to diff against.
|
||||
// (The API diff tool supports added and removed assemblies in theory but actually throws if one side doesn't have any.)
|
||||
static void EnsureAssemblies(FrameworkDiffInfo frameworkDiff)
|
||||
{
|
||||
Directory.CreateDirectory(frameworkDiff.BaselineFolderPath);
|
||||
Directory.CreateDirectory(frameworkDiff.CurrentFolderPath);
|
||||
|
||||
var baselineFileNames = GetFileNames(frameworkDiff.BaselineFolderPath);
|
||||
var currentFileNames = GetFileNames(frameworkDiff.CurrentFolderPath);
|
||||
|
||||
GenerateMissingAssemblies(currentFileNames.Except(baselineFileNames), frameworkDiff.BaselineFolderPath);
|
||||
GenerateMissingAssemblies(baselineFileNames.Except(currentFileNames), frameworkDiff.CurrentFolderPath);
|
||||
|
||||
static string[] GetFileNames(string folderPath)
|
||||
=> Directory.EnumerateFiles(folderPath, "*.dll").Select(Path.GetFileName)!.ToArray<string>();
|
||||
|
||||
void GenerateMissingAssemblies(IEnumerable<string> missingFileNames, string folderPath)
|
||||
{
|
||||
foreach (var missingFileName in missingFileNames)
|
||||
{
|
||||
GenerateEmptyAssembly(
|
||||
Path.GetFileNameWithoutExtension(missingFileName),
|
||||
frameworkDiff.Framework.GetShortFolderName(),
|
||||
Path.Join(folderPath, missingFileName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static async Task<NuGetDownloadContext> CreateNuGetDownloadContextAsync()
|
||||
@@ -453,6 +504,44 @@ public static class ApiDiffHelper
|
||||
value;
|
||||
}
|
||||
|
||||
static void GenerateEmptyAssembly(string name, string framework, string outputFilePath)
|
||||
{
|
||||
var projectContents =
|
||||
$"""
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>{framework}</TargetFramework>
|
||||
<Configuration>Release</Configuration>
|
||||
<DebugType>None</DebugType>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
""";
|
||||
|
||||
var tempDirPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
var projectFilePath = Path.Join(tempDirPath, $"{name}.csproj");
|
||||
|
||||
Directory.CreateDirectory(tempDirPath);
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(projectFilePath, projectContents);
|
||||
|
||||
using var process = ProcessTasks.StartProcess(
|
||||
"dotnet",
|
||||
$"build \"{projectFilePath}\" --output \"{tempDirPath}\"",
|
||||
tempDirPath);
|
||||
|
||||
process.AssertZeroExitCode();
|
||||
|
||||
File.Copy(Path.Join(tempDirPath, $"{name}.dll"), outputFilePath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(tempDirPath))
|
||||
Directory.Delete(tempDirPath, true);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GlobalDiffInfo(
|
||||
NuGetVersion baselineVersion,
|
||||
NuGetVersion currentVersion,
|
||||
|
||||
+4
-1
@@ -336,11 +336,14 @@ partial class Build : NukeBuild
|
||||
.DependsOn(CreateNugetPackages)
|
||||
.Executes(async () =>
|
||||
{
|
||||
var apiDiffPath = Parameters.ArtifactsDir / "api-diff";
|
||||
apiDiffPath.DeleteDirectory();
|
||||
|
||||
GlobalDiff = await ApiDiffHelper.DownloadAndExtractPackagesAsync(
|
||||
Directory.EnumerateFiles(Parameters.NugetRoot, "*.nupkg").Select(path => (AbsolutePath)path),
|
||||
NuGetVersion.Parse(Parameters.Version),
|
||||
Parameters.IsReleaseBranch,
|
||||
Parameters.ArtifactsDir / "api-diff" / "assemblies",
|
||||
apiDiffPath / "assemblies",
|
||||
Parameters.ForceApiValidationBaseline is { } forcedBaseline ? NuGetVersion.Parse(forcedBaseline) : null);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user