From b5c51fce259fb03d240c3f29a06276c803af07f6 Mon Sep 17 00:00:00 2001 From: Kieran Marron Date: Fri, 28 Sep 2018 15:41:56 +0100 Subject: [PATCH 01/11] Refactoring of merge message --- src/GitVersionCore.Tests/MergeMessageTests.cs | 75 ++++++---- src/GitVersionCore/MergeMessage.cs | 139 +++++++----------- 2 files changed, 103 insertions(+), 111 deletions(-) diff --git a/src/GitVersionCore.Tests/MergeMessageTests.cs b/src/GitVersionCore.Tests/MergeMessageTests.cs index 42d9ca6966..7a8e01f7fa 100644 --- a/src/GitVersionCore.Tests/MergeMessageTests.cs +++ b/src/GitVersionCore.Tests/MergeMessageTests.cs @@ -75,6 +75,7 @@ public void ParsesMergeMessage( var sut = new MergeMessage(message, _config); // Assert + sut.MatchDefinition.ShouldBe("Default"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeFalse(); @@ -91,13 +92,7 @@ public void ParsesMergeMessage( new object[] { "Merge pull request #1234 from origin/feature/one", "origin/feature/one", null, null, 1234 }, new object[] { "Merge pull request #1234 in feature/4.1/one", "feature/4.1/one", null, new SemanticVersion(4,1), 1234 }, new object[] { "Merge pull request #1234 in V://10.10.10.10", "V://10.10.10.10", null, null, 1234 }, - - - //TODO: Investigate successful github merge messages that may be invalid - // Should an empty PR number be valid? - new object[] { "Merge pull request # from feature/one", "feature/one", null, null, 0 }, - // The branch name appears to be incorrect - new object[] { "Merge pull request #1234 from feature/one into dev", "feature/one into dev", "dev", null, 1234 }, + new object[] { "Merge pull request #1234 from feature/one into dev", "feature/one", "dev", null, 1234 } }; [TestCaseSource(nameof(GitHubPullPullMergeMessages))] @@ -112,31 +107,32 @@ public void ParsesGitHubPullMergeMessage( var sut = new MergeMessage(message, _config); // Assert + sut.MatchDefinition.ShouldBe("GitHubPull"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeTrue(); sut.PullRequestNumber.ShouldBe(expectedPullRequestNumber); sut.Version.ShouldBe(expectedVersion); } - + private static readonly object[] BitBucketPullMergeMessages = { - new object[] { "Merge pull request #1234 from feature/one from feature/two to dev", "feature/two", null, null, 1234 }, - new object[] { "Merge pull request #1234 in feature/one from feature/two to dev", "feature/two", null, null, 1234 }, - new object[] { "Merge pull request #1234 in v4.0.0 from v4.1.0 to dev", "v4.1.0", null, new SemanticVersion(4,1), 1234 }, - new object[] { "Merge pull request #1234 in V4.0.0 from V4.1.0 to dev", "V4.1.0", null, new SemanticVersion(4,1), 1234 }, - new object[] { "Merge pull request #1234 from origin/feature/one from origin/feature/4.2/two to dev", "origin/feature/4.2/two", null, new SemanticVersion(4,2), 1234 }, - new object[] { "Merge pull request #1234 in feature/4.1/one from feature/4.2/two to dev", "feature/4.2/two", null, new SemanticVersion(4,2), 1234 }, - new object[] { "Merge pull request #1234 in feature/4.1/one from feature/4.2/two to dev into master", "feature/4.2/two", "master", new SemanticVersion(4,2), 1234 }, - new object[] { "Merge pull request #1234 in V4.1.0 from V://10.10.10.10 to dev", "V://10.10.10.10", null, null, 1234 }, + new object[] { "Merge pull request #1234 from feature/one from feature/two to dev", "feature/two", "dev", null, 1234 }, + new object[] { "Merge pull request #1234 in feature/one from feature/two to dev", "feature/two", "dev", null, 1234 }, + new object[] { "Merge pull request #1234 in v4.0.0 from v4.1.0 to dev", "v4.1.0", "dev", new SemanticVersion(4,1), 1234 }, + new object[] { "Merge pull request #1234 in V4.0.0 from V4.1.0 to dev", "V4.1.0", "dev", new SemanticVersion(4,1), 1234 }, + new object[] { "Merge pull request #1234 from origin/feature/one from origin/feature/4.2/two to dev", "origin/feature/4.2/two", "dev", new SemanticVersion(4,2), 1234 }, + new object[] { "Merge pull request #1234 in feature/4.1/one from feature/4.2/two to dev", "feature/4.2/two", "dev", new SemanticVersion(4,2), 1234 }, + new object[] { "Merge pull request #1234 in feature/4.1/one from feature/4.2/two to dev", "feature/4.2/two", "dev", new SemanticVersion(4,2), 1234 }, + new object[] { "Merge pull request #1234 from feature/one from feature/two to master" , "feature/two", "master", null, 1234 }, + new object[] { "Merge pull request #1234 in V4.1.0 from V://10.10.10.10 to dev", "V://10.10.10.10", "dev", null, 1234 }, //TODO: Investigate successful bitbucket merge messages that may be invalid // Regex has double 'from/in from' section. Is that correct? - new object[] { "Merge pull request #1234 in feature/4.1/one from feature/4.2/two to dev", "feature/4.2/two", null, new SemanticVersion(4,2), 1234 }, - new object[] { "Merge pull request #1234 from feature/one from v4.0.0 to master", "v4.0.0", null, new SemanticVersion(4), 1234 }, - // target branch is not resolved from targetbranch group - new object[] { "Merge pull request #1234 from feature/one from feature/two to master" , "feature/two", null, null, 1234 }, - // Should an empty PR number be valid? - new object[] { "Merge pull request # in feature/one from feature/two to master" , "feature/two", null, null, 0 } + new object[] { "Merge pull request #1234 in feature/4.1/one from feature/4.2/two to dev", "feature/4.2/two", "dev", new SemanticVersion(4,2), 1234 }, + new object[] { "Merge pull request #1234 from feature/one from v4.0.0 to master", "v4.0.0", "master", new SemanticVersion(4), 1234 } + + + }; [TestCaseSource(nameof(BitBucketPullMergeMessages))] @@ -151,6 +147,7 @@ public void ParsesBitBucketPullMergeMessage( var sut = new MergeMessage(message, _config); // Assert + sut.MatchDefinition.ShouldBe("BitBucketPull"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeTrue(); @@ -158,6 +155,7 @@ public void ParsesBitBucketPullMergeMessage( sut.Version.ShouldBe(expectedVersion); } + private static readonly object[] SmartGitMergeMessages = { new object[] { "Finish feature/one", "feature/one", null, null }, @@ -166,10 +164,7 @@ public void ParsesBitBucketPullMergeMessage( new object[] { "Finish feature/4.1/one", "feature/4.1/one", null, new SemanticVersion(4, 1) }, new object[] { "Finish origin/4.1/feature/one", "origin/4.1/feature/one", null, new SemanticVersion(4, 1) }, new object[] { "Finish V://10.10.10.10", "V://10.10.10.10", null, null }, - - //TODO: Investigate successful smart git merge messages that may be invalid - // The branch name appears to be incorrect - new object[] { "Finish V4.0.0 into master", "V4.0.0 into master", "master", new SemanticVersion(4) } + new object[] { "Finish V4.0.0 into master", "V4.0.0", "master", new SemanticVersion(4) } }; [TestCaseSource(nameof(SmartGitMergeMessages))] @@ -183,6 +178,7 @@ public void ParsesSmartGitMergeMessage( var sut = new MergeMessage(message, _config); // Assert + sut.MatchDefinition.ShouldBe("SmartGit"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeFalse(); @@ -212,11 +208,38 @@ public void ParsesRemoteTrackingMergeMessage( var sut = new MergeMessage(message, _config); // Assert + sut.MatchDefinition.ShouldBe("RemoteTracking"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeFalse(); sut.PullRequestNumber.ShouldBeNull(); sut.Version.ShouldBe(expectedVersion); } + + private static readonly object[] InvalidMergeMessages = + { + new object[] { "Merge pull request # from feature/one", "", null, null, null }, + new object[] { "Merge pull request # in feature/one from feature/two to master" , "", null, null, null } + }; + + [TestCaseSource(nameof(InvalidMergeMessages))] + public void ParsesInvalidBitBucketPullMergeMessage( + string message, + string expectedMergedBranch, + string expectedTargetBranch, + SemanticVersion expectedVersion, + int? expectedPullRequestNumber) + { + // Act + var sut = new MergeMessage(message, _config); + + // Assert + sut.MatchDefinition.ShouldBeNull(); + sut.TargetBranch.ShouldBe(expectedTargetBranch); + sut.MergedBranch.ShouldBe(expectedMergedBranch); + sut.IsMergedPullRequest.ShouldBeFalse(); + sut.PullRequestNumber.ShouldBe(expectedPullRequestNumber); + sut.Version.ShouldBe(expectedVersion); + } } } diff --git a/src/GitVersionCore/MergeMessage.cs b/src/GitVersionCore/MergeMessage.cs index 8fb597da84..86df3297e6 100644 --- a/src/GitVersionCore/MergeMessage.cs +++ b/src/GitVersionCore/MergeMessage.cs @@ -1,117 +1,86 @@ -using System; -using System.Linq; +using System; +using System.Collections.Generic; using System.Text.RegularExpressions; namespace GitVersion { class MergeMessage { - static Regex parseMergeMessage = new Regex( - @"^Merge (branch|tag) '(?[^']*)'", - RegexOptions.IgnoreCase | RegexOptions.Compiled); - static Regex parseGitHubPullMergeMessage = new Regex( - @"^Merge pull request #(?\d*) (from|in) (?.*)", - RegexOptions.IgnoreCase | RegexOptions.Compiled); - static Regex parseBitBucketPullMergeMessage = new Regex( - @"^Merge pull request #(?\d*) (from|in) (?.*) from (?.*) to (?.*)", - RegexOptions.IgnoreCase | RegexOptions.Compiled); - static Regex smartGitMergeMessage = new Regex( - @"^Finish (?.*)", - RegexOptions.IgnoreCase | RegexOptions.Compiled); - static Regex parseRemoteTrackingMergeMessage = new Regex( - @"^Merge remote-tracking branch '(?.*)' into (?.*)", - RegexOptions.IgnoreCase | RegexOptions.Compiled); - - private string mergeMessage; - private Config config; + private static readonly IList Patterns = new List + { + new MergeMessagePattern("Default", @"^Merge (branch|tag) '(?[^']*)'(?: into (?[^\s]*))*"), + new MergeMessagePattern("SmartGit", @"^Finish (?[^\s]*)(?: into (?[^\s]*))*"), + new MergeMessagePattern("BitBucketPull", @"^Merge pull request #(?\d+) (from|in) (?.*) from (?[^\s]*) to (?[^\s]*)"), + new MergeMessagePattern("GitHubPull", @"^Merge pull request #(?\d+) (from|in) (?:(?[^\s]*))(?: into (?[^\s]*))*"), + new MergeMessagePattern("RemoteTracking", @"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*") + }; public MergeMessage(string mergeMessage, Config config) { - this.mergeMessage = mergeMessage; - this.config = config; + if (mergeMessage == null) + throw new NullReferenceException(); - var lastIndexOf = mergeMessage.LastIndexOf("into", StringComparison.OrdinalIgnoreCase); - if (lastIndexOf != -1) + foreach (var pattern in Patterns) { - // If we have into in the merge message the rest should be the target branch - TargetBranch = mergeMessage.Substring(lastIndexOf + 5); - } + var match = pattern.Format.Match(mergeMessage); + if (match.Success) + { + MatchDefinition = pattern.Name; + MergedBranch = match.Groups["SourceBranch"].Value; - MergedBranch = ParseBranch(); + if (match.Groups["TargetBranch"].Success) + { + TargetBranch = match.Groups["TargetBranch"].Value; + } - // Remove remotes and branch prefixes like release/ feature/ hotfix/ etc - var toMatch = Regex.Replace(MergedBranch, @"^(\w+[-/])*", "", RegexOptions.IgnoreCase); - toMatch = Regex.Replace(toMatch, $"^{config.TagPrefix}", ""); - // We don't match if the version is likely an ip (i.e starts with http://) - var versionMatch = new Regex(@"^(? PullRequestNumber != null; + public int? PullRequestNumber { get; } + public SemanticVersion Version { get; } - match = smartGitMergeMessage.Match(mergeMessage); - if (match.Success) - { - return match.Groups["Branch"].Value; - } - match = parseBitBucketPullMergeMessage.Match(mergeMessage); - if (match.Success) - { - IsMergedPullRequest = true; - PullRequestNumber = GetPullRequestNumber(match); - return match.Groups["SourceBranch"].Value; - } + private SemanticVersion ParseVersion(string branchName, string tagPrefix) + { + // Remove remotes and branch prefixes like release/ feature/ hotfix/ etc + var toMatch = Regex.Replace(MergedBranch, @"^(\w+[-/])*", "", RegexOptions.IgnoreCase); + toMatch = Regex.Replace(toMatch, $"^{tagPrefix}", ""); + // We don't match if the version is likely an ip (i.e starts with http://) + var versionMatch = new Regex(@"^(? Date: Tue, 2 Oct 2018 16:05:57 +0100 Subject: [PATCH 02/11] Enable custom merge message formats to be applied via configuration --- docs/configuration.md | 19 ++++ ...riteOutEffectiveConfiguration.approved.txt | 1 + ...itScenarios.CanSetNextVersion.approved.txt | 1 + src/GitVersionCore.Tests/MergeMessageTests.cs | 77 ++++++++++++++++ src/GitVersionCore/Configuration/Config.cs | 7 +- src/GitVersionCore/MergeMessage.cs | 90 ++++++++++--------- 6 files changed, 152 insertions(+), 43 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 217041adbd..f3b7e54b97 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -48,6 +48,7 @@ commit-date-format: 'yyyy-MM-dd' ignore: sha: [] commits-before: yyyy-MM-ddTHH:mm:ss +merge-messages: {} ``` And the description of the available options are: @@ -179,6 +180,24 @@ Date and time in the format `yyyy-MM-ddTHH:mm:ss` (eg `commits-before: 2015-10-23T12:23:15`) to setup an exclusion range. Effectively any commit before `commits-before` will be ignored. +### merge-messages +Custom merge message formats to enable identification of merge messages that do not +follow the built-in conventions. Entries should be added as key-value pairs where +the value is a regular expression. +e.g. + +``` +merge-messages: + tfs: ^Merged (?:PR (?\d+)): Merge (?.+) to (?.+) +``` + +The regular expression should contain the following capture groups: ++ SourceBranch - Identifies the source branch of the merge ++ TargetBranch - Identifies the target of the merge ++ PullRequestNumber - Captures the pull-request number + +Custom merge message formats are evalauted _before_ any built in formats. + ## Branch configuration Then we have branch specific configuration, which looks something like this: diff --git a/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt b/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt index 2650aedd2b..0f12ea1663 100644 --- a/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt +++ b/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt @@ -115,3 +115,4 @@ branches: ignore: sha: [] commit-date-format: yyyy-MM-dd +merge-messages: {} diff --git a/src/GitVersionCore.Tests/Init/InitScenarios.CanSetNextVersion.approved.txt b/src/GitVersionCore.Tests/Init/InitScenarios.CanSetNextVersion.approved.txt index 4d1763fcf8..ff546e235d 100644 --- a/src/GitVersionCore.Tests/Init/InitScenarios.CanSetNextVersion.approved.txt +++ b/src/GitVersionCore.Tests/Init/InitScenarios.CanSetNextVersion.approved.txt @@ -2,3 +2,4 @@ next-version: 2.0.0 branches: {} ignore: sha: [] +merge-messages: {} diff --git a/src/GitVersionCore.Tests/MergeMessageTests.cs b/src/GitVersionCore.Tests/MergeMessageTests.cs index 7a8e01f7fa..165eef7901 100644 --- a/src/GitVersionCore.Tests/MergeMessageTests.cs +++ b/src/GitVersionCore.Tests/MergeMessageTests.cs @@ -2,6 +2,7 @@ using NUnit.Framework; using Shouldly; using System; +using System.Collections.Generic; namespace GitVersionCore.Tests { @@ -241,5 +242,81 @@ public void ParsesInvalidBitBucketPullMergeMessage( sut.PullRequestNumber.ShouldBe(expectedPullRequestNumber); sut.Version.ShouldBe(expectedVersion); } + + + [Test] + public void MatchesSingleCustomMessage() + { + // Arrange + var message = "My custom message"; + var definition = "Mycustom"; + _config.MergeMessageFormats = new Dictionary + { + [definition] = message + }; + + // Act + var sut = new MergeMessage(message, _config); + + // Assert + sut.MatchDefinition.ShouldBe(definition); + sut.TargetBranch.ShouldBeNull(); + sut.MergedBranch.ShouldBeEmpty(); + sut.IsMergedPullRequest.ShouldBeFalse(); + sut.PullRequestNumber.ShouldBeNull(); + sut.Version.ShouldBeNull(); + } + + [Test] + public void MatchesMultipleCustomMessages() + { + // Arrange + var format = "My custom message"; + var definition = "Mycustom"; + _config.MergeMessageFormats = new Dictionary + { + ["Default2"] = "some example", + ["Default3"] = "another example", + [definition] = format + }; + + // Act + var sut = new MergeMessage(format, _config); + + // Assert + sut.MatchDefinition.ShouldBe(definition); + sut.TargetBranch.ShouldBeNull(); + sut.MergedBranch.ShouldBeEmpty(); + sut.IsMergedPullRequest.ShouldBeFalse(); + sut.PullRequestNumber.ShouldBeNull(); + sut.Version.ShouldBeNull(); + } + + [Test] + public void MatchesCaptureGroupsFromCustomMessages() + { + // Arrange + var format = @"^Merged PR #(?\d+) into (?[^\s]*) from (?:(?[^\s]*))"; + var definition = "Mycustom"; + _config.MergeMessageFormats = new Dictionary + { + [definition] = format + }; + var pr = 1234; + var target = "master"; + var source = "feature/2.0/example"; + + + // Act + var sut = new MergeMessage($"Merged PR #{pr} into {target} from {source}", _config); + + // Assert + sut.MatchDefinition.ShouldBe(definition); + sut.TargetBranch.ShouldBe(target); + sut.MergedBranch.ShouldBe(source); + sut.IsMergedPullRequest.ShouldBeTrue(); + sut.PullRequestNumber.ShouldBe(pr); + sut.Version.ShouldBe(new SemanticVersion(2,0)); + } } } diff --git a/src/GitVersionCore/Configuration/Config.cs b/src/GitVersionCore/Configuration/Config.cs index 8225df969f..ad485a711f 100644 --- a/src/GitVersionCore/Configuration/Config.cs +++ b/src/GitVersionCore/Configuration/Config.cs @@ -1,4 +1,4 @@ -namespace GitVersion +namespace GitVersion { using System; using System.Collections.Generic; @@ -144,5 +144,8 @@ T MergeObjects(T target, T source) [YamlMember(Alias = "commit-date-format")] public string CommitDateFormat { get; set; } + + [YamlMember(Alias = "merge-messages")] + public Dictionary MergeMessageFormats { get; set; } = new Dictionary(); } -} \ No newline at end of file +} diff --git a/src/GitVersionCore/MergeMessage.cs b/src/GitVersionCore/MergeMessage.cs index 86df3297e6..a05400991c 100644 --- a/src/GitVersionCore/MergeMessage.cs +++ b/src/GitVersionCore/MergeMessage.cs @@ -4,15 +4,15 @@ namespace GitVersion { - class MergeMessage + internal class MergeMessage { - private static readonly IList Patterns = new List + private static readonly IList> DefaultPatterns = new List> { - new MergeMessagePattern("Default", @"^Merge (branch|tag) '(?[^']*)'(?: into (?[^\s]*))*"), - new MergeMessagePattern("SmartGit", @"^Finish (?[^\s]*)(?: into (?[^\s]*))*"), - new MergeMessagePattern("BitBucketPull", @"^Merge pull request #(?\d+) (from|in) (?.*) from (?[^\s]*) to (?[^\s]*)"), - new MergeMessagePattern("GitHubPull", @"^Merge pull request #(?\d+) (from|in) (?:(?[^\s]*))(?: into (?[^\s]*))*"), - new MergeMessagePattern("RemoteTracking", @"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*") + Pattern("Default", @"^Merge (branch|tag) '(?[^']*)'(?: into (?[^\s]*))*"), + Pattern("SmartGit", @"^Finish (?[^\s]*)(?: into (?[^\s]*))*"), + Pattern("BitBucketPull", @"^Merge pull request #(?\d+) (from|in) (?.*) from (?[^\s]*) to (?[^\s]*)"), + Pattern("GitHubPull", @"^Merge pull request #(?\d+) (from|in) (?:(?[^\s]*))(?: into (?[^\s]*))*"), + Pattern("RemoteTracking", @"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*") }; public MergeMessage(string mergeMessage, Config config) @@ -20,38 +20,56 @@ public MergeMessage(string mergeMessage, Config config) if (mergeMessage == null) throw new NullReferenceException(); - foreach (var pattern in Patterns) + foreach(var entry in config.MergeMessageFormats) { - var match = pattern.Format.Match(mergeMessage); - if (match.Success) + var pattern = Pattern(entry.Key, entry.Value); + if (ApplyPattern(mergeMessage, config.TagPrefix, pattern)) { - MatchDefinition = pattern.Name; - MergedBranch = match.Groups["SourceBranch"].Value; - - if (match.Groups["TargetBranch"].Success) - { - TargetBranch = match.Groups["TargetBranch"].Value; - } - - if (int.TryParse(match.Groups["PullRequestNumber"].Value, out var pullNumber)) - { - PullRequestNumber = pullNumber; - } - - Version = ParseVersion(MergedBranch, config.TagPrefix); + break; + } + } + foreach (var pattern in DefaultPatterns) + { + if (ApplyPattern(mergeMessage, config.TagPrefix, pattern)) + { break; } } } - public string MatchDefinition { get; } - public string TargetBranch { get; } - public string MergedBranch { get; } = ""; + public string MatchDefinition { get; private set; } + public string TargetBranch { get; private set; } + public string MergedBranch { get; private set; } = ""; public bool IsMergedPullRequest => PullRequestNumber != null; - public int? PullRequestNumber { get; } - public SemanticVersion Version { get; } + public int? PullRequestNumber { get; private set; } + public SemanticVersion Version { get; private set; } + private bool ApplyPattern(string mergeMessage, string tagPrefix, KeyValuePair pattern) + { + var match = pattern.Value.Match(mergeMessage); + if (match.Success) + { + MatchDefinition = pattern.Key; + MergedBranch = match.Groups["SourceBranch"].Value; + + if (match.Groups["TargetBranch"].Success) + { + TargetBranch = match.Groups["TargetBranch"].Value; + } + + if (int.TryParse(match.Groups["PullRequestNumber"].Value, out var pullNumber)) + { + PullRequestNumber = pullNumber; + } + + Version = ParseVersion(MergedBranch, tagPrefix); + + return true; + } + + return false; + } private SemanticVersion ParseVersion(string branchName, string tagPrefix) { @@ -70,17 +88,7 @@ private SemanticVersion ParseVersion(string branchName, string tagPrefix) return null; } - private class MergeMessagePattern - { - public MergeMessagePattern(string name, string format) - { - Name = name; - Format = new Regex(format, RegexOptions.IgnoreCase | RegexOptions.Compiled); - } - - public string Name { get; } - - public Regex Format { get; } - } + private static KeyValuePair Pattern(string name, string format) + => new KeyValuePair(name, new Regex(format, RegexOptions.IgnoreCase | RegexOptions.Compiled)); } } From 6b73852300ca260065226a07c3e0ee4dff88faf3 Mon Sep 17 00:00:00 2001 From: Kieran Marron Date: Tue, 2 Oct 2018 17:53:25 +0100 Subject: [PATCH 03/11] MergeMessage - Ensure return after first match --- src/GitVersionCore.Tests/MergeMessageTests.cs | 31 +++++++++++++++++-- src/GitVersionCore/MergeMessage.cs | 4 +-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/GitVersionCore.Tests/MergeMessageTests.cs b/src/GitVersionCore.Tests/MergeMessageTests.cs index 165eef7901..bc53b5c747 100644 --- a/src/GitVersionCore.Tests/MergeMessageTests.cs +++ b/src/GitVersionCore.Tests/MergeMessageTests.cs @@ -115,7 +115,7 @@ public void ParsesGitHubPullMergeMessage( sut.PullRequestNumber.ShouldBe(expectedPullRequestNumber); sut.Version.ShouldBe(expectedVersion); } - + private static readonly object[] BitBucketPullMergeMessages = { new object[] { "Merge pull request #1234 from feature/one from feature/two to dev", "feature/two", "dev", null, 1234 }, @@ -243,7 +243,7 @@ public void ParsesInvalidBitBucketPullMergeMessage( sut.Version.ShouldBe(expectedVersion); } - + [Test] public void MatchesSingleCustomMessage() { @@ -316,7 +316,32 @@ public void MatchesCaptureGroupsFromCustomMessages() sut.MergedBranch.ShouldBe(source); sut.IsMergedPullRequest.ShouldBeTrue(); sut.PullRequestNumber.ShouldBe(pr); - sut.Version.ShouldBe(new SemanticVersion(2,0)); + sut.Version.ShouldBe(new SemanticVersion(2, 0)); + } + + [Test] + public void ReturnsAfterFirstMatchingPattern() + { + // Arrange + var format = @"^Merge (branch|tag) '(?[^']*)'(?: into (?[^\s]*))*"; + var definition = "Mycustom"; + _config.MergeMessageFormats = new Dictionary + { + [definition] = format, + ["Default2"] = format, + ["Default3"] = format + }; + + // Act + var sut = new MergeMessage("Merge branch 'this'", _config); + + // Assert + sut.MatchDefinition.ShouldBe(definition); + sut.TargetBranch.ShouldBeNull(); + sut.MergedBranch.ShouldBe("this"); + sut.IsMergedPullRequest.ShouldBeFalse(); + sut.PullRequestNumber.ShouldBeNull(); + sut.Version.ShouldBeNull(); } } } diff --git a/src/GitVersionCore/MergeMessage.cs b/src/GitVersionCore/MergeMessage.cs index a05400991c..680d521440 100644 --- a/src/GitVersionCore/MergeMessage.cs +++ b/src/GitVersionCore/MergeMessage.cs @@ -25,7 +25,7 @@ public MergeMessage(string mergeMessage, Config config) var pattern = Pattern(entry.Key, entry.Value); if (ApplyPattern(mergeMessage, config.TagPrefix, pattern)) { - break; + return; } } @@ -33,7 +33,7 @@ public MergeMessage(string mergeMessage, Config config) { if (ApplyPattern(mergeMessage, config.TagPrefix, pattern)) { - break; + return; } } } From 76c7ddaded44e1f6fa4a3e78298369ccc4f1322e Mon Sep 17 00:00:00 2001 From: Kieranties Date: Sat, 13 Apr 2019 12:51:34 +0100 Subject: [PATCH 04/11] CR: merge-messages -> merge-message-formats --- docs/configuration.md | 4 ++-- ...oviderTests.CanWriteOutEffectiveConfiguration.approved.txt | 2 +- .../Init/InitScenarios.CanSetNextVersion.approved.txt | 2 +- src/GitVersionCore/Configuration/Config.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 7f9dc911fe..a58efeedc4 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -180,14 +180,14 @@ Date and time in the format `yyyy-MM-ddTHH:mm:ss` (eg `commits-before: 2015-10-23T12:23:15`) to setup an exclusion range. Effectively any commit before `commits-before` will be ignored. -### merge-messages +### merge-message-formats Custom merge message formats to enable identification of merge messages that do not follow the built-in conventions. Entries should be added as key-value pairs where the value is a regular expression. e.g. ``` -merge-messages: +merge-message-formats: tfs: ^Merged (?:PR (?\d+)): Merge (?.+) to (?.+) ``` diff --git a/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt b/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt index 8a70ea2b9e..0c3764505e 100644 --- a/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt +++ b/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt @@ -122,4 +122,4 @@ branches: ignore: sha: [] commit-date-format: yyyy-MM-dd -merge-messages: {} +merge-message-formats: {} diff --git a/src/GitVersionCore.Tests/Init/InitScenarios.CanSetNextVersion.approved.txt b/src/GitVersionCore.Tests/Init/InitScenarios.CanSetNextVersion.approved.txt index ff546e235d..0368e755e7 100644 --- a/src/GitVersionCore.Tests/Init/InitScenarios.CanSetNextVersion.approved.txt +++ b/src/GitVersionCore.Tests/Init/InitScenarios.CanSetNextVersion.approved.txt @@ -2,4 +2,4 @@ next-version: 2.0.0 branches: {} ignore: sha: [] -merge-messages: {} +merge-message-formats: {} diff --git a/src/GitVersionCore/Configuration/Config.cs b/src/GitVersionCore/Configuration/Config.cs index 40e96a3407..71a4f0a7ec 100644 --- a/src/GitVersionCore/Configuration/Config.cs +++ b/src/GitVersionCore/Configuration/Config.cs @@ -146,7 +146,7 @@ T MergeObjects(T target, T source) [YamlMember(Alias = "commit-date-format")] public string CommitDateFormat { get; set; } - [YamlMember(Alias = "merge-messages")] + [YamlMember(Alias = "merge-message-formats")] public Dictionary MergeMessageFormats { get; set; } = new Dictionary(); } } From 3862d1fa614c294479c6cddb29444dc1c818e1a5 Mon Sep 17 00:00:00 2001 From: Kieranties Date: Thu, 25 Apr 2019 19:27:44 +0100 Subject: [PATCH 05/11] Write log for matching mergmessage definition --- .../BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs index 3b2d4f228f..e36eb88133 100644 --- a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs +++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs @@ -23,6 +23,7 @@ public override IEnumerable GetVersions(GitVersionContext context) mergeMessage.Version != null && context.FullConfiguration.IsReleaseBranch(TrimRemote(mergeMessage.MergedBranch))) { + Logger.WriteInfo($"Found commit [{context.CurrentCommit.Sha}] matching merge message format: {mergeMessage.MatchDefinition}"); var shouldIncrement = !context.Configuration.PreventIncrementForMergedBranchVersion; return new[] { From b82c2977a899692b321ea4d94deb5914ac4bd6ad Mon Sep 17 00:00:00 2001 From: Kieranties Date: Fri, 26 Apr 2019 09:09:15 +0100 Subject: [PATCH 06/11] CR: Correct configuration example --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index a58efeedc4..7a4fc23714 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -48,7 +48,7 @@ commit-date-format: 'yyyy-MM-dd' ignore: sha: [] commits-before: yyyy-MM-ddTHH:mm:ss -merge-messages: {} +merge-message-formats: {} ``` And the description of the available options are: From f353dd8782cfcc91bdaf8de492fdbe08d896dc4c Mon Sep 17 00:00:00 2001 From: Kieranties Date: Fri, 26 Apr 2019 09:14:43 +0100 Subject: [PATCH 07/11] CR: Whitespace correction --- src/GitVersionCore.Tests/MergeMessageTests.cs | 130 +++++++++--------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/src/GitVersionCore.Tests/MergeMessageTests.cs b/src/GitVersionCore.Tests/MergeMessageTests.cs index 6d2f4f8b73..338620a0ea 100644 --- a/src/GitVersionCore.Tests/MergeMessageTests.cs +++ b/src/GitVersionCore.Tests/MergeMessageTests.cs @@ -55,13 +55,13 @@ public void EmptyTagPrefix(string prefix) private static readonly object[] MergeMessages = { - new object[] { "Merge branch 'feature/one'", "feature/one", null, null }, - new object[] { "Merge branch 'origin/feature/one'", "origin/feature/one", null, null }, - new object[] { "Merge tag 'v4.0.0' into master", "v4.0.0", "master", new SemanticVersion(4) }, - new object[] { "Merge tag 'V4.0.0' into master", "V4.0.0", "master", new SemanticVersion(4) }, - new object[] { "Merge branch 'feature/4.1/one'", "feature/4.1/one", null, new SemanticVersion(4, 1) }, - new object[] { "Merge branch 'origin/4.1/feature/one'", "origin/4.1/feature/one", null, new SemanticVersion(4, 1) }, - new object[] { "Merge tag 'v://10.10.10.10' into master", "v://10.10.10.10", "master", null } + new object[] { "Merge branch 'feature/one'", "feature/one", null, null }, + new object[] { "Merge branch 'origin/feature/one'", "origin/feature/one", null, null }, + new object[] { "Merge tag 'v4.0.0' into master", "v4.0.0", "master", new SemanticVersion(4) }, + new object[] { "Merge tag 'V4.0.0' into master", "V4.0.0", "master", new SemanticVersion(4) }, + new object[] { "Merge branch 'feature/4.1/one'", "feature/4.1/one", null, new SemanticVersion(4, 1) }, + new object[] { "Merge branch 'origin/4.1/feature/one'", "origin/4.1/feature/one", null, new SemanticVersion(4, 1) }, + new object[] { "Merge tag 'v://10.10.10.10' into master", "v://10.10.10.10", "master", null } }; [TestCaseSource(nameof(MergeMessages))] @@ -85,13 +85,13 @@ public void ParsesMergeMessage( private static readonly object[] GitHubPullPullMergeMessages = { - new object[] { "Merge pull request #1234 from feature/one", "feature/one", null, null, 1234 }, - new object[] { "Merge pull request #1234 in feature/one", "feature/one", null, null, 1234 }, - new object[] { "Merge pull request #1234 in v4.0.0", "v4.0.0", null, new SemanticVersion(4), 1234 }, - new object[] { "Merge pull request #1234 from origin/feature/one", "origin/feature/one", null, null, 1234 }, - new object[] { "Merge pull request #1234 in feature/4.1/one", "feature/4.1/one", null, new SemanticVersion(4,1), 1234 }, - new object[] { "Merge pull request #1234 in V://10.10.10.10", "V://10.10.10.10", null, null, 1234 }, - new object[] { "Merge pull request #1234 from feature/one into dev", "feature/one", "dev", null, 1234 } + new object[] { "Merge pull request #1234 from feature/one", "feature/one", null, null, 1234 }, + new object[] { "Merge pull request #1234 in feature/one", "feature/one", null, null, 1234 }, + new object[] { "Merge pull request #1234 in v4.0.0", "v4.0.0", null, new SemanticVersion(4), 1234 }, + new object[] { "Merge pull request #1234 from origin/feature/one", "origin/feature/one", null, null, 1234 }, + new object[] { "Merge pull request #1234 in feature/4.1/one", "feature/4.1/one", null, new SemanticVersion(4,1), 1234 }, + new object[] { "Merge pull request #1234 in V://10.10.10.10", "V://10.10.10.10", null, null, 1234 }, + new object[] { "Merge pull request #1234 from feature/one into dev", "feature/one", "dev", null, 1234 } }; [TestCaseSource(nameof(GitHubPullPullMergeMessages))] @@ -116,16 +116,16 @@ public void ParsesGitHubPullMergeMessage( private static readonly object[] BitBucketPullMergeMessages = { - new object[] { "Merge pull request #1234 from feature/one from feature/two to dev", "feature/two", "dev", null, 1234 }, - new object[] { "Merge pull request #1234 in feature/one from feature/two to dev", "feature/two", "dev", null, 1234 }, - new object[] { "Merge pull request #1234 in v4.0.0 from v4.1.0 to dev", "v4.1.0", "dev", new SemanticVersion(4,1), 1234 }, - new object[] { "Merge pull request #1234 from origin/feature/one from origin/feature/4.2/two to dev", "origin/feature/4.2/two", "dev", new SemanticVersion(4,2), 1234 }, - new object[] { "Merge pull request #1234 in feature/4.1/one from feature/4.2/two to dev", "feature/4.2/two", "dev", new SemanticVersion(4,2), 1234 }, - new object[] { "Merge pull request #1234 from feature/one from feature/two to master" , "feature/two", "master", null, 1234 }, - new object[] { "Merge pull request #1234 in V4.1.0 from V://10.10.10.10 to dev", "V://10.10.10.10", "dev", null, 1234 }, - //TODO: Investigate successful bitbucket merge messages that may be invalid - // Regex has double 'from/in from' section. Is that correct? - new object[] { "Merge pull request #1234 from feature/one from v4.0.0 to master", "v4.0.0", "master", new SemanticVersion(4), 1234 } + new object[] { "Merge pull request #1234 from feature/one from feature/two to dev", "feature/two", "dev", null, 1234 }, + new object[] { "Merge pull request #1234 in feature/one from feature/two to dev", "feature/two", "dev", null, 1234 }, + new object[] { "Merge pull request #1234 in v4.0.0 from v4.1.0 to dev", "v4.1.0", "dev", new SemanticVersion(4,1), 1234 }, + new object[] { "Merge pull request #1234 from origin/feature/one from origin/feature/4.2/two to dev", "origin/feature/4.2/two", "dev", new SemanticVersion(4,2), 1234 }, + new object[] { "Merge pull request #1234 in feature/4.1/one from feature/4.2/two to dev", "feature/4.2/two", "dev", new SemanticVersion(4,2), 1234 }, + new object[] { "Merge pull request #1234 from feature/one from feature/two to master" , "feature/two", "master", null, 1234 }, + new object[] { "Merge pull request #1234 in V4.1.0 from V://10.10.10.10 to dev", "V://10.10.10.10", "dev", null, 1234 }, + //TODO: Investigate successful bitbucket merge messages that may be invalid + // Regex has double 'from/in from' section. Is that correct? + new object[] { "Merge pull request #1234 from feature/one from v4.0.0 to master", "v4.0.0", "master", new SemanticVersion(4), 1234 } }; [TestCaseSource(nameof(BitBucketPullMergeMessages))] @@ -151,21 +151,21 @@ public void ParsesBitBucketPullMergeMessage( private static readonly object[] SmartGitMergeMessages = { - new object[] { "Finish feature/one", "feature/one", null, null }, - new object[] { "Finish origin/feature/one", "origin/feature/one", null, null }, - new object[] { "Finish v4.0.0", "v4.0.0", null, new SemanticVersion(4) }, - new object[] { "Finish feature/4.1/one", "feature/4.1/one", null, new SemanticVersion(4, 1) }, - new object[] { "Finish origin/4.1/feature/one", "origin/4.1/feature/one", null, new SemanticVersion(4, 1) }, - new object[] { "Finish V://10.10.10.10", "V://10.10.10.10", null, null }, - new object[] { "Finish V4.0.0 into master", "V4.0.0", "master", new SemanticVersion(4) } + new object[] { "Finish feature/one", "feature/one", null, null }, + new object[] { "Finish origin/feature/one", "origin/feature/one", null, null }, + new object[] { "Finish v4.0.0", "v4.0.0", null, new SemanticVersion(4) }, + new object[] { "Finish feature/4.1/one", "feature/4.1/one", null, new SemanticVersion(4, 1) }, + new object[] { "Finish origin/4.1/feature/one", "origin/4.1/feature/one", null, new SemanticVersion(4, 1) }, + new object[] { "Finish V://10.10.10.10", "V://10.10.10.10", null, null }, + new object[] { "Finish V4.0.0 into master", "V4.0.0", "master", new SemanticVersion(4) } }; [TestCaseSource(nameof(SmartGitMergeMessages))] public void ParsesSmartGitMergeMessage( - string message, - string expectedMergedBranch, - string expectedTargetBranch, - SemanticVersion expectedVersion) + string message, + string expectedMergedBranch, + string expectedTargetBranch, + SemanticVersion expectedVersion) { // Act var sut = new MergeMessage(message, _config); @@ -181,21 +181,21 @@ public void ParsesSmartGitMergeMessage( private static readonly object[] RemoteTrackingMergeMessages = { - new object[] { "Merge remote-tracking branch 'feature/one' into master", "feature/one", "master", null }, - new object[] { "Merge remote-tracking branch 'origin/feature/one' into dev", "origin/feature/one", "dev", null }, - new object[] { "Merge remote-tracking branch 'v4.0.0' into master", "v4.0.0", "master", new SemanticVersion(4) }, - new object[] { "Merge remote-tracking branch 'V4.0.0' into master", "V4.0.0", "master", new SemanticVersion(4) }, - new object[] { "Merge remote-tracking branch 'feature/4.1/one' into dev", "feature/4.1/one", "dev", new SemanticVersion(4, 1) }, - new object[] { "Merge remote-tracking branch 'origin/4.1/feature/one' into master", "origin/4.1/feature/one", "master", new SemanticVersion(4, 1) }, - new object[] { "Merge remote-tracking branch 'v://10.10.10.10' into master", "v://10.10.10.10", "master", null } + new object[] { "Merge remote-tracking branch 'feature/one' into master", "feature/one", "master", null }, + new object[] { "Merge remote-tracking branch 'origin/feature/one' into dev", "origin/feature/one", "dev", null }, + new object[] { "Merge remote-tracking branch 'v4.0.0' into master", "v4.0.0", "master", new SemanticVersion(4) }, + new object[] { "Merge remote-tracking branch 'V4.0.0' into master", "V4.0.0", "master", new SemanticVersion(4) }, + new object[] { "Merge remote-tracking branch 'feature/4.1/one' into dev", "feature/4.1/one", "dev", new SemanticVersion(4, 1) }, + new object[] { "Merge remote-tracking branch 'origin/4.1/feature/one' into master", "origin/4.1/feature/one", "master", new SemanticVersion(4, 1) }, + new object[] { "Merge remote-tracking branch 'v://10.10.10.10' into master", "v://10.10.10.10", "master", null } }; [TestCaseSource(nameof(RemoteTrackingMergeMessages))] public void ParsesRemoteTrackingMergeMessage( - string message, - string expectedMergedBranch, - string expectedTargetBranch, - SemanticVersion expectedVersion) + string message, + string expectedMergedBranch, + string expectedTargetBranch, + SemanticVersion expectedVersion) { // Act var sut = new MergeMessage(message, _config); @@ -211,25 +211,25 @@ public void ParsesRemoteTrackingMergeMessage( private static readonly object[] ParsesTfsEnglishUSMergeMessages = { - new object[] { "Merge feature/one to master", "feature/one", "master", null }, - new object[] { "Merge v://10.10.10.10 to master", "v://10.10.10.10", "master", null }, - new object[] { "Merge feature/one to v://10.10.10.10", "feature/one", "v://10.10.10.10", null }, - new object[] { "Merge V4.0.0 to master", "V4.0.0", "master", new SemanticVersion(4) }, - new object[] { "Merge feature/4.1/one to master", "feature/4.1/one", "master", new SemanticVersion(4, 1) } + new object[] { "Merge feature/one to master", "feature/one", "master", null }, + new object[] { "Merge v://10.10.10.10 to master", "v://10.10.10.10", "master", null }, + new object[] { "Merge feature/one to v://10.10.10.10", "feature/one", "v://10.10.10.10", null }, + new object[] { "Merge V4.0.0 to master", "V4.0.0", "master", new SemanticVersion(4) }, + new object[] { "Merge feature/4.1/one to master", "feature/4.1/one", "master", new SemanticVersion(4, 1) } }; [TestCaseSource(nameof(ParsesTfsEnglishUSMergeMessages))] public void ParsesTfsEnglishUSMessage( - string message, - string expectedMergedBranch, - string expectedTargetBranch, - SemanticVersion expectedVersion) + string message, + string expectedMergedBranch, + string expectedTargetBranch, + SemanticVersion expectedVersion) { // Act var sut = new MergeMessage(message, _config); // Assert - sut.MatchDefinition.ShouldBe("TfsMergeMessageEnglishUS"); + sut.MatchDefinition.ShouldBe("TfsMergeMessageEnglishUS"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeFalse(); @@ -237,7 +237,7 @@ public void ParsesTfsEnglishUSMessage( sut.Version.ShouldBe(expectedVersion); } -private static readonly object[] ParsesTfsGermanDEMergeMessages = + private static readonly object[] ParsesTfsGermanDEMergeMessages = { new object[] { "Zusammengeführter PR \"1234\": feature/one mit master mergen", "feature/one", "master", null, 1234 }, new object[] { "Zusammengeführter PR \"1234\": v://10.10.10.10 mit master mergen", "v://10.10.10.10", "master", null, 1234 }, @@ -248,11 +248,11 @@ public void ParsesTfsEnglishUSMessage( [TestCaseSource(nameof(ParsesTfsGermanDEMergeMessages))] public void ParseTfsGermanDEMessage( - string message, - string expectedMergedBranch, - string expectedTargetBranch, - SemanticVersion expectedVersion, - int? expectedPullRequestNumber) + string message, + string expectedMergedBranch, + string expectedTargetBranch, + SemanticVersion expectedVersion, + int? expectedPullRequestNumber) { // Act var sut = new MergeMessage(message, _config); @@ -268,9 +268,9 @@ public void ParseTfsGermanDEMessage( private static readonly object[] InvalidMergeMessages = { - new object[] { "Merge pull request # from feature/one", "", null, null, null }, - new object[] { "Merge pull request # in feature/one from feature/two to master" , "", null, null, null }, - new object[] { "Zusammengeführter PR : feature/one mit master mergen", "", null, null, null } + new object[] { "Merge pull request # from feature/one", "", null, null, null }, + new object[] { "Merge pull request # in feature/one from feature/two to master" , "", null, null, null }, + new object[] { "Zusammengeführter PR : feature/one mit master mergen", "", null, null, null } }; [TestCaseSource(nameof(InvalidMergeMessages))] From d27bfdd53c361363a1a826dea4b7df4017729461 Mon Sep 17 00:00:00 2001 From: Kieranties Date: Fri, 26 Apr 2019 09:33:08 +0100 Subject: [PATCH 08/11] CR: Refactor MergeMessage to remove private property setters --- src/GitVersionCore/MergeMessage.cs | 68 ++++++++++++------------------ 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/src/GitVersionCore/MergeMessage.cs b/src/GitVersionCore/MergeMessage.cs index 1e6abcf778..7eba60049c 100644 --- a/src/GitVersionCore/MergeMessage.cs +++ b/src/GitVersionCore/MergeMessage.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; namespace GitVersion @@ -22,57 +23,44 @@ public MergeMessage(string mergeMessage, Config config) if (mergeMessage == null) throw new NullReferenceException(); - foreach(var entry in config.MergeMessageFormats) - { - var pattern = Pattern(entry.Key, entry.Value); - if (ApplyPattern(mergeMessage, config.TagPrefix, pattern)) - { - return; - } - } + // Concat config messages with the defaults. + // Ensure configs are processed first. + var allPatterns = config.MergeMessageFormats + .Select(x => Pattern(x.Key, x.Value)) + .Concat(DefaultPatterns); - foreach (var pattern in DefaultPatterns) + foreach (var pattern in allPatterns) { - if (ApplyPattern(mergeMessage, config.TagPrefix, pattern)) + var match = pattern.Value.Match(mergeMessage); + if (match.Success) { - return; - } - } - } + MatchDefinition = pattern.Key; + MergedBranch = match.Groups["SourceBranch"].Value; - public string MatchDefinition { get; private set; } - public string TargetBranch { get; private set; } - public string MergedBranch { get; private set; } = ""; - public bool IsMergedPullRequest => PullRequestNumber != null; - public int? PullRequestNumber { get; private set; } - public SemanticVersion Version { get; private set; } + if (match.Groups["TargetBranch"].Success) + { + TargetBranch = match.Groups["TargetBranch"].Value; + } - private bool ApplyPattern(string mergeMessage, string tagPrefix, KeyValuePair pattern) - { - var match = pattern.Value.Match(mergeMessage); - if (match.Success) - { - MatchDefinition = pattern.Key; - MergedBranch = match.Groups["SourceBranch"].Value; + if (int.TryParse(match.Groups["PullRequestNumber"].Value, out var pullNumber)) + { + PullRequestNumber = pullNumber; + } - if (match.Groups["TargetBranch"].Success) - { - TargetBranch = match.Groups["TargetBranch"].Value; - } + Version = ParseVersion(MergedBranch, config.TagPrefix); - if (int.TryParse(match.Groups["PullRequestNumber"].Value, out var pullNumber)) - { - PullRequestNumber = pullNumber; + break; } - - Version = ParseVersion(MergedBranch, tagPrefix); - - return true; } - - return false; } + public string MatchDefinition { get; } + public string TargetBranch { get; } + public string MergedBranch { get; } = ""; + public bool IsMergedPullRequest => PullRequestNumber != null; + public int? PullRequestNumber { get; } + public SemanticVersion Version { get; } + private SemanticVersion ParseVersion(string branchName, string tagPrefix) { // Remove remotes and branch prefixes like release/ feature/ hotfix/ etc From c22e1ec8ab16e3df559e5ee18bddf1f1c11fe5c3 Mon Sep 17 00:00:00 2001 From: Kieranties Date: Fri, 10 May 2019 18:19:12 +0100 Subject: [PATCH 09/11] Revert "Merge pull request #1591 from asbjornu/feature/tfs-merge-messages" This reverts commit a0a6cc41a94c4bda9866d927423450fb74930615, reversing changes made to 371a896343daadffdb1fea9df78638c0ccdff057. # Conflicts: # src/GitVersionCore/MergeMessage.cs --- src/GitVersionCore.Tests/MergeMessageTests.cs | 57 ------------------- .../MergeMessageBaseVersionStrategyTests.cs | 2 - src/GitVersionCore/MergeMessage.cs | 4 +- 3 files changed, 1 insertion(+), 62 deletions(-) diff --git a/src/GitVersionCore.Tests/MergeMessageTests.cs b/src/GitVersionCore.Tests/MergeMessageTests.cs index 338620a0ea..fa5cfb72c4 100644 --- a/src/GitVersionCore.Tests/MergeMessageTests.cs +++ b/src/GitVersionCore.Tests/MergeMessageTests.cs @@ -209,63 +209,6 @@ public void ParsesRemoteTrackingMergeMessage( sut.Version.ShouldBe(expectedVersion); } - private static readonly object[] ParsesTfsEnglishUSMergeMessages = - { - new object[] { "Merge feature/one to master", "feature/one", "master", null }, - new object[] { "Merge v://10.10.10.10 to master", "v://10.10.10.10", "master", null }, - new object[] { "Merge feature/one to v://10.10.10.10", "feature/one", "v://10.10.10.10", null }, - new object[] { "Merge V4.0.0 to master", "V4.0.0", "master", new SemanticVersion(4) }, - new object[] { "Merge feature/4.1/one to master", "feature/4.1/one", "master", new SemanticVersion(4, 1) } - }; - - [TestCaseSource(nameof(ParsesTfsEnglishUSMergeMessages))] - public void ParsesTfsEnglishUSMessage( - string message, - string expectedMergedBranch, - string expectedTargetBranch, - SemanticVersion expectedVersion) - { - // Act - var sut = new MergeMessage(message, _config); - - // Assert - sut.MatchDefinition.ShouldBe("TfsMergeMessageEnglishUS"); - sut.TargetBranch.ShouldBe(expectedTargetBranch); - sut.MergedBranch.ShouldBe(expectedMergedBranch); - sut.IsMergedPullRequest.ShouldBeFalse(); - sut.PullRequestNumber.ShouldBeNull(); - sut.Version.ShouldBe(expectedVersion); - } - - private static readonly object[] ParsesTfsGermanDEMergeMessages = - { - new object[] { "Zusammengeführter PR \"1234\": feature/one mit master mergen", "feature/one", "master", null, 1234 }, - new object[] { "Zusammengeführter PR \"1234\": v://10.10.10.10 mit master mergen", "v://10.10.10.10", "master", null, 1234 }, - new object[] { "Zusammengeführter PR \"1234\": feature/one mit v://10.10.10.10 mergen", "feature/one", "v://10.10.10.10", null, 1234 }, - new object[] { "Zusammengeführter PR \"1234\": V4.0.0 mit master mergen", "V4.0.0", "master", new SemanticVersion(4), 1234 }, - new object[] { "Zusammengeführter PR \"1234\": feature/4.1/one mit master mergen", "feature/4.1/one", "master", new SemanticVersion(4, 1), 1234 } - }; - - [TestCaseSource(nameof(ParsesTfsGermanDEMergeMessages))] - public void ParseTfsGermanDEMessage( - string message, - string expectedMergedBranch, - string expectedTargetBranch, - SemanticVersion expectedVersion, - int? expectedPullRequestNumber) - { - // Act - var sut = new MergeMessage(message, _config); - - // Assert - sut.MatchDefinition.ShouldBe("TfsMergeMessageGermanDE"); - sut.TargetBranch.ShouldBe(expectedTargetBranch); - sut.MergedBranch.ShouldBe(expectedMergedBranch); - sut.IsMergedPullRequest.ShouldBeTrue(); - sut.PullRequestNumber.ShouldBe(expectedPullRequestNumber); - sut.Version.ShouldBe(expectedVersion); - } - private static readonly object[] InvalidMergeMessages = { new object[] { "Merge pull request # from feature/one", "", null, null, null }, diff --git a/src/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs b/src/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs index 099fc536ba..b5fe2e3e43 100644 --- a/src/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs +++ b/src/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs @@ -47,8 +47,6 @@ public void ShouldNotAllowIncrementOfVersion() [TestCase("Merge branch 'Release-v2.2'", true, "2.2.0")] [TestCase("Merge remote-tracking branch 'origin/release/0.8.0' into develop/master", true, "0.8.0")] [TestCase("Merge remote-tracking branch 'refs/remotes/origin/release/2.0.0'", true, "2.0.0")] - [TestCase("Merge release/5.1.0 to master", true, "5.1.0")] // Team Foundation Server 2017 default merge message (en-US) - [TestCase("Zusammengeführter PR \"9\": release/5.1.0 mit master mergen", true, "5.1.0")] // Team Foundation Server 2017 default merge message (de-DE) public void TakesVersionFromMergeOfReleaseBranch(string message, bool isMergeCommit, string expectedVersion) { var parents = GetParents(isMergeCommit); diff --git a/src/GitVersionCore/MergeMessage.cs b/src/GitVersionCore/MergeMessage.cs index 7eba60049c..42a48ff949 100644 --- a/src/GitVersionCore/MergeMessage.cs +++ b/src/GitVersionCore/MergeMessage.cs @@ -13,9 +13,7 @@ public class MergeMessage Pattern("SmartGit", @"^Finish (?[^\s]*)(?: into (?[^\s]*))*"), Pattern("BitBucketPull", @"^Merge pull request #(?\d+) (from|in) (?.*) from (?[^\s]*) to (?[^\s]*)"), Pattern("GitHubPull", @"^Merge pull request #(?\d+) (from|in) (?:(?[^\s]*))(?: into (?[^\s]*))*"), - Pattern("RemoteTracking", @"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*"), - Pattern("TfsMergeMessageEnglishUS", @"^Merge (?[^\s]*) to (?[^\s]*)"), - Pattern("TfsMergeMessageGermanDE",@"^Zusammengeführter PR ""(?\d+)""\: (?.*) mit (?.*) mergen") + Pattern("RemoteTracking", @"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*") }; public MergeMessage(string mergeMessage, Config config) From 09b656c59ff6dc1f2028a45e898f09349f6f1f84 Mon Sep 17 00:00:00 2001 From: Kieranties Date: Sat, 11 May 2019 10:00:28 +0100 Subject: [PATCH 10/11] CR: Use private class for merge message patterns --- src/GitVersionCore/MergeMessage.cs | 32 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/GitVersionCore/MergeMessage.cs b/src/GitVersionCore/MergeMessage.cs index 42a48ff949..ffe6d4853f 100644 --- a/src/GitVersionCore/MergeMessage.cs +++ b/src/GitVersionCore/MergeMessage.cs @@ -7,13 +7,13 @@ namespace GitVersion { public class MergeMessage { - private static readonly IList> DefaultPatterns = new List> + private static readonly IList DefaultPatterns = new List { - Pattern("Default", @"^Merge (branch|tag) '(?[^']*)'(?: into (?[^\s]*))*"), - Pattern("SmartGit", @"^Finish (?[^\s]*)(?: into (?[^\s]*))*"), - Pattern("BitBucketPull", @"^Merge pull request #(?\d+) (from|in) (?.*) from (?[^\s]*) to (?[^\s]*)"), - Pattern("GitHubPull", @"^Merge pull request #(?\d+) (from|in) (?:(?[^\s]*))(?: into (?[^\s]*))*"), - Pattern("RemoteTracking", @"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*") + new MergeMessagePattern("Default", @"^Merge (branch|tag) '(?[^']*)'(?: into (?[^\s]*))*"), + new MergeMessagePattern("SmartGit", @"^Finish (?[^\s]*)(?: into (?[^\s]*))*"), + new MergeMessagePattern("BitBucketPull", @"^Merge pull request #(?\d+) (from|in) (?.*) from (?[^\s]*) to (?[^\s]*)"), + new MergeMessagePattern("GitHubPull", @"^Merge pull request #(?\d+) (from|in) (?:(?[^\s]*))(?: into (?[^\s]*))*"), + new MergeMessagePattern("RemoteTracking", @"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*") }; public MergeMessage(string mergeMessage, Config config) @@ -24,15 +24,15 @@ public MergeMessage(string mergeMessage, Config config) // Concat config messages with the defaults. // Ensure configs are processed first. var allPatterns = config.MergeMessageFormats - .Select(x => Pattern(x.Key, x.Value)) + .Select(x => new MergeMessagePattern(x.Key, x.Value)) .Concat(DefaultPatterns); foreach (var pattern in allPatterns) { - var match = pattern.Value.Match(mergeMessage); + var match = pattern.Format.Match(mergeMessage); if (match.Success) { - MatchDefinition = pattern.Key; + MatchDefinition = pattern.DefinitionName; MergedBranch = match.Groups["SourceBranch"].Value; if (match.Groups["TargetBranch"].Success) @@ -76,7 +76,17 @@ private SemanticVersion ParseVersion(string branchName, string tagPrefix) return null; } - private static KeyValuePair Pattern(string name, string format) - => new KeyValuePair(name, new Regex(format, RegexOptions.IgnoreCase | RegexOptions.Compiled)); + private class MergeMessagePattern + { + public MergeMessagePattern(string name, string format) + { + DefinitionName = name; + Format = new Regex(format, RegexOptions.IgnoreCase | RegexOptions.Compiled); + } + + public string DefinitionName { get; } + + public Regex Format { get; } + } } } From 629efffabb41f378f253bc253d86ba9c564e6fdb Mon Sep 17 00:00:00 2001 From: Kieranties Date: Sat, 11 May 2019 10:14:41 +0100 Subject: [PATCH 11/11] CR: Clean up naming within MergeMessage class --- src/GitVersionCore.Tests/MergeMessageTests.cs | 20 ++++----- src/GitVersionCore/MergeMessage.cs | 44 +++++++++---------- .../MergeMessageBaseVersionStrategy.cs | 2 +- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/GitVersionCore.Tests/MergeMessageTests.cs b/src/GitVersionCore.Tests/MergeMessageTests.cs index fa5cfb72c4..14b0a18514 100644 --- a/src/GitVersionCore.Tests/MergeMessageTests.cs +++ b/src/GitVersionCore.Tests/MergeMessageTests.cs @@ -75,7 +75,7 @@ public void ParsesMergeMessage( var sut = new MergeMessage(message, _config); // Assert - sut.MatchDefinition.ShouldBe("Default"); + sut.FormatName.ShouldBe("Default"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeFalse(); @@ -106,7 +106,7 @@ public void ParsesGitHubPullMergeMessage( var sut = new MergeMessage(message, _config); // Assert - sut.MatchDefinition.ShouldBe("GitHubPull"); + sut.FormatName.ShouldBe("GitHubPull"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeTrue(); @@ -140,7 +140,7 @@ public void ParsesBitBucketPullMergeMessage( var sut = new MergeMessage(message, _config); // Assert - sut.MatchDefinition.ShouldBe("BitBucketPull"); + sut.FormatName.ShouldBe("BitBucketPull"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeTrue(); @@ -171,7 +171,7 @@ public void ParsesSmartGitMergeMessage( var sut = new MergeMessage(message, _config); // Assert - sut.MatchDefinition.ShouldBe("SmartGit"); + sut.FormatName.ShouldBe("SmartGit"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeFalse(); @@ -201,7 +201,7 @@ public void ParsesRemoteTrackingMergeMessage( var sut = new MergeMessage(message, _config); // Assert - sut.MatchDefinition.ShouldBe("RemoteTracking"); + sut.FormatName.ShouldBe("RemoteTracking"); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeFalse(); @@ -228,7 +228,7 @@ public void ParsesInvalidMergeMessage( var sut = new MergeMessage(message, _config); // Assert - sut.MatchDefinition.ShouldBeNull(); + sut.FormatName.ShouldBeNull(); sut.TargetBranch.ShouldBe(expectedTargetBranch); sut.MergedBranch.ShouldBe(expectedMergedBranch); sut.IsMergedPullRequest.ShouldBeFalse(); @@ -251,7 +251,7 @@ public void MatchesSingleCustomMessage() var sut = new MergeMessage(message, _config); // Assert - sut.MatchDefinition.ShouldBe(definition); + sut.FormatName.ShouldBe(definition); sut.TargetBranch.ShouldBeNull(); sut.MergedBranch.ShouldBeEmpty(); sut.IsMergedPullRequest.ShouldBeFalse(); @@ -276,7 +276,7 @@ public void MatchesMultipleCustomMessages() var sut = new MergeMessage(format, _config); // Assert - sut.MatchDefinition.ShouldBe(definition); + sut.FormatName.ShouldBe(definition); sut.TargetBranch.ShouldBeNull(); sut.MergedBranch.ShouldBeEmpty(); sut.IsMergedPullRequest.ShouldBeFalse(); @@ -303,7 +303,7 @@ public void MatchesCaptureGroupsFromCustomMessages() var sut = new MergeMessage($"Merged PR #{pr} into {target} from {source}", _config); // Assert - sut.MatchDefinition.ShouldBe(definition); + sut.FormatName.ShouldBe(definition); sut.TargetBranch.ShouldBe(target); sut.MergedBranch.ShouldBe(source); sut.IsMergedPullRequest.ShouldBeTrue(); @@ -328,7 +328,7 @@ public void ReturnsAfterFirstMatchingPattern() var sut = new MergeMessage("Merge branch 'this'", _config); // Assert - sut.MatchDefinition.ShouldBe(definition); + sut.FormatName.ShouldBe(definition); sut.TargetBranch.ShouldBeNull(); sut.MergedBranch.ShouldBe("this"); sut.IsMergedPullRequest.ShouldBeFalse(); diff --git a/src/GitVersionCore/MergeMessage.cs b/src/GitVersionCore/MergeMessage.cs index ffe6d4853f..831e3cb31b 100644 --- a/src/GitVersionCore/MergeMessage.cs +++ b/src/GitVersionCore/MergeMessage.cs @@ -7,13 +7,13 @@ namespace GitVersion { public class MergeMessage { - private static readonly IList DefaultPatterns = new List + private static readonly IList DefaultFormats = new List { - new MergeMessagePattern("Default", @"^Merge (branch|tag) '(?[^']*)'(?: into (?[^\s]*))*"), - new MergeMessagePattern("SmartGit", @"^Finish (?[^\s]*)(?: into (?[^\s]*))*"), - new MergeMessagePattern("BitBucketPull", @"^Merge pull request #(?\d+) (from|in) (?.*) from (?[^\s]*) to (?[^\s]*)"), - new MergeMessagePattern("GitHubPull", @"^Merge pull request #(?\d+) (from|in) (?:(?[^\s]*))(?: into (?[^\s]*))*"), - new MergeMessagePattern("RemoteTracking", @"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*") + new MergeMessageFormat("Default", @"^Merge (branch|tag) '(?[^']*)'(?: into (?[^\s]*))*"), + new MergeMessageFormat("SmartGit", @"^Finish (?[^\s]*)(?: into (?[^\s]*))*"), + new MergeMessageFormat("BitBucketPull", @"^Merge pull request #(?\d+) (from|in) (?.*) from (?[^\s]*) to (?[^\s]*)"), + new MergeMessageFormat("GitHubPull", @"^Merge pull request #(?\d+) (from|in) (?:(?[^\s]*))(?: into (?[^\s]*))*"), + new MergeMessageFormat("RemoteTracking", @"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*") }; public MergeMessage(string mergeMessage, Config config) @@ -21,18 +21,18 @@ public MergeMessage(string mergeMessage, Config config) if (mergeMessage == null) throw new NullReferenceException(); - // Concat config messages with the defaults. + // Concat config formats with the defaults. // Ensure configs are processed first. - var allPatterns = config.MergeMessageFormats - .Select(x => new MergeMessagePattern(x.Key, x.Value)) - .Concat(DefaultPatterns); + var allFormats = config.MergeMessageFormats + .Select(x => new MergeMessageFormat(x.Key, x.Value)) + .Concat(DefaultFormats); - foreach (var pattern in allPatterns) + foreach (var format in allFormats) { - var match = pattern.Format.Match(mergeMessage); + var match = format.Pattern.Match(mergeMessage); if (match.Success) { - MatchDefinition = pattern.DefinitionName; + FormatName = format.Name; MergedBranch = match.Groups["SourceBranch"].Value; if (match.Groups["TargetBranch"].Success) @@ -45,21 +45,21 @@ public MergeMessage(string mergeMessage, Config config) PullRequestNumber = pullNumber; } - Version = ParseVersion(MergedBranch, config.TagPrefix); + Version = ParseVersion(config.TagPrefix); break; } } } - public string MatchDefinition { get; } + public string FormatName { get; } public string TargetBranch { get; } public string MergedBranch { get; } = ""; public bool IsMergedPullRequest => PullRequestNumber != null; public int? PullRequestNumber { get; } public SemanticVersion Version { get; } - private SemanticVersion ParseVersion(string branchName, string tagPrefix) + private SemanticVersion ParseVersion(string tagPrefix) { // Remove remotes and branch prefixes like release/ feature/ hotfix/ etc var toMatch = Regex.Replace(MergedBranch, @"^(\w+[-/])*", "", RegexOptions.IgnoreCase); @@ -76,17 +76,17 @@ private SemanticVersion ParseVersion(string branchName, string tagPrefix) return null; } - private class MergeMessagePattern + private class MergeMessageFormat { - public MergeMessagePattern(string name, string format) + public MergeMessageFormat(string name, string pattern) { - DefinitionName = name; - Format = new Regex(format, RegexOptions.IgnoreCase | RegexOptions.Compiled); + Name = name; + Pattern = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); } - public string DefinitionName { get; } + public string Name { get; } - public Regex Format { get; } + public Regex Pattern { get; } } } } diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs index e36eb88133..f5c99450e8 100644 --- a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs +++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs @@ -23,7 +23,7 @@ public override IEnumerable GetVersions(GitVersionContext context) mergeMessage.Version != null && context.FullConfiguration.IsReleaseBranch(TrimRemote(mergeMessage.MergedBranch))) { - Logger.WriteInfo($"Found commit [{context.CurrentCommit.Sha}] matching merge message format: {mergeMessage.MatchDefinition}"); + Logger.WriteInfo($"Found commit [{context.CurrentCommit.Sha}] matching merge message format: {mergeMessage.FormatName}"); var shouldIncrement = !context.Configuration.PreventIncrementForMergedBranchVersion; return new[] {