Skip to content

Commit

Permalink
tools: Report dependency changes in the diff
Browse files Browse the repository at this point in the history
This is assembly-based rather than NuGet based, but 99% of the time they're the same thing - and this is much easier than relying on having NuGet dependencies.
  • Loading branch information
jskeet committed Jan 14, 2025
1 parent bb1c6e6 commit 550148d
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 11 deletions.
44 changes: 37 additions & 7 deletions tools/Google.Cloud.Tools.VersionCompat/Assemblies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -32,34 +33,61 @@ namespace Google.Cloud.Tools.VersionCompat
/// </summary>
public static class Assemblies
{
private static DiffResult Compare(IReadOnlyList<TypeDefinition> olderTypes, IReadOnlyList<TypeDefinition> newerTypes)
private static IEnumerable<Diff> CompareTypes(IEnumerable<TypeDefinition> olderTypes, IEnumerable<TypeDefinition> 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<Diff> 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
{
var olderTypesList = new List<TypeDefinition>();
var newerTypesList = new List<TypeDefinition>();
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);
Expand All @@ -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<TypeDefinition> GetAllTypes(AssemblyDefinition asm) => asm.Modules.SelectMany(x => x.Types);
}

/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion tools/Google.Cloud.Tools.VersionCompat/Cause.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ public enum Cause
ConstantMadeExported,
ConstantTypeChanged,
ConstantAccessModifierChanged,
ConstantValueChanged
ConstantValueChanged,
DependencyAdded,
DependencyChanged,
DependencyRemoved,
}
}
3 changes: 2 additions & 1 deletion tools/Google.Cloud.Tools.VersionCompat/Diff.cs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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);

Expand Down
5 changes: 3 additions & 2 deletions tools/Google.Cloud.Tools.VersionCompat/DiffResult.cs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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<Diff> diffs) => All = diffs;
public DiffResult(IEnumerable<Diff> diffs) => All = diffs.ToImmutableList();
public IReadOnlyList<Diff> All { get; }
public IEnumerable<Diff> Major => All.Where(x => x.Level == Level.Major);
public IEnumerable<Diff> Minor => All.Where(x => x.Level == Level.Minor);
Expand Down

0 comments on commit 550148d

Please sign in to comment.