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); }
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); }
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); } } }
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); }
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); }
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); }
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); }
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)); }
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)); }