/// <summary> /// Log upgrade warnings from the graphs. /// </summary> public static IEnumerable <RestoreLogMessage> GetDependenciesAboveUpperBounds(List <IndexedRestoreTargetGraph> graphs, ILogger logger) { var messages = new List <RestoreLogMessage>(); foreach (var indexedGraph in graphs) { var graph = indexedGraph.Graph; foreach (var node in graph.Flattened) { var dependencies = node.Data?.Dependencies ?? Enumerable.Empty <LibraryDependency>(); foreach (var dependency in dependencies) { // Check if the dependency has an upper bound var dependencyRange = dependency.LibraryRange.VersionRange; var upperBound = dependencyRange?.MaxVersion; if (upperBound != null) { var dependencyId = dependency.Name; // If the version does not exist then it was not resolved or is a project and should be skipped. var match = indexedGraph.GetItemById(dependencyId, LibraryType.Package); if (match != null) { var actualVersion = match.Key.Version; // If the upper bound is included then require that the version be higher than the upper bound to fail // If the upper bound is not included, then an exact match on the upperbound is a failure var compare = dependencyRange.IsMaxInclusive ? 1 : 0; if (VersionComparer.VersionRelease.Compare(actualVersion, upperBound) >= compare) { // True if the package already has an NU1107 error, NU1608 would be redundant here. if (!indexedGraph.HasErrors(dependencyId)) { var parent = DiagnosticUtility.FormatIdentity(node.Key); var child = DiagnosticUtility.FormatDependency(dependencyId, dependencyRange); var actual = DiagnosticUtility.FormatIdentity(match.Key); var message = string.Format(CultureInfo.CurrentCulture, Strings.Warning_VersionAboveUpperBound, parent, child, actual); messages.Add(RestoreLogMessage.CreateWarning(NuGetLogCode.NU1608, message, dependencyId, graph.TargetGraphName)); } } } } } } } // Merge log messages return(DiagnosticUtility.MergeOnTargetGraph(messages)); }
/// <summary> /// Log downgrade warnings from the graphs. /// </summary> private static Task LogDowngradeWarningsAsync(IEnumerable <RestoreTargetGraph> graphs, ILogger logger) { var messages = new List <RestoreLogMessage>(); foreach (var graph in graphs) { if (graph.AnalyzeResult.Downgrades.Count > 0) { // Find all dependencies in the flattened graph that are not packages. var ignoreIds = new HashSet <string>( graph.Flattened.Where(e => e.Key.Type != LibraryType.Package) .Select(e => e.Key.Name), StringComparer.OrdinalIgnoreCase); foreach (var downgrade in graph.AnalyzeResult.Downgrades) { var downgraded = downgrade.DowngradedFrom; var downgradedBy = downgrade.DowngradedTo; // Filter out non-package dependencies if (!ignoreIds.Contains(downgraded.Key.Name)) { // Not all dependencies have a min version, if one does not exist use 0.0.0 var fromVersion = downgraded.GetVersionRange().MinVersion ?? new NuGetVersion(0, 0, 0); // Use the actual version resolved if it exists var toVersion = downgradedBy.GetVersionOrDefault() ?? downgradedBy.GetVersionRange().MinVersion ?? new NuGetVersion(0, 0, 0); var message = string.Format( CultureInfo.CurrentCulture, Strings.Log_DowngradeWarning, downgraded.Key.Name, fromVersion, toVersion) + $" {Environment.NewLine} {downgraded.GetPathWithLastRange()} {Environment.NewLine} {downgradedBy.GetPathWithLastRange()}"; messages.Add(RestoreLogMessage.CreateWarning(NuGetLogCode.NU1605, message, downgraded.Key.Name, graph.TargetGraphName)); } } } } // Merge and log messages var mergedMessages = DiagnosticUtility.MergeOnTargetGraph(messages); return(logger.LogMessagesAsync(mergedMessages)); }
/// <summary> /// Log errors for missing dependencies. /// </summary> internal static async Task LogAsync(IEnumerable <IRestoreTargetGraph> graphs, RemoteWalkContext context, CancellationToken token) { var tasks = graphs.SelectMany(graph => graph.Unresolved.Select(e => GetMessageAsync( graph.TargetGraphName, e, context.FilterDependencyProvidersForLibrary(e), context.PackageSourceMapping.IsEnabled, context.RemoteLibraryProviders, context.CacheContext, context.Logger, token))).ToArray(); var messages = await Task.WhenAll(tasks); await context.Logger.LogMessagesAsync(DiagnosticUtility.MergeOnTargetGraph(messages)); }
/// <summary> /// Log warnings for all project issues related to unexpected dependencies. /// </summary> public static async Task LogAsync(IEnumerable <IRestoreTargetGraph> graphs, PackageSpec project, ILogger logger) { var ignoreIds = new HashSet <string>(StringComparer.OrdinalIgnoreCase); var graphList = graphs.AsList(); // Index the flattened graph for faster lookups. var indexedGraphs = graphList.Select(IndexedRestoreTargetGraph.Create).ToList(); // 1. Detect project dependency authoring issues in the current project. // The user can fix these themselves. var projectMissingVersions = GetProjectDependenciesMissingVersion(project); ignoreIds.UnionWith(projectMissingVersions.Select(e => e.LibraryId)); await logger.LogMessagesAsync(DiagnosticUtility.MergeOnTargetGraph(projectMissingVersions)); var projectMissingLowerBounds = GetProjectDependenciesMissingLowerBounds(project); ignoreIds.UnionWith(projectMissingLowerBounds.Select(e => e.LibraryId)); await logger.LogMessagesAsync(DiagnosticUtility.MergeOnTargetGraph(projectMissingLowerBounds)); // Ignore generating NU1603/NU1602 across entire graph if lock file is enabled. Because // lock file enforce a fixed resolved version for all the different requests for the same package ID. if (!PackagesLockFileUtilities.IsNuGetLockFileEnabled(project)) { // 2. Detect dependency and source issues across the entire graph // where the minimum version was not matched exactly. // Ignore packages already logged by #1 var missingMinimums = GetMissingLowerBounds(graphList, ignoreIds); ignoreIds.UnionWith(missingMinimums.Select(e => e.LibraryId)); await logger.LogMessagesAsync(DiagnosticUtility.MergeOnTargetGraph(missingMinimums)); } // 3. Detect top level dependencies that have a version different from the specified version. // Ignore packages already logged in #1 and #2 since those errors are more specific. var bumpedUp = GetBumpedUpDependencies(indexedGraphs, project, ignoreIds); await logger.LogMessagesAsync(DiagnosticUtility.MergeOnTargetGraph(bumpedUp)); // 4. Detect dependencies that are higher than the upper bound of a version range. var aboveUpperBounds = GetDependenciesAboveUpperBounds(indexedGraphs, logger); await logger.LogMessagesAsync(aboveUpperBounds); }
public static async Task LogAsync(IList <DownloadDependencyResolutionResult> downloadDependencyResults, IList <IRemoteDependencyProvider> remoteLibraryProviders, SourceCacheContext sourceCacheContext, ILogger logger, CancellationToken token) { var messageTasks = new List <Task <RestoreLogMessage> >(); foreach (var ddi in downloadDependencyResults) { foreach (var unresolved in ddi.Unresolved) { messageTasks.Add(GetMessageAsync( ddi.Framework.ToString(), unresolved, remoteLibraryProviders, sourceCacheContext, logger, token)); } } var messages = await Task.WhenAll(messageTasks); await logger.LogMessagesAsync(DiagnosticUtility.MergeOnTargetGraph(messages)); }
internal static async Task LogAsync(IList <DownloadDependencyResolutionResult> downloadDependencyResults, RemoteWalkContext context, CancellationToken token) { var messageTasks = new List <Task <RestoreLogMessage> >(); foreach (var ddi in downloadDependencyResults) { foreach (var unresolved in ddi.Unresolved) { messageTasks.Add(GetMessageAsync( ddi.Framework.ToString(), unresolved, context.FilterDependencyProvidersForLibrary(unresolved), context.CacheContext, context.Logger, token)); } } var messages = await Task.WhenAll(messageTasks); await context.Logger.LogMessagesAsync(DiagnosticUtility.MergeOnTargetGraph(messages)); }