public static int Compare(AssemblyReflectionInput assembly1Input, AssemblyReflectionInput assembly2Input, string outputApiPath = null, SemverChangeType?expectedChangeType = null, bool useDependencyChanges = false) { return(CompareAction(assembly1Input, assembly2Input, (assembly1, assembly2) => { var assembly1Semver = GetSemanticVersion(assembly1); var assembly2Semver = GetSemanticVersion(assembly2); var compareResult = ComparePublicApi(assembly1, assembly2); var dependencyCompareResult = CompareDependencies(assembly1, assembly2); if (useDependencyChanges && dependencyCompareResult > compareResult) { compareResult = dependencyCompareResult; } if (!string.IsNullOrWhiteSpace(outputApiPath) && Directory.Exists(outputApiPath)) { var path1 = GetSafeApiFileName(outputApiPath, assembly1.GetName().Name, assembly1Semver, ".api.txt"); var path2 = GetSafeApiFileName(outputApiPath, assembly2.GetName().Name, assembly2Semver, ".api.txt"); if (path2.Equals(path1, StringComparison.OrdinalIgnoreCase)) { path1 = Path.Join(Path.GetDirectoryName(path1), Path.GetFileNameWithoutExtension(path1), "(1)", Path.GetExtension(path1)); path2 = Path.Join(Path.GetDirectoryName(path2), Path.GetFileNameWithoutExtension(path2), "(2)", Path.GetExtension(path2)); } WriteApiToFile(assembly1, path1); WriteApiToFile(assembly2, path2); } var calculatedSemver = CalculateSemver(assembly1Semver, compareResult); if (expectedChangeType.HasValue) { if (expectedChangeType >= compareResult || assembly1Semver.IsPrerelease) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(); Console.WriteLine($"Valid [{expectedChangeType}] semver change for {assembly1.GetName().Name} {assembly1Semver.ToShortVerion()} => {assembly2.GetName().Name} {assembly2Semver.ToShortVerion()}. Calculated as [{compareResult}] ({calculatedSemver})"); Console.ResetColor(); return 0; } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(); Console.WriteLine($"Changes for {assembly1.GetName().Name} {assembly1Semver.ToShortVerion()} => {assembly2.GetName().Name} {assembly2Semver.ToShortVerion()} do not meet semver guidelines for a [{expectedChangeType}] change. Calculated as [{compareResult}] ({calculatedSemver})"); Console.ResetColor(); return 1; } } else { Console.WriteLine(); Console.WriteLine($"The calculated semver for {assembly1.GetName().Name} {assembly1Semver.ToShortVerion()} => {assembly2.GetName().Name} {assembly2Semver.ToShortVerion()} is [{compareResult}] ({calculatedSemver})"); return 0; } })); }
private static int CompareAction(AssemblyReflectionInput assembly1Input, AssemblyReflectionInput assembly2Input, Func <Assembly, Assembly, int> compareFunc) { var assembly1Paths = new[] { assembly1Input.AssemblyPath }.Concat(assembly1Input.AssemblyDependencies).Distinct(); var assembly2Paths = new[] { assembly2Input.AssemblyPath }.Concat(assembly2Input.AssemblyDependencies).Distinct(); using var loadContext1 = new MetadataLoadContext(new PathAssemblyResolver(assembly1Paths)); using var loadContext2 = new MetadataLoadContext(new PathAssemblyResolver(assembly2Paths)); var assembly1 = loadContext1.LoadFromAssemblyPath(assembly1Input.AssemblyPath); var assembly2 = loadContext2.LoadFromAssemblyPath(assembly2Input.AssemblyPath); return(compareFunc(assembly1, assembly2)); }
public static int WritePublicApi(AssemblyReflectionInput input, string outputApiPath) { var assembly1Paths = new[] { input.AssemblyPath }.Concat(input.AssemblyDependencies).Distinct(); using (var loadContext1 = new MetadataLoadContext(new PathAssemblyResolver(assembly1Paths))) { var assembly1 = loadContext1.LoadFromAssemblyPath(input.AssemblyPath); var assembly1Semver = GetSemanticVersion(assembly1); WriteApiToFile(assembly1, GetSafeApiFileName(outputApiPath, input.AssemblyPath, assembly1Semver, ".api.txt")); WriteSignaturesToFile(assembly1, GetSafeApiFileName(outputApiPath, input.AssemblyPath, assembly1Semver, ".signatures.txt")); } return(0); }