Example #1
0
        public async Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState state, CancellationToken token)
        {
            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            var packageReferences = project.Required().PackageReferences.Where(r => !state.PackagesToRemove.Contains(r));

            if (project != null && (project.Components & ProjectComponents.Web) == ProjectComponents.Web

                // If the web project doesn't include a reference to the Newtonsoft package, mark it for addition
                && !packageReferences.Any(r => NewtonsoftPackageName.Equals(r.Name, StringComparison.OrdinalIgnoreCase)))
            {
                var analyzerPackage = await _packageLoader.GetLatestVersionAsync(NewtonsoftPackageName, false, null, token).ConfigureAwait(false);

                if (analyzerPackage is not null)
                {
                    _logger.LogInformation("Reference to Newtonsoft package ({NewtonsoftPackageName}, version {NewtonsoftPackageVersion}) needs added", NewtonsoftPackageName, analyzerPackage.Version);
                    state.PackagesToAdd.Add(analyzerPackage);
                }
                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);
            }

            return(state);
        }
Example #2
0
        public async Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState state, CancellationToken token)
        {
            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 references = await project.Required().GetNuGetReferencesAsync(token).ConfigureAwait(false);

            var packages = references.PackageReferences.ToLookup(p => p.Name);

            foreach (var duplicates in packages.Where(g => g.Count() > 1))
            {
                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.PackagesToRemove.Add(package);
                }
            }

            return(state);
        }
        public async Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState state, CancellationToken token)
        {
            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            var references = await project.Required().GetNuGetReferencesAsync(token).ConfigureAwait(false);

            var packageReferences = references.PackageReferences.Where(r => !state.PackagesToRemove.Contains(r));

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

                if (analyzerPackage is not null)
                {
                    _logger.LogInformation("Reference to .NET Upgrade Assistant analyzer package ({AnalyzerPackageName}, version {AnalyzerPackageVersion}) needs added", AnalyzerPackageName, analyzerPackage.Version);
                    state.PackagesToAdd.Add(analyzerPackage with {
                        PrivateAssets = "all"
                    });
                }
                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);
            }

            return(state);
        }
Example #4
0
        private static async Task <(IProject Project, PackageAnalysisState State)> GetMockProjectAndPackageState(AutoMock mock, string?sdk = null, IEnumerable <Reference>?frameworkReferences = null)
        {
            var projectRoot = mock.Mock <IProjectFile>();

            projectRoot.Setup(r => r.IsSdk).Returns(sdk is not null);
            if (sdk is not null)
            {
                projectRoot.Setup(r => r.Sdk).Returns(sdk);
            }
            else
            {
                projectRoot.Setup(r => r.Sdk).Throws <ArgumentOutOfRangeException>();
            }

            var project = mock.Mock <IProject>();

            project.Setup(p => p.GetFile()).Returns(projectRoot.Object);
            project.Setup(p => p.FrameworkReferences).Returns(frameworkReferences !);

            var context = mock.Mock <IUpgradeContext>();

            context.Setup(c => c.CurrentProject).Returns(project.Object);

            var restorer = mock.Mock <IPackageRestorer>();

            restorer.Setup(r => r.RestorePackagesAsync(
                               It.IsAny <IUpgradeContext>(),
                               It.IsAny <IProject>(),
                               It.IsAny <CancellationToken>())).Returns(Task.FromResult(new RestoreOutput(string.Empty, string.Empty)));

            return(project.Object, await PackageAnalysisState.CreateAsync(context.Object, restorer.Object, CancellationToken.None).ConfigureAwait(true));
        }
        public Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState 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.IsSdk || !projectRoot.Sdk.Equals(WebSdk, StringComparison.OrdinalIgnoreCase))
            {
                return(Task.FromResult(state));
            }

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

            if (aspNetCoreReference is not null)
            {
                _logger.LogInformation("Removing framework reference Microsoft.AspNetCore.App it is already included as part of the Microsoft.NET.Sdk.Web SDK");
                state.FrameworkReferencesToRemove.Add(aspNetCoreReference);
            }

            return(Task.FromResult(state));
        }
        private async Task AddNetCoreReferences(NuGetPackageMap packageMap, PackageAnalysisState state, IProject project, CancellationToken token)
        {
            var references = await project.GetNuGetReferencesAsync(token).ConfigureAwait(false);

            foreach (var newPackage in packageMap.NetCorePackages)
            {
                var packageToAdd = newPackage;
                if (packageToAdd.HasWildcardVersion)
                {
                    var reference = await _packageLoader.GetLatestVersionAsync(packageToAdd.Name, false, null, token).ConfigureAwait(false);

                    if (reference is not null)
                    {
                        packageToAdd = reference;
                    }
                }

                if (!state.PackagesToAdd.Contains(packageToAdd) && !references.PackageReferences.Contains(packageToAdd))
                {
                    _logger.LogInformation("Adding package {PackageName} based on package mapping configuration {PackageMapSet}", packageToAdd.Name, packageMap.PackageSetName);
                    state.PackagesToAdd.Add(packageToAdd);
                }
            }

            foreach (var frameworkReference in packageMap.NetCoreFrameworkReferences)
            {
                if (!state.FrameworkReferencesToAdd.Contains(frameworkReference) && !project.FrameworkReferences.Contains(frameworkReference))
                {
                    _logger.LogInformation("Adding framework reference {FrameworkReference} based on package mapping configuration {PackageMapSet}", frameworkReference.Name, packageMap.PackageSetName);
                    state.FrameworkReferencesToAdd.Add(frameworkReference);
                }
            }
        }
Example #7
0
        public async Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

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

            var references = await project.GetNuGetReferencesAsync(token).ConfigureAwait(false);

            // If the package is referenced transitively, mark for removal
            foreach (var packageReference in references.PackageReferences.Where(r => !state.PackagesToRemove.Contains(r)))
            {
                if (references.IsTransitiveDependency(packageReference))
                {
                    _logger.LogInformation("Marking package {PackageName} for removal because it appears to be a transitive dependency", packageReference.Name);
                    state.PackagesToRemove.Add(packageReference);
                    continue;
                }
            }

            return(state);
        }
Example #8
0
        public async Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

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

            var references = await project.GetNuGetReferencesAsync(token).ConfigureAwait(false);

            foreach (var packageReference in references.PackageReferences.Where(r => !state.PackagesToRemove.Contains(r)))
            {
                // 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, project.TargetFrameworks, token).ConfigureAwait(false))
                {
                    _logger.LogDebug("Package {NuGetPackage} will work on {TargetFramework}", packageReference, project.TargetFrameworks);
                    continue;
                }
                else
                {
                    // If the package won't work on the target Framework, check newer versions of the package
                    var updatedReference = await GetUpdatedPackageVersionAsync(packageReference, project.TargetFrameworks, token).ConfigureAwait(false);

                    if (updatedReference == null)
                    {
                        _logger.LogWarning("No version of {PackageName} found that supports {TargetFramework}; leaving unchanged", packageReference.Name, project.TargetFrameworks);
                    }
                    else
                    {
                        _logger.LogInformation("Marking package {NuGetPackage} for removal because it doesn't support the target framework but a newer version ({Version}) does", packageReference, updatedReference.Version);
                        var isMajorChange = _comparer.IsMajorChange(updatedReference.Version, packageReference.Version);

                        if (isMajorChange)
                        {
                            _logger.LogWarning("Package {NuGetPackage} has been upgraded across major versions ({OldVersion} -> {NewVersion}) which may introduce breaking changes", packageReference.Name, packageReference.Version, updatedReference.Version);
                            state.PossibleBreakingChangeRecommended = true;
                        }

                        if (updatedReference.IsPrerelease)
                        {
                            _logger.LogWarning("Package {NuGetPackage} has been upgraded to a prerelease version ({NewVersion}) because no released version supports target(s) {TFM}", packageReference.Name, updatedReference.Version, string.Join(", ", project.TargetFrameworks));
                        }

                        state.PackagesToRemove.Add(packageReference);
                        state.PackagesToAdd.Add(updatedReference);
                    }
                }
            }

            return(state);
        }
        public async Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState 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 &&
                  !project.TargetFrameworks.Any(tfm => _tfmComparer.Compare(tfm, TargetFrameworkMoniker.NetCoreApp30) < 0)))
            {
                return(state);
            }

            var references = await project.GetNuGetReferencesAsync(token).ConfigureAwait(false);

            if (references.IsTransitivelyAvailable(NewtonsoftPackageName))
            {
                _logger.LogDebug("{PackageName} already referenced transitively", NewtonsoftPackageName);
                return(state);
            }

            var packageReferences = references.PackageReferences.Where(r => !state.PackagesToRemove.Contains(r));

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

                if (newtonsoftPackage is not null)
                {
                    _logger.LogInformation("Reference to Newtonsoft package ({NewtonsoftPackageName}, version {NewtonsoftPackageVersion}) needs added", NewtonsoftPackageName, newtonsoftPackage.Version);
                    state.PackagesToAdd.Add(newtonsoftPackage);
                }
                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);
            }

            return(state);
        }
Example #10
0
        public async Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState 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.IsWindows))
            {
                return(state);
            }

            var references = await project.GetNuGetReferencesAsync(token).ConfigureAwait(false);

            if (references.IsTransitivelyAvailable(PackageName))
            {
                _logger.LogDebug("{PackageName} already referenced transitively", PackageName);
                return(state);
            }

            var latestVersion = await _loader.GetLatestVersionAsync(PackageName, false, null, token).ConfigureAwait(false);

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

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

                state.PackagesToRemove.Add(existing);
            }

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

            state.PackagesToAdd.Add(new NuGetReference(PackageName, latestVersion.Version));

            return(state);
        }
Example #11
0
        public async Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState state, CancellationToken token)
        {
            if (project is null)
            {
                throw new ArgumentNullException(nameof(project));
            }

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

            var currentTFM = project.TFM;

            // Get package maps as an array here so that they're only loaded once (as opposed to each iteration through the loop)
            var allPackageMaps = await _packageMapProvider.GetPackageMapsAsync(token).ToArrayAsync(token).ConfigureAwait(false);

            var packageMaps = currentTFM.IsFramework ? allPackageMaps.Where(x => x.NetCorePackagesWorkOnNetFx).ToArray <NuGetPackageMap>() : allPackageMaps;

            var packageReferences = project.PackageReferences;

            foreach (var packageReference in packageReferences.Where(r => !state.PackagesToRemove.Contains(r)))
            {
                foreach (var map in packageMaps.Where(m => m.ContainsPackageReference(packageReference.Name, packageReference.Version)))
                {
                    state.PossibleBreakingChangeRecommended = true;
                    _logger.LogInformation("Marking package {PackageName} for removal based on package mapping configuration {PackageMapSet}", packageReference.Name, map.PackageSetName);
                    state.PackagesToRemove.Add(packageReference);
                    await AddNetCoreReferences(map, state, project, token).ConfigureAwait(false);
                }
            }

            var assemblyReferences = project.References;

            foreach (var reference in assemblyReferences.Where(r => !state.ReferencesToRemove.Contains(r)))
            {
                foreach (var map in packageMaps.Where(m => m.ContainsAssemblyReference(reference.Name)))
                {
                    state.PossibleBreakingChangeRecommended = true;
                    _logger.LogInformation("Marking assembly reference {ReferenceName} for removal based on package mapping configuration {PackageMapSet}", reference.Name, map.PackageSetName);
                    state.ReferencesToRemove.Add(reference);
                    await AddNetCoreReferences(map, state, project, token).ConfigureAwait(false);
                }
            }

            return(state);
        }
Example #12
0
        public async Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState state, CancellationToken token)
        {
            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            var currentTFM = project.Required().TFM;

            foreach (var packageReference in project.Required().PackageReferences.Where(r => !state.PackagesToRemove.Contains(r)))
            {
                // 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.DoesPackageSupportTargetFrameworkAsync(packageReference, state.PackageCachePath !, currentTFM, token).ConfigureAwait(false))
                {
                    _logger.LogDebug("Package {NuGetPackage} will work on {TargetFramework}", packageReference, currentTFM);
                    continue;
                }
        public async Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState state, CancellationToken token)
        {
            if (!project.Required().TFM.IsWindows)
            {
                return(state);
            }

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

            if (project.IsTransitivelyAvailable(PackageName))
            {
                _logger.LogDebug("{PackageName} already referenced transitively", PackageName);
                return(state);
            }

            var latestVersion = await _loader.GetLatestVersionAsync(PackageName, false, null, token).ConfigureAwait(false);

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

            if (project.TryGetPackageByName(PackageName, out var existing))
            {
                var version = existing.GetNuGetVersion();

                if (version >= latestVersion.GetNuGetVersion())
                {
                    return(state);
                }

                state.PackagesToRemove.Add(existing);
            }

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

            state.PackagesToAdd.Add(new NuGetReference(PackageName, latestVersion.Version));

            return(state);
        }
        public Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState state, CancellationToken token)
        {
            if (state is null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            // If the package is referenced transitively, mark for removal
            foreach (var packageReference in project.Required().PackageReferences.Where(r => !state.PackagesToRemove.Contains(r)))
            {
                if (project.IsTransitiveDependency(packageReference))
                {
                    _logger.LogInformation("Marking package {PackageName} for removal because it appears to be a transitive dependency", packageReference.Name);
                    state.PackagesToRemove.Add(packageReference);
                    continue;
                }
            }

            return(Task.FromResult(state));
        }
Example #15
0
        public Task <PackageAnalysisState> AnalyzeAsync(IProject project, PackageAnalysisState state, CancellationToken token)
        {
            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.Required().PackageReferences.ToLookup(p => p.Name);

            foreach (var duplicates in packages.Where(g => g.Count() > 1))
            {
                var highestVersion = duplicates.Select(p => p.GetNuGetVersion()).Max();

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

            return(Task.FromResult(state));
        }