From 0c036ab7723258a494d61c7331c76bd54591c55d Mon Sep 17 00:00:00 2001 From: "Matthew Parker [SSW]" <61717342+MattParkerDev@users.noreply.github.com> Date: Tue, 21 May 2024 18:16:56 +1000 Subject: [PATCH] add package version consistency check --- .../ViewModels/MainWindowViewModel.cs | 21 +++++ .../Views/MainWindow.axaml | 11 ++- .../PackageVersionConsistency.cs | 76 +++++++++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 DotNetSolutionTools.Core/PackageVersionConsistency.cs diff --git a/DotNetSolutionTools.App/ViewModels/MainWindowViewModel.cs b/DotNetSolutionTools.App/ViewModels/MainWindowViewModel.cs index fba2e38..4f15082 100644 --- a/DotNetSolutionTools.App/ViewModels/MainWindowViewModel.cs +++ b/DotNetSolutionTools.App/ViewModels/MainWindowViewModel.cs @@ -158,6 +158,27 @@ public partial class MainWindowViewModel : ObservableObject } } + [RelayCommand] + private async Task CheckForInconsistentNugetPackageVersionsInSolutionFile(CancellationToken token) + { + SetBeginCommandState(); + try + { + await Task.Run( + () => + { + var results = PackageVersionConsistency.FindInconsistentNugetPackageVersions(SolutionFilePath); + SetCommandSuccessState($"{results.Count} packages with inconsistent versions", results); + }, + token + ); + } + catch (Exception e) + { + SetCommandFailureState("Failed to check for inconsistent package versions in solution file", e); + } + } + [RelayCommand] private async Task CheckForMissingImplicitUsingsInSolutionFile(CancellationToken token) { diff --git a/DotNetSolutionTools.App/Views/MainWindow.axaml b/DotNetSolutionTools.App/Views/MainWindow.axaml index a606c62..56bc704 100644 --- a/DotNetSolutionTools.App/Views/MainWindow.axaml +++ b/DotNetSolutionTools.App/Views/MainWindow.axaml @@ -31,7 +31,7 @@ - + + diff --git a/DotNetSolutionTools.Core/PackageVersionConsistency.cs b/DotNetSolutionTools.Core/PackageVersionConsistency.cs new file mode 100644 index 0000000..2025e8d --- /dev/null +++ b/DotNetSolutionTools.Core/PackageVersionConsistency.cs @@ -0,0 +1,76 @@ +using DotNetSolutionTools.Core.Common; +using Microsoft.Build.Construction; +using Microsoft.Build.Definition; +using Microsoft.Build.Evaluation; +using NuGet.Versioning; + +namespace DotNetSolutionTools.Core; + +public class PackageVersionConsistency +{ + public static List FindInconsistentNugetPackageVersions(string solutionFilePath) + { + var solutionFile = SolutionFile.Parse(solutionFilePath); + var csprojList = SlnHelper.GetCSharpProjectObjectsFromSolutionFile(solutionFile); + var packageList = new List<(string, NuGetVersion)>(); + var outOfSyncPackages = new List<(string packageName, NuGetVersion version)>(); + foreach (var project in csprojList) + { + var projectPackages = GetPackageVersions(project); + packageList.AddRange(projectPackages); + } + + var groupedByPackage = packageList.GroupBy(s => s.Item1).ToList(); + foreach (var package in groupedByPackage) + { + var versions = package.Select(s => s.Item2).Distinct().ToList(); + if (versions.Count > 1) + { + outOfSyncPackages.Add((package.Key, versions.First())); + } + } + + Console.WriteLine("Logging out of sync packages"); + outOfSyncPackages.ForEach(s => Console.WriteLine(s.packageName)); + + return outOfSyncPackages.Select(s => s.packageName).ToList(); + } + + private static List<(string, NuGetVersion)> GetPackageVersions(ProjectRootElement project) + { + Project? evalProject = null; + try + { + evalProject = Project.FromProjectRootElement( + project, + new ProjectOptions { LoadSettings = ProjectLoadSettings.IgnoreMissingImports } + ); + var packages = evalProject + .Items.Where(x => x.ItemType == "PackageReference" && x.HasMetadata("Version")) + .ToList(); + + var packageNameAndVersion = packages + .Select(x => + ( + x.EvaluatedInclude, + NuGetVersion.Parse(x.Metadata.First(s => s.Name == "Version").UnevaluatedValue) + ) + ) + .ToList(); + return packageNameAndVersion; + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + finally + { + if (evalProject is not null) + { + ProjectCollection.GlobalProjectCollection.UnloadProject(evalProject); + ProjectCollection.GlobalProjectCollection.TryUnloadProject(project); + } + } + } +}