diff --git a/tools/Google.Cloud.Tools.VersionCompat/Assemblies.cs b/tools/Google.Cloud.Tools.VersionCompat/Assemblies.cs index 20796ab4e5316..2cb899c34c4ee 100644 --- a/tools/Google.Cloud.Tools.VersionCompat/Assemblies.cs +++ b/tools/Google.Cloud.Tools.VersionCompat/Assemblies.cs @@ -22,6 +22,7 @@ using System.IO; using System.Linq; using System.Net.Http; +using System.Reflection; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -32,21 +33,48 @@ namespace Google.Cloud.Tools.VersionCompat /// public static class Assemblies { - private static DiffResult Compare(IReadOnlyList olderTypes, IReadOnlyList newerTypes) + private static IEnumerable CompareTypes(IEnumerable olderTypes, IEnumerable newerTypes) { var oWithNested = olderTypes.WithNested().ToImmutableList(); var nWithNested = newerTypes.WithNested().ToImmutableList(); - var diffs = TopLevel.Diffs(oWithNested, nWithNested).ToImmutableList(); + return TopLevel.Diffs(oWithNested, nWithNested).ToImmutableList(); + } + + private static IEnumerable CompareDependencies(AssemblyDefinition older, AssemblyDefinition newer) + { + var olderDeps = older.MainModule.AssemblyReferences.Where(FilterDep).ToDictionary(d => d.Name, d => d.Version); + var newerDeps = newer.MainModule.AssemblyReferences.Where(FilterDep).ToDictionary(d => d.Name, d => d.Version); - return new DiffResult(diffs); + var oldOnly = olderDeps + .Where(dep => !newerDeps.ContainsKey(dep.Key)) + .OrderBy(dep => dep.Key, StringComparer.Ordinal) + .Select(pair => Diff.Minor(Cause.DependencyRemoved, $"Dependency {pair.Key} v{pair.Value} removed")); + var newOnly = newerDeps + .Where(dep => !olderDeps.ContainsKey(dep.Key)) + .OrderBy(dep => dep.Key, StringComparer.Ordinal) + .Select(pair => Diff.Minor(Cause.DependencyAdded, $"Dependency {pair.Key} v{pair.Value} added")); + var changed = olderDeps + .Join(newerDeps, pair => pair.Key, pair => pair.Key, (oldPair, newPair) => (dep: oldPair.Key, oldVersion: oldPair.Value, newVersion: newPair.Value)) + .Where(tuple => !tuple.oldVersion.Equals(tuple.newVersion)) + .OrderBy(tuple => tuple.dep, StringComparer.Ordinal) + .Select(tuple => Diff.Create( + tuple.oldVersion.Major == tuple.newVersion.Major ? Level.Minor : Level.Minor, + Cause.DependencyChanged, $"Dependency {tuple.dep} changed from v{tuple.oldVersion} to v{tuple.newVersion}")); + + return oldOnly.Concat(newOnly).Concat(changed); + + // Filtering for aspects we don't care about, such as the actual target framework. + bool FilterDep(AssemblyNameReference asmName) => asmName.Name != "netstandard"; } public static DiffResult Compare(AssemblyDefinition older, AssemblyDefinition newer, string testNamespace) { if (testNamespace == null) { - return Compare(older.Modules.SelectMany(x => x.Types).ToList(), newer.Modules.SelectMany(x => x.Types).ToList()); + var diffs = CompareTypes(GetAllTypes(older), GetAllTypes(newer)) + .Concat(CompareDependencies(older, newer)); + return new DiffResult(diffs); } else { @@ -54,12 +82,12 @@ public static DiffResult Compare(AssemblyDefinition older, AssemblyDefinition ne var newerTypesList = new List(); var nsOlder = $"{testNamespace}.A."; var nsNewer = $"{testNamespace}.B."; - foreach (var type in older.Modules.SelectMany(x => x.Types).Where(x => x.FullName.StartsWith(nsOlder))) + foreach (var type in GetAllTypes(older).Where(x => x.FullName.StartsWith(nsOlder))) { type.Namespace = type.Namespace.Replace($"{testNamespace}.A", testNamespace); olderTypesList.Add(type); } - foreach (var type in newer.Modules.SelectMany(x => x.Types).Where(x => x.FullName.StartsWith(nsNewer))) + foreach (var type in GetAllTypes(newer).Where(x => x.FullName.StartsWith(nsNewer))) { type.Namespace = type.Namespace.Replace($"{testNamespace}.B", testNamespace); newerTypesList.Add(type); @@ -68,8 +96,10 @@ public static DiffResult Compare(AssemblyDefinition older, AssemblyDefinition ne { throw new InvalidOperationException("Test data has no relevant types."); } - return Compare(olderTypesList, newerTypesList); + return new DiffResult(CompareTypes(olderTypesList, newerTypesList)); } + + IEnumerable GetAllTypes(AssemblyDefinition asm) => asm.Modules.SelectMany(x => x.Types); } /// diff --git a/tools/Google.Cloud.Tools.VersionCompat/Cause.cs b/tools/Google.Cloud.Tools.VersionCompat/Cause.cs index d49b48a1d379f..ef581fe501f31 100644 --- a/tools/Google.Cloud.Tools.VersionCompat/Cause.cs +++ b/tools/Google.Cloud.Tools.VersionCompat/Cause.cs @@ -70,6 +70,9 @@ public enum Cause ConstantMadeExported, ConstantTypeChanged, ConstantAccessModifierChanged, - ConstantValueChanged + ConstantValueChanged, + DependencyAdded, + DependencyChanged, + DependencyRemoved, } } diff --git a/tools/Google.Cloud.Tools.VersionCompat/Diff.cs b/tools/Google.Cloud.Tools.VersionCompat/Diff.cs index 73bc088abf35e..2193b2043ddf6 100644 --- a/tools/Google.Cloud.Tools.VersionCompat/Diff.cs +++ b/tools/Google.Cloud.Tools.VersionCompat/Diff.cs @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC +// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ public class Diff { public static Diff Major(Cause cause, FormattableString msg) => new Diff(Level.Major, cause, msg); public static Diff Minor(Cause cause, FormattableString msg) => new Diff(Level.Minor, cause, msg); + public static Diff Create(Level level, Cause cause, FormattableString msg) => new Diff(level, cause, msg); private Diff(Level level, Cause cause, FormattableString msg) => (Level, Cause, Msg) = (level, cause, msg); diff --git a/tools/Google.Cloud.Tools.VersionCompat/DiffResult.cs b/tools/Google.Cloud.Tools.VersionCompat/DiffResult.cs index 22f5bc7db9a3d..0d7d910dcc4cb 100644 --- a/tools/Google.Cloud.Tools.VersionCompat/DiffResult.cs +++ b/tools/Google.Cloud.Tools.VersionCompat/DiffResult.cs @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC +// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,13 +14,14 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; namespace Google.Cloud.Tools.VersionCompat { public class DiffResult { - public DiffResult(IReadOnlyList diffs) => All = diffs; + public DiffResult(IEnumerable diffs) => All = diffs.ToImmutableList(); public IReadOnlyList All { get; } public IEnumerable Major => All.Where(x => x.Level == Level.Major); public IEnumerable Minor => All.Where(x => x.Level == Level.Minor);