Change Output format to match PR feedback
Don't use Environment.Exit() PR Feedback, Unecessary Usings and Immutable types
This commit is contained in:
parent
dd5c0bb423
commit
3b848c0487
9 changed files with 169 additions and 56 deletions
|
@ -120,8 +120,8 @@ header "Testing stage2 End to End ..."
|
||||||
DOTNET_HOME=$STAGE2_DIR DOTNET_TOOLS=$STAGE2_DIR $DIR/test/e2e-test.sh
|
DOTNET_HOME=$STAGE2_DIR DOTNET_TOOLS=$STAGE2_DIR $DIR/test/e2e-test.sh
|
||||||
|
|
||||||
# Run Validation for Project.json dependencies
|
# 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
|
#TODO for release builds this should fail
|
||||||
set +e
|
set +e
|
||||||
"$OUTPUT_DIR/tools/pjvalidate" "$REPOROOT/src"
|
"$STAGE2_DIR/../tools/pjvalidate" "$REPOROOT/src"
|
||||||
set -e
|
set -e
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MultiProjectValidator
|
namespace MultiProjectValidator
|
||||||
{
|
{
|
||||||
|
|
|
@ -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<string, List<DependencyInfo>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
dependencyGroup.AddEntry(dependencyInfo);
|
||||||
|
|
||||||
|
return dependencyGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DependencyName { get; private set; }
|
||||||
|
public Dictionary<string, List<DependencyInfo>> 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>()
|
||||||
|
{
|
||||||
|
dependencyInfo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.DotNet.ProjectModel;
|
using Microsoft.DotNet.ProjectModel;
|
||||||
|
using System.Text;
|
||||||
|
using ProjectSanity.AnalysisRules.DependencyMismatch;
|
||||||
|
|
||||||
namespace MultiProjectValidator.AnalysisRules
|
namespace MultiProjectValidator.AnalysisRules
|
||||||
{
|
{
|
||||||
|
@ -12,62 +13,73 @@ namespace MultiProjectValidator.AnalysisRules
|
||||||
{
|
{
|
||||||
var targetGroupedContexts = GroupContextsByTarget(projectContexts);
|
var targetGroupedContexts = GroupContextsByTarget(projectContexts);
|
||||||
|
|
||||||
var failureMessages = EvaluateTargetContextGroups(targetGroupedContexts);
|
var failureMessages = EvaluateProjectContextTargetGroups(targetGroupedContexts);
|
||||||
var pass = failureMessages.Count == 0;
|
var pass = failureMessages.Count == 0;
|
||||||
|
|
||||||
var result = new AnalysisResult(failureMessages, pass);
|
var result = new AnalysisResult(failureMessages, pass);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> EvaluateTargetContextGroups(Dictionary<string, List<ProjectContext>> targetGroupedContexts)
|
private List<string> EvaluateProjectContextTargetGroups(Dictionary<string, List<ProjectContext>> targetGroupedProjectContexts)
|
||||||
{
|
{
|
||||||
var failureMessages = new List<string>();
|
var failureMessages = new List<string>();
|
||||||
|
|
||||||
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;
|
return failureMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> EvaluateTargetContextGroup(List<ProjectContext> targetContexts)
|
private List<string> EvaluateProjectContextTargetGroup(List<ProjectContext> targetProjectContextGroup)
|
||||||
{
|
{
|
||||||
var failedMessages = new List<string>();
|
var failedMessages = new List<string>();
|
||||||
var assemblyVersionMap = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
foreach(var context in targetContexts)
|
var dependencyGroups = CreateDependencyGroups(targetProjectContextGroup);
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var dependencyGroup in dependencyGroups)
|
||||||
{
|
{
|
||||||
var libraries = context.LibraryManager.GetLibraries();
|
if(dependencyGroup.HasConflict)
|
||||||
|
|
||||||
foreach(var library in libraries)
|
|
||||||
{
|
{
|
||||||
var name = library.Identity.Name;
|
failedMessages.Add(GetDependencyGroupConflictMessage(dependencyGroup));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return failedMessages;
|
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<string, List<ProjectContext>> GroupContextsByTarget(List<ProjectContext> projectContexts)
|
private Dictionary<string, List<ProjectContext>> GroupContextsByTarget(List<ProjectContext> projectContexts)
|
||||||
{
|
{
|
||||||
var targetContextMap = new Dictionary<string, List<ProjectContext>>();
|
var targetContextMap = new Dictionary<string, List<ProjectContext>>();
|
||||||
|
@ -90,5 +102,39 @@ namespace MultiProjectValidator.AnalysisRules
|
||||||
|
|
||||||
return targetContextMap;
|
return targetContextMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<DependencyGroup> CreateDependencyGroups(List<ProjectContext> projectContexts)
|
||||||
|
{
|
||||||
|
var libraryNameDependencyGroupMap = new Dictionary<string, DependencyGroup>();
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.DotNet.ProjectModel;
|
using Microsoft.DotNet.ProjectModel;
|
||||||
|
|
||||||
namespace MultiProjectValidator
|
namespace MultiProjectValidator
|
||||||
|
|
|
@ -10,7 +10,17 @@ namespace MultiProjectValidator
|
||||||
{
|
{
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
var rootPath = ParseAndValidateArgs(args);
|
|
||||||
|
string rootPath = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
rootPath = ParseAndValidateArgs(args);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
List<ProjectContext> projects = null;
|
List<ProjectContext> projects = null;
|
||||||
try
|
try
|
||||||
|
@ -20,7 +30,7 @@ namespace MultiProjectValidator
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Failed to load projects from path: " + rootPath);
|
Console.WriteLine("Failed to load projects from path: " + rootPath);
|
||||||
Exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var analyzer = ProjectAnalyzer.Create(projects);
|
var analyzer = ProjectAnalyzer.Create(projects);
|
||||||
|
@ -80,7 +90,7 @@ namespace MultiProjectValidator
|
||||||
if (args.Length != 1)
|
if (args.Length != 1)
|
||||||
{
|
{
|
||||||
PrintHelp();
|
PrintHelp();
|
||||||
Exit(1);
|
throw new Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
string rootPath = args[0];
|
string rootPath = args[0];
|
||||||
|
@ -88,17 +98,12 @@ namespace MultiProjectValidator
|
||||||
if (!Directory.Exists(rootPath))
|
if (!Directory.Exists(rootPath))
|
||||||
{
|
{
|
||||||
Console.WriteLine("Root Directory does not exist: " + rootPath);
|
Console.WriteLine("Root Directory does not exist: " + rootPath);
|
||||||
Exit(1);
|
throw new Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
return rootPath;
|
return rootPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Exit(int code)
|
|
||||||
{
|
|
||||||
Environment.Exit(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void PrintHelp()
|
private static void PrintHelp()
|
||||||
{
|
{
|
||||||
var help = @"
|
var help = @"
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.DotNet.ProjectModel;
|
using Microsoft.DotNet.ProjectModel;
|
||||||
using MultiProjectValidator.AnalysisRules;
|
using MultiProjectValidator.AnalysisRules;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
using System;
|
using System.IO;
|
||||||
using System.IO;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.DotNet.ProjectModel;
|
using Microsoft.DotNet.ProjectModel;
|
||||||
|
|
||||||
namespace MultiProjectValidator
|
namespace MultiProjectValidator
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue