From f86530dc8d4979595662dd0ac342cdc9d7a889ee Mon Sep 17 00:00:00 2001 From: Anthony Steele Date: Mon, 22 Oct 2018 15:41:00 +0100 Subject: [PATCH] Multipackage wordings (#479) * multipackage commit wording * Multipackage updates can't all have the same branch name! * Tests pass * Introduce md5 hash * Tests on branch namer * Another test - same input data, same hash --- NuKeeper.Tests/Engine/BranchNamerTests.cs | 116 ++++++++++++++++++ NuKeeper.Tests/Engine/CommitWordingTests.cs | 7 +- NuKeeper.Tests/Engine/HasherTests.cs | 17 +++ NuKeeper/Engine/BranchNamer.cs | 25 +++- NuKeeper/Engine/CommitWording.cs | 26 +++- NuKeeper/Engine/Hasher.cs | 31 +++++ .../Engine/Packages/ExistingBranchFilter.cs | 2 +- 7 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 NuKeeper.Tests/Engine/BranchNamerTests.cs create mode 100644 NuKeeper.Tests/Engine/HasherTests.cs create mode 100644 NuKeeper/Engine/Hasher.cs diff --git a/NuKeeper.Tests/Engine/BranchNamerTests.cs b/NuKeeper.Tests/Engine/BranchNamerTests.cs new file mode 100644 index 000000000..079af5a66 --- /dev/null +++ b/NuKeeper.Tests/Engine/BranchNamerTests.cs @@ -0,0 +1,116 @@ +using System.Collections.Generic; +using NuKeeper.Engine; +using NuKeeper.Inspection.RepositoryInspection; +using NUnit.Framework; + +namespace NuKeeper.Tests.Engine +{ + [TestFixture] + public class BranchNamerTests + { + [Test] + public void TestWithSinglePackage() + { + var packages = PackageUpdates.MakeUpdateSet("SomePackage") + .InList(); + + var branchName = BranchNamer.MakeName(packages); + + Assert.That(branchName, Is.EqualTo("nukeeper-update-SomePackage-to-1.2.3")); + } + + [Test] + public void TestWithTwoPackages() + { + var packages = new List + { + PackageUpdates.MakeUpdateSet("SomePackage"), + PackageUpdates.MakeUpdateSet("OtherPackage") + }; + + var branchName = BranchNamer.MakeName(packages); + + Assert.That(branchName, Is.EqualTo("nukeeper-update-2-packages-AA9F9828431C8BFB7A18D3D8F0CF229D")); + } + + [Test] + public void TestWithThreePackages() + { + var packages = new List + { + PackageUpdates.MakeUpdateSet("SomePackage"), + PackageUpdates.MakeUpdateSet("OtherPackage"), + PackageUpdates.MakeUpdateSet("SomethingElse"), + }; + + var branchName = BranchNamer.MakeName(packages); + + Assert.That(branchName, Is.EqualTo("nukeeper-update-3-packages-BBBB3BF2315D6111CFCBF6A4A7A29DD8")); + } + + [Test] + public void EquivalentInputs_HaveSameHash() + { + var packages1 = new List + { + PackageUpdates.MakeUpdateSet("SomePackage", "2.3.4"), + PackageUpdates.MakeUpdateSet("OtherPackage", "2.3.4") + }; + + var packages2 = new List + { + PackageUpdates.MakeUpdateSet("SomePackage", "2.3.4"), + PackageUpdates.MakeUpdateSet("OtherPackage", "2.3.4") + }; + + var branchName1 = BranchNamer.MakeName(packages1); + var branchName2 = BranchNamer.MakeName(packages2); + + Assert.That(branchName1, Is.EqualTo(branchName2)); + } + + + [Test] + public void VersionChange_ChangesHash() + { + var packages1 = new List + { + PackageUpdates.MakeUpdateSet("SomePackage", "2.3.4"), + PackageUpdates.MakeUpdateSet("OtherPackage", "2.3.4") + }; + + var packages2 = new List + { + PackageUpdates.MakeUpdateSet("SomePackage", "2.3.4"), + PackageUpdates.MakeUpdateSet("OtherPackage", "2.3.5") + }; + + var branchName1 = BranchNamer.MakeName(packages1); + var branchName2 = BranchNamer.MakeName(packages2); + + Assert.That(branchName1, Is.Not.EqualTo(branchName2)); + } + + [Test] + public void NameChange_ChangesHash() + { + var packages1 = new List + { + PackageUpdates.MakeUpdateSet("SomePackage", "2.3.4"), + PackageUpdates.MakeUpdateSet("OtherPackage", "2.3.4") + }; + + var packages2 = new List + { + PackageUpdates.MakeUpdateSet("ZomePackage", "2.3.4"), + PackageUpdates.MakeUpdateSet("OtherPackage", "2.3.4") + }; + + var branchName1 = BranchNamer.MakeName(packages1); + var branchName2 = BranchNamer.MakeName(packages2); + + Assert.That(branchName1, Is.Not.EqualTo(branchName2)); + } + + } +} diff --git a/NuKeeper.Tests/Engine/CommitWordingTests.cs b/NuKeeper.Tests/Engine/CommitWordingTests.cs index 42da79e0a..c6e383506 100644 --- a/NuKeeper.Tests/Engine/CommitWordingTests.cs +++ b/NuKeeper.Tests/Engine/CommitWordingTests.cs @@ -298,7 +298,12 @@ public void TwoUpdateSets() var report = CommitWording.MakeCommitDetails(updates); - Assert.That(report, Does.StartWith("2 packages were updated: `foo.bar`, `packageTwo`")); + Assert.That(report, Does.StartWith("2 packages were updated in 1 project:")); + Assert.That(report, Does.Contain("`foo.bar`, `packageTwo`")); + Assert.That(report, Does.Contain("
")); + Assert.That(report, Does.Contain("
")); + Assert.That(report, Does.Contain("")); + Assert.That(report, Does.Contain("")); Assert.That(report, Does.Contain("NuKeeper has generated a major update of `foo.bar` to `2.1.1` from `1.1.0`")); Assert.That(report, Does.Contain("NuKeeper has generated a major update of `packageTwo` to `3.4.5` from `1.1.0`")); } diff --git a/NuKeeper.Tests/Engine/HasherTests.cs b/NuKeeper.Tests/Engine/HasherTests.cs new file mode 100644 index 000000000..8111544b9 --- /dev/null +++ b/NuKeeper.Tests/Engine/HasherTests.cs @@ -0,0 +1,17 @@ +using NUnit.Framework; +using NuKeeper.Engine; + +namespace NuKeeper.Tests.Engine +{ + [TestFixture] + public class HasherTests + { + [Test] + public void CanHash() + { + var output = Hasher.Hash("test"); + + Assert.That(output, Is.EqualTo("098F6BCD4621D373CADE4E832627B4F6")); + } + } +} diff --git a/NuKeeper/Engine/BranchNamer.cs b/NuKeeper/Engine/BranchNamer.cs index 7252a7abb..f2fbed30b 100644 --- a/NuKeeper/Engine/BranchNamer.cs +++ b/NuKeeper/Engine/BranchNamer.cs @@ -6,14 +6,33 @@ namespace NuKeeper.Engine { public static class BranchNamer { - public static string MakeName(PackageUpdateSet updateSet) + public static string MakeName(IReadOnlyCollection updates) + { + return updates.Count > 1 ? + MakeMultiPackageName(updates) : + MakeSinglePackageName(updates.First()); + } + + private static string MakeMultiPackageName(IReadOnlyCollection updates) + { + var updatesHash = Hasher.Hash(PackageVersionStrings(updates)); + + return $"nukeeper-update-{updates.Count}-packages-{updatesHash}"; + } + + public static string MakeSinglePackageName(PackageUpdateSet updateSet) { return $"nukeeper-update-{updateSet.SelectedId}-to-{updateSet.SelectedVersion}"; } - public static string MakeName(IReadOnlyCollection updates) + private static string PackageVersionStrings(IReadOnlyCollection updates) + { + return string.Join(",", updates.Select(PackageVersionString)); + } + + private static string PackageVersionString(PackageUpdateSet updateSet) { - return updates.Count > 1 ? "nukeeper-update-packages" : MakeName(updates.First()); + return $"{updateSet.SelectedId}-v{updateSet.SelectedVersion}"; } } } diff --git a/NuKeeper/Engine/CommitWording.cs b/NuKeeper/Engine/CommitWording.cs index 524ef357a..2f935f513 100644 --- a/NuKeeper/Engine/CommitWording.cs +++ b/NuKeeper/Engine/CommitWording.cs @@ -47,6 +47,11 @@ public static string MakeCommitDetails(IReadOnlyCollection upd builder.AppendLine(MakeCommitVersionDetails(update)); } + if (updates.Count > 1) + { + MultiPackageFooter(builder); + } + AddCommitFooter(builder); return builder.ToString(); @@ -57,7 +62,26 @@ private static void MultiPackagePrefix(IReadOnlyCollection upd var packageNames = updates .Select(p => CodeQuote(p.SelectedId)) .JoinWithCommas(); - builder.AppendLine($"{updates.Count} packages were updated: {packageNames}"); + + var projects = updates.SelectMany( + u => u.CurrentPackages) + .Select(p => p.Path.FullName) + .Distinct() + .ToList(); + + var projectOptS = (projects.Count > 1) ? "s" : string.Empty; + + builder.AppendLine($"{updates.Count} packages were updated in {projects.Count} project{projectOptS}:"); + builder.AppendLine(packageNames); + builder.AppendLine("
"); + builder.AppendLine("Details of updated packages"); + builder.AppendLine(""); + } + + private static void MultiPackageFooter(StringBuilder builder) + { + builder.AppendLine("
"); + builder.AppendLine(""); } private static string MakeCommitVersionDetails(PackageUpdateSet updates) diff --git a/NuKeeper/Engine/Hasher.cs b/NuKeeper/Engine/Hasher.cs new file mode 100644 index 000000000..c7490c904 --- /dev/null +++ b/NuKeeper/Engine/Hasher.cs @@ -0,0 +1,31 @@ +using System.Globalization; +using System.Security.Cryptography; +using System.Text; + +namespace NuKeeper.Engine +{ + public static class Hasher + { +#pragma warning disable CA5351 + private static MD5 md5 = MD5.Create(); + + public static string Hash(string input) + { + var inputBytes = Encoding.ASCII.GetBytes(input); + var hash = md5.ComputeHash(inputBytes); + return BytesToString(hash); + } + + private static string BytesToString(byte[] bytes) + { + var result = new StringBuilder(); + + foreach (var b in bytes) + { + result.Append(b.ToString("X2", CultureInfo.InvariantCulture)); + } + + return result.ToString(); + } + } +} diff --git a/NuKeeper/Engine/Packages/ExistingBranchFilter.cs b/NuKeeper/Engine/Packages/ExistingBranchFilter.cs index 2f0141aed..c0c367ee1 100644 --- a/NuKeeper/Engine/Packages/ExistingBranchFilter.cs +++ b/NuKeeper/Engine/Packages/ExistingBranchFilter.cs @@ -22,7 +22,7 @@ public async Task CanMakeBranchFor(PackageUpdateSet packageUpdateSet, { try { - var branchName = BranchNamer.MakeName(packageUpdateSet); + var branchName = BranchNamer.MakeSinglePackageName(packageUpdateSet); var githubBranch = await _gitHub.GetRepositoryBranch(pushFork.Owner, pushFork.Name, branchName); return (githubBranch == null); }