From 3b848c0487bf439f602f3ed2a20d663e0bfbc91b Mon Sep 17 00:00:00 2001 From: Bryan Date: Tue, 15 Dec 2015 18:09:08 -0800 Subject: [PATCH] Change Output format to match PR feedback Don't use Environment.Exit() PR Feedback, Unecessary Usings and Immutable types --- scripts/compile.sh | 4 +- tools/MultiProjectValidator/AnalysisResult.cs | 3 - .../DependencyMismatch/DependencyGroup.cs | 53 +++++++++ .../DependencyMismatch/DependencyInfo.cs | 21 ++++ .../AnalysisRules/DependencyMismatchRule.cs | 106 +++++++++++++----- tools/MultiProjectValidator/IAnalysisRule.cs | 5 +- tools/MultiProjectValidator/Program.cs | 23 ++-- .../MultiProjectValidator/ProjectAnalyzer.cs | 5 +- tools/MultiProjectValidator/ProjectLoader.cs | 5 +- 9 files changed, 169 insertions(+), 56 deletions(-) create mode 100644 tools/MultiProjectValidator/AnalysisRules/DependencyMismatch/DependencyGroup.cs create mode 100644 tools/MultiProjectValidator/AnalysisRules/DependencyMismatch/DependencyInfo.cs diff --git a/scripts/compile.sh b/scripts/compile.sh index 70ad33031..5105123c1 100755 --- a/scripts/compile.sh +++ b/scripts/compile.sh @@ -120,8 +120,8 @@ header "Testing stage2 End to End ..." DOTNET_HOME=$STAGE2_DIR DOTNET_TOOLS=$STAGE2_DIR $DIR/test/e2e-test.sh # Run Validation for Project.json dependencies -dotnet publish "$REPOROOT/tools/MultiProjectValidator" -o "$OUTPUT_DIR/../tools" +dotnet publish "$REPOROOT/tools/MultiProjectValidator" -o "$STAGE2_DIR/../tools" #TODO for release builds this should fail set +e -"$OUTPUT_DIR/tools/pjvalidate" "$REPOROOT/src" +"$STAGE2_DIR/../tools/pjvalidate" "$REPOROOT/src" set -e diff --git a/tools/MultiProjectValidator/AnalysisResult.cs b/tools/MultiProjectValidator/AnalysisResult.cs index eee0ecc14..52c8b3336 100644 --- a/tools/MultiProjectValidator/AnalysisResult.cs +++ b/tools/MultiProjectValidator/AnalysisResult.cs @@ -1,7 +1,4 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace MultiProjectValidator { diff --git a/tools/MultiProjectValidator/AnalysisRules/DependencyMismatch/DependencyGroup.cs b/tools/MultiProjectValidator/AnalysisRules/DependencyMismatch/DependencyGroup.cs new file mode 100644 index 000000000..59a51096e --- /dev/null +++ b/tools/MultiProjectValidator/AnalysisRules/DependencyMismatch/DependencyGroup.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; + +namespace ProjectSanity.AnalysisRules.DependencyMismatch +{ + internal class DependencyGroup + { + public static DependencyGroup CreateWithEntry(DependencyInfo dependencyInfo) + { + var dependencyGroup = new DependencyGroup + { + DependencyName = dependencyInfo.Name, + VersionDependencyInfoMap = new Dictionary>() + }; + + dependencyGroup.AddEntry(dependencyInfo); + + return dependencyGroup; + } + + public string DependencyName { get; private set; } + public Dictionary> VersionDependencyInfoMap { get; private set; } + + public bool HasConflict + { + get + { + return VersionDependencyInfoMap.Count > 1; + } + } + + public void AddEntry(DependencyInfo dependencyInfo) + { + if (!dependencyInfo.Name.Equals(DependencyName, StringComparison.OrdinalIgnoreCase)) + { + throw new Exception("Added dependency does not match group"); + } + + if (VersionDependencyInfoMap.ContainsKey(dependencyInfo.Version)) + { + VersionDependencyInfoMap[dependencyInfo.Version].Add(dependencyInfo); + } + else + { + VersionDependencyInfoMap[dependencyInfo.Version] = new List() + { + dependencyInfo + }; + } + } + + } +} diff --git a/tools/MultiProjectValidator/AnalysisRules/DependencyMismatch/DependencyInfo.cs b/tools/MultiProjectValidator/AnalysisRules/DependencyMismatch/DependencyInfo.cs new file mode 100644 index 000000000..b91e3298c --- /dev/null +++ b/tools/MultiProjectValidator/AnalysisRules/DependencyMismatch/DependencyInfo.cs @@ -0,0 +1,21 @@ +using Microsoft.DotNet.ProjectModel; + +namespace ProjectSanity.AnalysisRules.DependencyMismatch +{ + internal class DependencyInfo + { + public static DependencyInfo Create(ProjectContext context, LibraryDescription library) + { + return new DependencyInfo + { + ProjectPath = context.ProjectFile.ProjectFilePath, + Version = library.Identity.Version.ToString(), + Name = library.Identity.Name + }; + } + + public string ProjectPath { get; private set; } + public string Version { get; private set; } + public string Name { get; private set; } + } +} diff --git a/tools/MultiProjectValidator/AnalysisRules/DependencyMismatchRule.cs b/tools/MultiProjectValidator/AnalysisRules/DependencyMismatchRule.cs index 865190550..67fab1014 100644 --- a/tools/MultiProjectValidator/AnalysisRules/DependencyMismatchRule.cs +++ b/tools/MultiProjectValidator/AnalysisRules/DependencyMismatchRule.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using Microsoft.DotNet.ProjectModel; +using System.Text; +using ProjectSanity.AnalysisRules.DependencyMismatch; namespace MultiProjectValidator.AnalysisRules { @@ -12,62 +13,73 @@ namespace MultiProjectValidator.AnalysisRules { var targetGroupedContexts = GroupContextsByTarget(projectContexts); - var failureMessages = EvaluateTargetContextGroups(targetGroupedContexts); + var failureMessages = EvaluateProjectContextTargetGroups(targetGroupedContexts); var pass = failureMessages.Count == 0; var result = new AnalysisResult(failureMessages, pass); return result; } - private List EvaluateTargetContextGroups(Dictionary> targetGroupedContexts) + private List EvaluateProjectContextTargetGroups(Dictionary> targetGroupedProjectContexts) { var failureMessages = new List(); - foreach (var target in targetGroupedContexts.Keys) + foreach (var target in targetGroupedProjectContexts.Keys) { - var targetContexts = targetGroupedContexts[target]; + var targetProjectContextGroup = targetGroupedProjectContexts[target]; - failureMessages.AddRange(EvaluateTargetContextGroup(targetContexts)); + var groupFailureMessages = EvaluateProjectContextTargetGroup(targetProjectContextGroup); + + if (groupFailureMessages.Count > 0) + { + string aggregateFailureMessage = $"Failures for Target {target} {Environment.NewLine}{Environment.NewLine}" + + string.Join("", groupFailureMessages); + + failureMessages.Add(aggregateFailureMessage); + } } return failureMessages; } - private List EvaluateTargetContextGroup(List targetContexts) + private List EvaluateProjectContextTargetGroup(List targetProjectContextGroup) { var failedMessages = new List(); - var assemblyVersionMap = new Dictionary(); - foreach(var context in targetContexts) + var dependencyGroups = CreateDependencyGroups(targetProjectContextGroup); + + + foreach (var dependencyGroup in dependencyGroups) { - var libraries = context.LibraryManager.GetLibraries(); - - foreach(var library in libraries) + if(dependencyGroup.HasConflict) { - var name = library.Identity.Name; - var version = library.Identity.Version.ToString(); - - if (assemblyVersionMap.ContainsKey(name)) - { - var existingVersion = assemblyVersionMap[name]; - if (!string.Equals(existingVersion, version, StringComparison.OrdinalIgnoreCase)) - { - string message = - $"Dependency mismatch in {context.ProjectFile.ProjectFilePath} for dependency {name}. Versions {version}, {existingVersion}"; - - failedMessages.Add(message); - } - } - else - { - assemblyVersionMap[name] = version; - } + failedMessages.Add(GetDependencyGroupConflictMessage(dependencyGroup)); } } return failedMessages; } + private string GetDependencyGroupConflictMessage(DependencyGroup dependencyGroup) + { + StringBuilder sb = new StringBuilder(); + + sb.Append($"Conflict for {dependencyGroup.DependencyName} in projects:{Environment.NewLine}"); + + foreach (var version in dependencyGroup.VersionDependencyInfoMap.Keys) + { + var dependencyInfoList = dependencyGroup.VersionDependencyInfoMap[version]; + + foreach (var dependencyInfo in dependencyInfoList) + { + sb.Append($"Version: {dependencyInfo.Version} Path: {dependencyInfo.ProjectPath} {Environment.NewLine}"); + } + } + sb.Append(Environment.NewLine); + + return sb.ToString(); + } + private Dictionary> GroupContextsByTarget(List projectContexts) { var targetContextMap = new Dictionary>(); @@ -90,5 +102,39 @@ namespace MultiProjectValidator.AnalysisRules return targetContextMap; } + + private List CreateDependencyGroups(List projectContexts) + { + var libraryNameDependencyGroupMap = new Dictionary(); + + foreach (var projectContext in projectContexts) + { + var libraries = projectContext.LibraryManager.GetLibraries(); + + foreach (var library in libraries) + { + var dependencyInfo = DependencyInfo.Create(projectContext, library); + + if (libraryNameDependencyGroupMap.ContainsKey(dependencyInfo.Name)) + { + var dependencyGroup = libraryNameDependencyGroupMap[dependencyInfo.Name]; + + dependencyGroup.AddEntry(dependencyInfo); + } + else + { + var dependencyGroup = DependencyGroup.CreateWithEntry(dependencyInfo); + + libraryNameDependencyGroupMap[dependencyInfo.Name] = dependencyGroup; + } + } + } + + return libraryNameDependencyGroupMap.Values.ToList(); + } + + + + } } diff --git a/tools/MultiProjectValidator/IAnalysisRule.cs b/tools/MultiProjectValidator/IAnalysisRule.cs index 566d01ca1..7130bca79 100644 --- a/tools/MultiProjectValidator/IAnalysisRule.cs +++ b/tools/MultiProjectValidator/IAnalysisRule.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; using Microsoft.DotNet.ProjectModel; namespace MultiProjectValidator diff --git a/tools/MultiProjectValidator/Program.cs b/tools/MultiProjectValidator/Program.cs index f5e90b645..776a07657 100644 --- a/tools/MultiProjectValidator/Program.cs +++ b/tools/MultiProjectValidator/Program.cs @@ -10,7 +10,17 @@ namespace MultiProjectValidator { public static int Main(string[] args) { - var rootPath = ParseAndValidateArgs(args); + + string rootPath = null; + + try + { + rootPath = ParseAndValidateArgs(args); + } + catch + { + return 1; + } List projects = null; try @@ -20,7 +30,7 @@ namespace MultiProjectValidator catch(Exception e) { Console.WriteLine("Failed to load projects from path: " + rootPath); - Exit(1); + return 1; } var analyzer = ProjectAnalyzer.Create(projects); @@ -80,7 +90,7 @@ namespace MultiProjectValidator if (args.Length != 1) { PrintHelp(); - Exit(1); + throw new Exception(); } string rootPath = args[0]; @@ -88,16 +98,11 @@ namespace MultiProjectValidator if (!Directory.Exists(rootPath)) { Console.WriteLine("Root Directory does not exist: " + rootPath); - Exit(1); + throw new Exception(); } return rootPath; } - - private static void Exit(int code) - { - Environment.Exit(code); - } private static void PrintHelp() { diff --git a/tools/MultiProjectValidator/ProjectAnalyzer.cs b/tools/MultiProjectValidator/ProjectAnalyzer.cs index c0517bbfb..8ea50e5a6 100644 --- a/tools/MultiProjectValidator/ProjectAnalyzer.cs +++ b/tools/MultiProjectValidator/ProjectAnalyzer.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; using Microsoft.DotNet.ProjectModel; using MultiProjectValidator.AnalysisRules; diff --git a/tools/MultiProjectValidator/ProjectLoader.cs b/tools/MultiProjectValidator/ProjectLoader.cs index b4f214ed0..e0088568b 100644 --- a/tools/MultiProjectValidator/ProjectLoader.cs +++ b/tools/MultiProjectValidator/ProjectLoader.cs @@ -1,8 +1,5 @@ -using System; -using System.IO; +using System.IO; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.DotNet.ProjectModel; namespace MultiProjectValidator