コード例 #1
0
        public Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            // If the package is referenced more than once (bizarrely, this happens one of our test inputs), only keep the highest version
            var packages = project.NuGetReferences
                           .PackageReferences
                           .ToLookup(p => p.Name)
                           .Where(g => g.Count() > 1);

            foreach (var duplicates in packages)
            {
                var highestVersion = duplicates.OrderByDescending(p => p.Version, _comparer).First();

                foreach (var package in duplicates.Where(p => p != highestVersion))
                {
                    _logger.LogInformation("Marking package {NuGetPackage} for removal because it is referenced elsewhere in the project with a higher version", package);
                    state.Packages.Remove(package, new OperationDetails());
                }
            }

            return(Task.CompletedTask);
        }
コード例 #2
0
        public Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            project = project.Required();
            var projectRoot = project.GetFile();

            // Check SDK directly (instead of using project.Components) since having the FrameworkReference counts as
            // having the AspNetCore component and this analyzer is specifically insterested in cases where both the SDK
            // and the framework reference are present.
            if (!projectRoot.Sdk.Contains(WebSdk))
            {
                return(Task.CompletedTask);
            }

            var aspNetCoreReference = project.FrameworkReferences?.FirstOrDefault(f => f.Name.Equals(AspNetCoreFrameworkReference, StringComparison.OrdinalIgnoreCase));

            if (aspNetCoreReference is not null)
            {
                var logMessage = "Removing framework reference Microsoft.AspNetCore.App it is already included as part of the Microsoft.NET.Sdk.Web SDK";
                _logger.LogInformation(logMessage);
                state.FrameworkReferences.Remove(aspNetCoreReference, new OperationDetails {
                    Details = new[] { logMessage }
                });
            }

            return(Task.FromResult(state));
        }
コード例 #3
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            // If the project doesn't include a reference to the analyzer package, mark it for addition
            if (!state.Packages.Any(r => AnalyzerPackageName.Equals(r.Name, StringComparison.OrdinalIgnoreCase)))
            {
                var analyzerPackage = await _packageLoader.GetLatestVersionAsync(AnalyzerPackageName, state.TargetFrameworks, new() { Prerelease = true }, token).ConfigureAwait(false);

                if (analyzerPackage is not null)
                {
                    _logger.LogInformation("Reference to .NET Upgrade Assistant analyzer package ({AnalyzerPackageName}, version {AnalyzerPackageVersion}) needs to be added", AnalyzerPackageName, analyzerPackage.Version);
                    state.Packages.Add(analyzerPackage with {
                        PrivateAssets = "all"
                    }, new OperationDetails());
                }
                else
                {
                    _logger.LogWarning(".NET Upgrade Assistant analyzer NuGet package reference cannot be added because the package cannot be found");
                }
            }
            else
            {
                _logger.LogDebug("Reference to .NET Upgrade Assistant analyzer package ({AnalyzerPackageName}) already exists", AnalyzerPackageName);
            }
        }
コード例 #4
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            if (!project.TargetFrameworks.Any(tfm => tfm.IsNetCore))
            {
                _logger.LogDebug("None of the tfms match packages from {PackageName}", SystemConfigurationPackageName);
                return;
            }

            if (!project.IsVbClassLibrary())
            {
                _logger.LogDebug("{Project} is not a VB class library", project.FileInfo);
                return;
            }

            if (await _transitiveIdentifier.IsTransitiveDependencyAsync(SystemConfigurationPackageName, project.NuGetReferences.PackageReferences, project.TargetFrameworks, token).ConfigureAwait(false))
            {
                _logger.LogDebug("{PackageName} already referenced transitively", SystemConfigurationPackageName);
                return;
            }

            if (!state.Packages.Any(r => SystemConfigurationPackageName.Equals(r.Name, StringComparison.OrdinalIgnoreCase)))
            {
                var systemConfigurationPackage = await _packageLoader.GetLatestVersionAsync(SystemConfigurationPackageName, state.TargetFrameworks, new(), token).ConfigureAwait(false);

                if (systemConfigurationPackage is not null)
                {
                    // Note: Not expecting to see this package added explicitly. This resolves the error but the package is also included in the WindowCompatabilityPack which would make this reference transitively available.
                    // 1>C:\{ProjectDir}\My Project\Settings.Designer.vb(21,18): error BC30002: Type 'Global.System.Configuration.ApplicationSettingsBase' is not defined.
                    // 1>C:\{ProjectDir}\My Project\Settings.Designer.vb(57,10): error BC30002: Type 'Global.System.Configuration.UserScopedSettingAttribute' is not defined.
                    // 1>C:\{ProjectDir}\My Project\Settings.Designer.vb(59,10): error BC30002: Type 'Global.System.Configuration.DefaultSettingValueAttribute' is not defined.
                    var logMessage = SR.Format("Reference to configuration package ({0}, version {1}) needs to be added in order to resolve compile errors from Settings.Designer.vb", SystemConfigurationPackageName, systemConfigurationPackage.Version);
                    _logger.LogInformation(logMessage);
                    state.Packages.Add(systemConfigurationPackage, new OperationDetails {
                        Details = new[] { logMessage }
                    });
                }
                else
                {
                    _logger.LogWarning($"{SystemConfigurationPackageName} NuGet package reference cannot be added because the package cannot be found");
                }
            }
            else
            {
                _logger.LogDebug("Reference to configuration package ({SystemConfigurationPackageName}) already exists", SystemConfigurationPackageName);
            }
        }
コード例 #5
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            var components = await project.GetComponentsAsync(token).ConfigureAwait(false);

            // This reference only needs added to ASP.NET Core exes
            if (!(components.HasFlag(ProjectComponents.AspNetCore) &&
                  project.OutputType == ProjectOutputType.Exe &&
                  !state.TargetFrameworks.Any(tfm => _tfmComparer.Compare(tfm, TargetFrameworkMoniker.NetCoreApp30) < 0)))
            {
                return;
            }

            if (await _transitiveIdentifier.IsTransitiveDependencyAsync(NewtonsoftPackageName, project, token).ConfigureAwait(false))
            {
                _logger.LogDebug("{PackageName} already referenced transitively", NewtonsoftPackageName);
                return;
            }

            if (!state.Packages.Any(r => NewtonsoftPackageName.Equals(r.Name, StringComparison.OrdinalIgnoreCase)))
            {
                var newtonsoftPackage = await _packageLoader.GetLatestVersionAsync(NewtonsoftPackageName, state.TargetFrameworks, new(), token).ConfigureAwait(false);

                if (newtonsoftPackage is not null)
                {
                    var logMessage = SR.Format("Reference to Newtonsoft package ({0}, version {1}) needs to be added", NewtonsoftPackageName, newtonsoftPackage.Version);
                    _logger.LogInformation(logMessage);
                    state.Packages.Add(newtonsoftPackage, new OperationDetails {
                        Risk = BuildBreakRisk.None, Details = new[] { logMessage }
                    });
                }
                else
                {
                    _logger.LogWarning("Newtonsoft NuGet package reference cannot be added because the package cannot be found");
                }
            }
            else
            {
                _logger.LogDebug("Reference to Newtonsoft package ({NewtonsoftPackageName}) already exists", NewtonsoftPackageName);
            }
        }
コード例 #6
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (!(await project.IsWinUIProjectAsync(token).ConfigureAwait(false)))
            {
                return;
            }

            if (project.AllProjectReferences().Any(id => id.Contains(".vcxproj")))
            {
                var newPackage = new NuGetReference(CsWinRTPackageName, CsWinRTVersion);
                state.Packages.Add(newPackage,
                                   new OperationDetails()
                {
                    Risk = BuildBreakRisk.Medium, Details = ImmutableList.Create <string>(newPackage.Name)
                });
            }

            foreach (var package in state.Packages)
            {
                if (package.Name.StartsWith("Microsoft.Toolkit", StringComparison.Ordinal))
                {
                    var newPackageName = package.Name == "Microsoft.Toolkit" ? "CommunityToolkit.Common"
                        : package.Name.Replace("Microsoft.Toolkit.Uwp", "CommunityToolkit.WinUI")
                                         .Replace("Microsoft.Toolkit", "CommunityToolkit");

                    var newPackage = new NuGetReference(newPackageName, package.Version);
                    if (!await _packageLoader.DoesPackageSupportTargetFrameworksAsync(newPackage, project.TargetFrameworks, token).ConfigureAwait(true))
                    {
                        newPackage = await _packageLoader.GetLatestVersionAsync(newPackage.Name, project.TargetFrameworks,
                                                                                new PackageSearchOptions { LatestMinorAndBuildOnly = false, Prerelease = false, Unlisted = false }, token).ConfigureAwait(true);

                        if (newPackage == null)
                        {
                            _logger.LogWarning($"Unable to find a supported WinUI nuget package for {package.Name}. Skipping this package.");
                            continue;
                        }
                    }

                    _logger.LogInformation($"UWP Package not supported. Replacing {package.Name} v{package.Version} with {newPackage.Name} v{newPackage.Version}");
                    state.Packages.Add(newPackage, new OperationDetails()
                    {
                        Risk = BuildBreakRisk.Medium, Details = ImmutableList.Create <string>(newPackage.Name)
                    });
                    state.Packages.Remove(package, new OperationDetails()
                    {
                        Risk = BuildBreakRisk.Medium, Details = ImmutableList.Create <string>(package.Name)
                    });
                }
            }
        }
コード例 #7
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            if (!state.TargetFrameworks.Any(tfm => tfm.IsWindows))
            {
                return;
            }

            if (await _transitiveIdentifier.IsTransitiveDependencyAsync(PackageName, project, token).ConfigureAwait(false))
            {
                _logger.LogDebug("{PackageName} already referenced transitively", PackageName);
                return;
            }

            var latestVersion = await _loader.GetLatestVersionAsync(PackageName, state.TargetFrameworks, new(), token).ConfigureAwait(false);

            if (latestVersion is null)
            {
                _logger.LogWarning("Could not find {PackageName}", latestVersion);
                return;
            }

            if (project.NuGetReferences.TryGetPackageByName(PackageName, out var existing))
            {
                if (_comparer.Compare(existing.Version, latestVersion.Version) >= 0)
                {
                    return;
                }

                state.Packages.Remove(existing, new OperationDetails());
            }

            var logMessage = SR.Format("Adding {0} {1} helps with speeding up the upgrade process for Windows-based APIs", PackageName, latestVersion.Version);

            _logger.LogInformation(logMessage);

            state.Packages.Add(new NuGetReference(PackageName, latestVersion.Version), new OperationDetails {
                Details = new[] { logMessage }
            });
        }
コード例 #8
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            foreach (var reference in state.References)
            {
                if (project.TryResolveHintPath(reference, out var path))
                {
                    _logger.LogDebug("Found hint path for {Reference} at {Path}", reference.Name, path);

                    var found = await _lookup.SearchAsync(path, project.TargetFrameworks, token).ToListAsync(token).ConfigureAwait(false);

                    if (found.Count == 0)
                    {
                        _logger.LogWarning("No match found for loose assembly {Path}", reference);
                        continue;
                    }

                    if (found.Count > 1)
                    {
                        _logger.LogWarning("Multiple matches found for {Path}", reference);
                    }

                    var first = found.FirstOrDefault();

                    if (first is not null)
                    {
                        var logMessage = SR.Format("Found package {0}: {1} for loose assembly {2}", first.Name, first.Version, reference);

                        _logger.LogDebug(logMessage);

                        state.References.Remove(reference, new OperationDetails {
                            Risk = BuildBreakRisk.Medium, Details = new[] { logMessage }
                        });
                        state.Packages.Add(first, new OperationDetails {
                            Risk = BuildBreakRisk.Medium, Details = new[] { logMessage }
                        });
                    }
                }
            }
        }
コード例 #9
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            if (!state.TargetFrameworks.Any(tfm => tfm.IsWindows))
            {
                return;
            }

            if (await project.NuGetReferences.IsTransitivelyAvailableAsync(PackageName, token).ConfigureAwait(false))
            {
                _logger.LogDebug("{PackageName} already referenced transitively", PackageName);
                return;
            }

            var latestVersion = await _loader.GetLatestVersionAsync(PackageName, state.TargetFrameworks, new(), token).ConfigureAwait(false);

            if (latestVersion is null)
            {
                _logger.LogWarning("Could not find {PackageName}", latestVersion);
                return;
            }

            if (project.NuGetReferences.TryGetPackageByName(PackageName, out var existing))
            {
                if (_comparer.Compare(existing.Version, latestVersion.Version) >= 0)
                {
                    return;
                }

                state.Packages.Remove(existing, new OperationDetails());
            }

            _logger.LogInformation("Adding {PackageName} {Version}", PackageName, latestVersion.Version);

            state.Packages.Add(new NuGetReference(PackageName, latestVersion.Version), new OperationDetails());
        }
コード例 #10
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            // Get package maps as an array here so that they're only loaded once (as opposed to each iteration through the loop)
            var packageMaps = state.TargetFrameworks.Any(c => c.IsFramework) ? _packageMaps.Where(x => x.NetCorePackagesWorkOnNetFx).ToArray() : _packageMaps;

            foreach (var packageReference in state.Packages)
            {
                foreach (var map in packageMaps.Where(m => ContainsPackageReference(m.NetFrameworkPackages, packageReference.Name, packageReference.Version)))
                {
                    _logger.LogInformation("Marking package {PackageName} for removal based on package mapping configuration {PackageMapSet}", packageReference.Name, map.PackageSetName);
                    state.Packages.Remove(packageReference, new OperationDetails()
                    {
                        Details = ProcessReferenceWarnings(map.Details), Risk = BuildBreakRisk.Medium
                    });
                    await AddNetCoreReferences(map, state, token).ConfigureAwait(false);
                }
            }

            foreach (var reference in project.References)
            {
                foreach (var map in packageMaps.Where(m => m.ContainsAssemblyReference(reference.Name)))
                {
                    _logger.LogInformation("Marking assembly reference {ReferenceName} for removal based on package mapping configuration {PackageMapSet}", reference.Name, map.PackageSetName);
                    state.References.Remove(reference, new OperationDetails()
                    {
                        Details = ProcessReferenceWarnings(map.Details), Risk = BuildBreakRisk.Medium
                    });
                    await AddNetCoreReferences(map, state, token).ConfigureAwait(false);
                }
            }
        }
コード例 #11
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            var allPackages = new HashSet <NuGetReference>(state.Packages.Concat(project.PackageReferences));
            var closure     = await _transitiveChecker.GetTransitiveDependenciesAsync(allPackages, state.TargetFrameworks, token).ConfigureAwait(false);

            var dependencyLookup = allPackages
                                   .SelectMany(p => closure.GetDependencies(p))
                                   .ToLookup(p => p.Name);

            var toRemove = state.Packages
                           .Where(p =>
            {
                // Temporary fix for packages to exclude from the removal list
                // Until we have a fix for https://github.com/dotnet/upgrade-assistant/issues/1069
                if (p.Name == "Microsoft.WindowsAppSDK")
                {
                    return(false);
                }

                // Only remove a package iff it is transitively brought in with a higher or equal version
                var versions = dependencyLookup[p.Name].Select(static d => d.Version);

                if (_comparer.TryFindBestVersion(versions, out var best))
                {
                    return(_comparer.Compare(p.Version, best) <= 0);
                }

                return(false);
            })
コード例 #12
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            // If the package is referenced transitively, mark for removal
            foreach (var packageReference in state.Packages)
            {
                if (await project.NuGetReferences.IsTransitiveDependencyAsync(packageReference, token).ConfigureAwait(false))
                {
                    state.Packages.Remove(packageReference, new OperationDetails {
                        Details = new[] { "Unnecessary transitive dependency" }
                    });
                }
            }
        }
コード例 #13
0
        public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            // Making a copy of state.Packages collection to avoid modifying a collection that is being enumerated.
            var packages = state.Packages.ToList();

            foreach (var packageReference in packages)
            {
                // If the package doesn't target the right framework but a newer version does, mark it for removal and the newer version for addition
                if (await _packageLoader.DoesPackageSupportTargetFrameworksAsync(packageReference, state.TargetFrameworks, token).ConfigureAwait(false))
                {
                    _logger.LogDebug("Package {NuGetPackage} will work on {TargetFramework}", packageReference, state.TargetFrameworks);
                    continue;
                }
                else
                {
                    // If the package won't work on the target Framework, check newer versions of the package
                    var newerVersions = await _packageLoader.GetNewerVersionsAsync(packageReference, state.TargetFrameworks, new() { LatestMinorAndBuildOnly = true }, token).ConfigureAwait(false);

                    var updatedReference = newerVersions.FirstOrDefault();
                    var details          = new List <string>();

                    if (updatedReference == null)
                    {
                        _logger.LogWarning("No version of {PackageName} found that supports {TargetFramework}; leaving unchanged", packageReference.Name, state.TargetFrameworks);
                    }
                    else
                    {
                        var logMessage = SR.Format("Package {0} does not support the target(s) {1} but a newer version ({2}) does.", packageReference, string.Join(", ", state.TargetFrameworks), updatedReference.Version);
                        _logger.LogInformation(logMessage);
                        var isMajorChange = _comparer.IsMajorChange(updatedReference.Version, packageReference.Version);

                        if (isMajorChange)
                        {
                            var logString = SR.Format("Package {0} needs to be upgraded across major versions ({1} -> {2}) which may introduce breaking changes.", packageReference.Name, packageReference.Version, updatedReference.Version);
                            details.Add($"{logMessage}  {logString}");
                            _logger.LogWarning(logString);
                        }

                        if (updatedReference.IsPrerelease)
                        {
                            var logString = SR.Format("Package {0} needs to be upgraded to a prerelease version ({1}) because no released version supports target(s) {2}", packageReference.Name, updatedReference.Version, string.Join(", ", state.TargetFrameworks));
                            details.Add($"{logMessage}  {logString}");
                            _logger.LogWarning(logString);
                        }

                        if (!isMajorChange && !updatedReference.IsPrerelease)
                        {
                            details.Add($"{logMessage}  {SR.Format("Package {0} needs to be upgraded from {1} to {2}.", packageReference.Name, packageReference.Version, updatedReference.Version)}");
                        }

                        state.Packages.Remove(packageReference, new OperationDetails()
                        {
                            Risk = BuildBreakRisk.None, Details = details
                        });
                        state.Packages.Add(updatedReference, new OperationDetails()
                        {
                            Risk = isMajorChange ? BuildBreakRisk.Medium : BuildBreakRisk.Low, Details = details
                        });
                    }
                }
            }
        }