-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[APICompat] Don't filter package assets and handle placeholder files #27822
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
using Microsoft.DotNet.ApiCompatibility; | ||
using Microsoft.DotNet.ApiCompatibility.Logging; | ||
using Microsoft.DotNet.ApiCompatibility.Runner; | ||
using Microsoft.DotNet.ApiSymbolExtensions.Logging; | ||
using NuGet.ContentModel; | ||
using NuGet.Frameworks; | ||
|
||
|
@@ -31,6 +32,19 @@ public static void QueueApiCompatFromContentItem(this IApiCompatRunner apiCompat | |
return; | ||
} | ||
|
||
// Don't perform api compatibility checks on placeholder files. | ||
if (leftContentItems.IsPlaceholderFile() && rightContentItems.IsPlaceholderFile()) | ||
{ | ||
leftContentItems[0].Properties.TryGetValue("tfm", out object? tfmRaw); | ||
string tfm = tfmRaw?.ToString() ?? string.Empty; | ||
|
||
log.LogMessage(MessageImportance.Normal, string.Format(Resources.SkipApiCompatForPlaceholderFiles, tfm)); | ||
} | ||
|
||
// Make sure placeholder package files aren't enqueued as api comparison check work items. | ||
Debug.Assert(!leftContentItems.IsPlaceholderFile() && !rightContentItems.IsPlaceholderFile(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is an accurate assert. What if a package explicitly adds a placeholder in a compatible framework? It might do this if a) the library became part of that framework and we could compare the package library to the framework library (in references) or b) as an intentional breaking change in which case we should still compare and raise the missing file. |
||
"Placeholder files must not be enqueued for api comparison checks."); | ||
|
||
// If a right hand side package is provided in addition to the left side, package validation runs in baseline comparison mode. | ||
// The assumption stands that the right hand side is "current" and has more information than the left, i.e. assembly references. | ||
// If the left package doesn't provide assembly references, fallback to the references from the right side if the TFMs are compatible. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,6 @@ | |
using NuGet.ContentModel; | ||
using NuGet.Frameworks; | ||
using NuGet.Packaging; | ||
using NuGet.Packaging.Core; | ||
using NuGet.RuntimeModel; | ||
|
||
namespace Microsoft.DotNet.PackageValidation | ||
|
@@ -136,7 +135,7 @@ public static Package Create(string? packagePath, IReadOnlyDictionary<NuGetFrame | |
NuspecReader nuspecReader = packageReader.NuspecReader; | ||
string packageId = nuspecReader.GetId(); | ||
string version = nuspecReader.GetVersion().ToString(); | ||
IEnumerable<string> packageAssets = packageReader.GetFiles().Where(t => t.EndsWith(".dll")).ToArray(); | ||
IEnumerable<string> packageAssets = packageReader.GetFiles().ToArray(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make sure you add a couple tests to ensure we can handle the other file types that NuGet will give us. I wonder if we should ignore exe, or allow folks to specify something to ignore exe's? I guess they could add a suppression to ignore all things from the comparison of an exe. |
||
|
||
return new Package(packagePath!, packageId, version, packageAssets, packageAssemblyReferences); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,13 +43,21 @@ public void Validate(PackageValidatorOption options) | |
{ | ||
// Search for compatible compile time assets in the latest package. | ||
IReadOnlyList<ContentItem>? latestCompileAssets = options.Package.FindBestCompileAssetForFramework(baselineTargetFramework); | ||
if (latestCompileAssets == null) | ||
// Emit an error if | ||
// - No latest compile time asset is available or | ||
// - The latest compile time asset is a placeholder but the baseline compile time asset isn't. | ||
if (latestCompileAssets == null || | ||
(latestCompileAssets.IsPlaceholderFile() && !baselineCompileAssets.IsPlaceholderFile())) | ||
{ | ||
log.LogError(new Suppression(DiagnosticIds.TargetFrameworkDropped) { Target = baselineTargetFramework.ToString() }, | ||
DiagnosticIds.TargetFrameworkDropped, | ||
string.Format(Resources.MissingTargetFramework, | ||
baselineTargetFramework)); | ||
} | ||
else if (baselineCompileAssets.IsPlaceholderFile() && !latestCompileAssets.IsPlaceholderFile()) | ||
{ | ||
// Ignore the newly added compile time asset in the latest package. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In strict mode I think we would want to flag this. |
||
} | ||
else if (options.EnqueueApiCompatWorkItems) | ||
{ | ||
apiCompatRunner.QueueApiCompatFromContentItem(log, | ||
|
@@ -67,13 +75,21 @@ public void Validate(PackageValidatorOption options) | |
{ | ||
// Search for compatible runtime assets in the latest package. | ||
IReadOnlyList<ContentItem>? latestRuntimeAssets = options.Package.FindBestRuntimeAssetForFramework(baselineTargetFramework); | ||
if (latestRuntimeAssets == null) | ||
// Emit an error if | ||
// - No latest runtime asset is available or | ||
// - The latest runtime asset is a placeholder but the baseline runtime asset isn't. | ||
if (latestRuntimeAssets == null || | ||
(latestRuntimeAssets.IsPlaceholderFile() && !baselineRuntimeAssets.IsPlaceholderFile())) | ||
{ | ||
log.LogError(new Suppression(DiagnosticIds.TargetFrameworkDropped) { Target = baselineTargetFramework.ToString() }, | ||
DiagnosticIds.TargetFrameworkDropped, | ||
string.Format(Resources.MissingTargetFramework, | ||
baselineTargetFramework)); | ||
} | ||
else if (baselineRuntimeAssets.IsPlaceholderFile() && !latestRuntimeAssets.IsPlaceholderFile()) | ||
{ | ||
// Ignore the newly added run time asset in the latest package. | ||
} | ||
else if (options.EnqueueApiCompatWorkItems) | ||
{ | ||
apiCompatRunner.QueueApiCompatFromContentItem(log, | ||
|
@@ -95,19 +111,28 @@ public void Validate(PackageValidatorOption options) | |
|
||
foreach (IGrouping<string, ContentItem> baselineRuntimeSpecificAssetsRidGroup in baselineRuntimeSpecificAssetsRidGroupedPerRid) | ||
{ | ||
IReadOnlyList<ContentItem> baselineRuntimeSpecificAssetsForRid = baselineRuntimeSpecificAssetsRidGroup.ToArray(); | ||
IReadOnlyList<ContentItem>? latestRuntimeSpecificAssets = options.Package.FindBestRuntimeAssetForFrameworkAndRuntime(baselineTargetFramework, baselineRuntimeSpecificAssetsRidGroup.Key); | ||
if (latestRuntimeSpecificAssets == null) | ||
// Emit an error if | ||
// - No latest runtime specific asset is available or | ||
// - The latest runtime specific asset is a placeholder but the baseline runtime specific asset isn't. | ||
if (latestRuntimeSpecificAssets == null || | ||
(latestRuntimeSpecificAssets.IsPlaceholderFile() && !baselineRuntimeSpecificAssetsForRid.IsPlaceholderFile())) | ||
{ | ||
log.LogError(new Suppression(DiagnosticIds.TargetFrameworkAndRidPairDropped) { Target = baselineTargetFramework.ToString() + "-" + baselineRuntimeSpecificAssetsRidGroup.Key }, | ||
DiagnosticIds.TargetFrameworkAndRidPairDropped, | ||
string.Format(Resources.MissingTargetFrameworkAndRid, | ||
baselineTargetFramework, | ||
baselineRuntimeSpecificAssetsRidGroup.Key)); | ||
} | ||
else if (baselineRuntimeSpecificAssetsForRid.IsPlaceholderFile() && !latestRuntimeSpecificAssets.IsPlaceholderFile()) | ||
{ | ||
// Ignore the newly added runtime specific asset in the latest package. | ||
} | ||
else if (options.EnqueueApiCompatWorkItems) | ||
{ | ||
apiCompatRunner.QueueApiCompatFromContentItem(log, | ||
baselineRuntimeSpecificAssetsRidGroup.ToArray(), | ||
baselineRuntimeSpecificAssetsForRid, | ||
latestRuntimeSpecificAssets, | ||
apiCompatOptions, | ||
options.BaselinePackage, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the condition here should be if left is a placeholder and we're not in strict mode?
When in strict mode, then if left is placeholder right must also be placeholder.
Perhaps we cover these cases by just fleshing out the comparisons with tests involving placeholders.