/// <summary> /// Validates that the compatible frameworks have compatible surface area. /// </summary> /// <param name="package">Nuget Package that needs to be validated.</param> public void Validate(PackageValidatorOption option) { ApiCompatRunner apiCompatRunner = new(_log, option.EnableStrictMode, option.FrameworkReferences, option.Package.PackagePath); ManagedCodeConventions conventions = new(null); PatternSet patternSet = option.Package.RefAssets.Any() ? conventions.Patterns.CompileRefAssemblies : conventions.Patterns.CompileLibAssemblies; IEnumerable <ContentItem> compileAssets = option.Package.CompileAssets.OrderByDescending(t => ((NuGetFramework)t.Properties["tfm"]).Version); Queue <ContentItem> compileAssetsQueue = new(compileAssets); while (compileAssetsQueue.Count > 0) { ContentItem compileTimeAsset = compileAssetsQueue.Dequeue(); // If no assets are available for comparison, stop the iteration. if (compileAssetsQueue.Count == 0) { break; } // The runtime graph doesn't need to be passed in to the collection as compile time assets can't be rid specific. ContentItemCollection contentItemCollection = new(); // The collection won't contain the current compile time asset as it is already dequeued. contentItemCollection.Load(compileAssetsQueue.Select(t => t.Path)); NuGetFramework framework = (NuGetFramework)compileTimeAsset.Properties["tfm"]; SelectionCriteria managedCriteria = conventions.Criteria.ForFramework(framework); // Searches for a compatible compile time asset and compares it. ContentItem?compatibleFrameworkAsset = contentItemCollection.FindBestItemGroup(managedCriteria, patternSet)?.Items.FirstOrDefault(); if (compatibleFrameworkAsset != null) { string header = string.Format(Resources.ApiCompatibilityHeader, compatibleFrameworkAsset.Path, compileTimeAsset.Path); apiCompatRunner.QueueApiCompatFromContentItem(option.Package.PackageId, compatibleFrameworkAsset, compileTimeAsset, header); } } apiCompatRunner.RunApiCompat(); }
/// <summary> /// Validates that there are compile time and runtime assets for all the compatible frameworks. /// Validates that the surface between compile time and runtime assets is compatible. /// </summary> /// <param name="package">Nuget Package that needs to be validated.</param> public void Validate(PackageValidatorOption option) { ApiCompatRunner apiCompatRunner = new(_log, option.EnableStrictMode, option.FrameworkReferences, option.Package.PackagePath); HashSet <NuGetFramework> compatibleTargetFrameworks = new(); foreach (NuGetFramework item in option.Package.FrameworksInPackage) { compatibleTargetFrameworks.Add(item); if (s_packageTfmMapping.ContainsKey(item)) { compatibleTargetFrameworks.UnionWith(s_packageTfmMapping[item]); } } foreach (NuGetFramework framework in compatibleTargetFrameworks) { ContentItem?compileTimeAsset = option.Package.FindBestCompileAssetForFramework(framework); if (compileTimeAsset == null) { _log.LogError( new Suppression(DiagnosticIds.ApplicableCompileTimeAsset) { Target = framework.ToString() }, DiagnosticIds.ApplicableCompileTimeAsset, Resources.NoCompatibleCompileTimeAsset, framework.ToString()); break; } ContentItem?runtimeAsset = option.Package.FindBestRuntimeAssetForFramework(framework); if (runtimeAsset == null) { _log.LogError( new Suppression(DiagnosticIds.CompatibleRuntimeRidLessAsset) { Target = framework.ToString() }, DiagnosticIds.CompatibleRuntimeRidLessAsset, Resources.NoCompatibleRuntimeAsset, framework.ToString()); } // Invoke ApiCompat to compare the compile time asset with the runtime asset if they are not the same assembly. else if (option.RunApiCompat && compileTimeAsset.Path != runtimeAsset.Path) { string header = string.Format(Resources.ApiCompatibilityHeader, compileTimeAsset.Path, runtimeAsset.Path); apiCompatRunner.QueueApiCompatFromContentItem(option.Package.PackageId, compileTimeAsset, runtimeAsset, header); } foreach (string rid in option.Package.Rids.Where(t => IsSupportedRidTargetFrameworkPair(framework, t))) { ContentItem?runtimeRidSpecificAsset = option.Package.FindBestRuntimeAssetForFrameworkAndRuntime(framework, rid); if (runtimeRidSpecificAsset == null) { _log.LogError( new Suppression(DiagnosticIds.CompatibleRuntimeRidSpecificAsset) { Target = framework.ToString() + "-" + rid }, DiagnosticIds.CompatibleRuntimeRidSpecificAsset, Resources.NoCompatibleRidSpecificRuntimeAsset, framework.ToString(), rid); } // Invoke ApiCompat to compare the compile time asset with the runtime specific asset if they are not the same and // if the comparison hasn't already happened (when the runtime asset is the same as the runtime specific asset). else if (option.RunApiCompat && compileTimeAsset.Path != runtimeRidSpecificAsset.Path && (runtimeAsset == null || runtimeAsset.Path != runtimeRidSpecificAsset.Path)) { string header = string.Format(Resources.ApiCompatibilityHeader, compileTimeAsset.Path, runtimeRidSpecificAsset.Path); apiCompatRunner.QueueApiCompatFromContentItem(option.Package.PackageId, compileTimeAsset, runtimeRidSpecificAsset, header); } } } if (option.RunApiCompat) { apiCompatRunner.RunApiCompat(); } }
/// <summary> /// Validates the latest nuget package doesnot drop any target framework/rid and does not introduce any breaking changes. /// </summary> /// <param name="package">Nuget Package that needs to be validated.</param> public void Validate(PackageValidatorOption option) { if (option.BaselinePackage is null) { throw new ArgumentNullException(nameof(option.BaselinePackage)); } ApiCompatRunner apiCompatRunner = new(_log, option.EnableStrictMode, option.FrameworkReferences, option.BaselinePackage.PackagePath, option.Package.PackagePath); // Iterate over all available baseline assets foreach (ContentItem baselineCompileTimeAsset in option.BaselinePackage.RefAssets) { // Search for a compatible compile time asset in the latest package NuGetFramework baselineTargetFramework = (NuGetFramework)baselineCompileTimeAsset.Properties["tfm"]; ContentItem? latestCompileTimeAsset = option.Package.FindBestCompileAssetForFramework(baselineTargetFramework); if (latestCompileTimeAsset == null) { _log.LogError( new Suppression(DiagnosticIds.TargetFrameworkDropped) { Target = baselineTargetFramework.ToString() }, DiagnosticIds.TargetFrameworkDropped, Resources.MissingTargetFramework, baselineTargetFramework.ToString()); } else if (option.RunApiCompat) { string header = string.Format(Resources.ApiCompatibilityBaselineHeader, baselineCompileTimeAsset.Path, latestCompileTimeAsset.Path, option.BaselinePackage.Version, option.Package.Version); apiCompatRunner.QueueApiCompatFromContentItem(option.Package.PackageId, baselineCompileTimeAsset, latestCompileTimeAsset, header, isBaseline: true); } } // Iterates over both runtime and runtime specific baseline assets and searches for a compatible non runtime // specific asset in the latest package. foreach (ContentItem baselineRuntimeAsset in option.BaselinePackage.RuntimeAssets) { // Search for a compatible runtime asset in the latest package NuGetFramework baselineTargetFramework = (NuGetFramework)baselineRuntimeAsset.Properties["tfm"]; ContentItem? latestRuntimeAsset = option.Package.FindBestRuntimeAssetForFramework(baselineTargetFramework); if (latestRuntimeAsset == null) { _log.LogError( new Suppression(DiagnosticIds.TargetFrameworkDropped) { Target = baselineTargetFramework.ToString() }, DiagnosticIds.TargetFrameworkDropped, Resources.MissingTargetFramework, baselineTargetFramework.ToString()); } else if (option.RunApiCompat) { string header = string.Format(Resources.ApiCompatibilityBaselineHeader, baselineRuntimeAsset.Path, latestRuntimeAsset.Path, option.BaselinePackage.Version, option.Package.Version); apiCompatRunner.QueueApiCompatFromContentItem(option.Package.PackageId, baselineRuntimeAsset, latestRuntimeAsset, header, isBaseline: true); } } // Compares runtime specific baseline assets against runtime specific latest assets. foreach (ContentItem baselineRuntimeSpecificAsset in option.BaselinePackage.RuntimeSpecificAssets) { NuGetFramework baselineTargetFramework = (NuGetFramework)baselineRuntimeSpecificAsset.Properties["tfm"]; string baselineRid = (string)baselineRuntimeSpecificAsset.Properties["rid"]; ContentItem? latestRuntimeSpecificAsset = option.Package.FindBestRuntimeAssetForFrameworkAndRuntime(baselineTargetFramework, baselineRid); if (latestRuntimeSpecificAsset == null) { _log.LogError( new Suppression(DiagnosticIds.TargetFrameworkAndRidPairDropped) { Target = baselineTargetFramework.ToString() + "-" + baselineRid }, DiagnosticIds.TargetFrameworkAndRidPairDropped, Resources.MissingTargetFrameworkAndRid, baselineTargetFramework.ToString(), baselineRid); } else if (option.RunApiCompat) { string header = string.Format(Resources.ApiCompatibilityBaselineHeader, baselineRuntimeSpecificAsset.Path, latestRuntimeSpecificAsset.Path, option.BaselinePackage.Version, option.Package.Version); apiCompatRunner.QueueApiCompatFromContentItem(option.Package.PackageId, baselineRuntimeSpecificAsset, latestRuntimeSpecificAsset, header, isBaseline: true); } } if (option.RunApiCompat) { apiCompatRunner.RunApiCompat(); } }