diff --git a/GitVersionCore.Tests/GitFlow/WikiScenarios.cs b/GitVersionCore.Tests/GitFlow/WikiScenarios.cs index c939c81bc5..847c0fe0d9 100644 --- a/GitVersionCore.Tests/GitFlow/WikiScenarios.cs +++ b/GitVersionCore.Tests/GitFlow/WikiScenarios.cs @@ -76,7 +76,7 @@ public void MinorReleaseExample() // Make a commit after a tag should bump up the beta fixture.Repository.MakeACommit(); - fixture.AssertFullSemver("1.3.0-beta.2+2"); + fixture.AssertFullSemver("1.3.0-beta.2+0"); // Merge release branch to master fixture.Repository.Checkout("master"); diff --git a/GitVersionCore.Tests/GitHubFlow/ReleaseBranchTests.cs b/GitVersionCore.Tests/GitHubFlow/ReleaseBranchTests.cs index 42c36a9a3b..3ae1a23e4f 100644 --- a/GitVersionCore.Tests/GitHubFlow/ReleaseBranchTests.cs +++ b/GitVersionCore.Tests/GitHubFlow/ReleaseBranchTests.cs @@ -57,4 +57,40 @@ public void WhenReleaseBranchIsMergedIntoMasterHighestVersionIsTakenWithIt() fixture.AssertFullSemver("2.0.0+11"); } } + + [Test] + public void WhenMergingReleaseBackToDevShouldNotResetBetaVersion() + { + using (var fixture = new EmptyRepositoryFixture()) + { + const string TaggedVersion = "1.0.3"; + fixture.Repository.MakeATaggedCommit(TaggedVersion); + fixture.Repository.CreateBranch("develop"); + fixture.Repository.Checkout("develop"); + + fixture.Repository.MakeCommits(1); + + fixture.Repository.CreateBranch("release-2.0.0"); + fixture.Repository.Checkout("release-2.0.0"); + fixture.Repository.MakeCommits(1); + + fixture.AssertFullSemver("2.0.0-beta.1+1"); + + //tag it to bump to beta 2 + fixture.Repository.ApplyTag("2.0.0-beta1"); + + fixture.Repository.MakeCommits(1); + + fixture.AssertFullSemver("2.0.0-beta.2+0"); + + //merge down to develop + fixture.Repository.Checkout("develop"); + fixture.Repository.MergeNoFF("release-2.0.0", Constants.SignatureNow()); + + //but keep working on the release + fixture.Repository.Checkout("release-2.0.0"); + + fixture.AssertFullSemver("2.0.0-beta.2+0"); + } + } } \ No newline at end of file diff --git a/GitVersionCore/GitFlow/BranchFinders/BranchCommitDifferenceFinder.cs b/GitVersionCore/GitFlow/BranchFinders/BranchCommitDifferenceFinder.cs index 0828ba7eaa..88e91e1ad5 100644 --- a/GitVersionCore/GitFlow/BranchFinders/BranchCommitDifferenceFinder.cs +++ b/GitVersionCore/GitFlow/BranchFinders/BranchCommitDifferenceFinder.cs @@ -1,5 +1,6 @@ namespace GitVersion { + using System.Collections.Generic; using System.Linq; using LibGit2Sharp; @@ -34,5 +35,38 @@ public static int NumberOfCommitsInBranchNotKnownFromBaseBranch(IRepository repo return repo.Commits.QueryBy(filter) .Count(); } + + public static int NumberOfCommitsSinceLastTagOrBranchPoint(GitVersionContext context, List tagsInDescendingOrder, BranchType branchType, string baseBranchName) + { + if (!tagsInDescendingOrder.Any()) + { + return NumberOfCommitsInBranchNotKnownFromBaseBranch(context.Repository, context.CurrentBranch, branchType, baseBranchName); + } + + var mostRecentTag = tagsInDescendingOrder.First(); + var ancestor = mostRecentTag; + if (mostRecentTag.Target == context.CurrentCommit) + { + var previousTag = tagsInDescendingOrder.Skip(1).FirstOrDefault(); + if (previousTag != null) + { + ancestor = previousTag; + } + else + { + return NumberOfCommitsInBranchNotKnownFromBaseBranch(context.Repository, context.CurrentBranch, BranchType.Release, baseBranchName); + } + + } + + var filter = new CommitFilter + { + Since = context.CurrentCommit, + Until = ancestor.Target, + SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Time + }; + + return context.Repository.Commits.QueryBy(filter).Count() - 1; + } } } \ No newline at end of file diff --git a/GitVersionCore/GitFlow/BranchFinders/HotfixVersionFinder.cs b/GitVersionCore/GitFlow/BranchFinders/HotfixVersionFinder.cs index 5af628acc4..2549009189 100644 --- a/GitVersionCore/GitFlow/BranchFinders/HotfixVersionFinder.cs +++ b/GitVersionCore/GitFlow/BranchFinders/HotfixVersionFinder.cs @@ -1,6 +1,5 @@ namespace GitVersion { - using System.Linq; using LibGit2Sharp; class HotfixVersionFinder @@ -28,7 +27,7 @@ public SemanticVersion FindVersion(GitVersionContext context) static string GetSemanticVersionPreReleaseTag(GitVersionContext context, ShortVersion shortVersion, int nbHotfixCommits) { var semanticVersionPreReleaseTag = "beta.1"; - var tagVersion = RecentTagVersionExtractor.RetrieveMostRecentOptionalTagVersion(context.Repository, shortVersion, context.CurrentBranch.Commits.Take(nbHotfixCommits + 1)); + var tagVersion = RecentTagVersionExtractor.RetrieveMostRecentOptionalTagVersion(context, shortVersion); if (tagVersion != null) { semanticVersionPreReleaseTag = tagVersion; diff --git a/GitVersionCore/GitFlow/BranchFinders/RecentTagVersionExtractor.cs b/GitVersionCore/GitFlow/BranchFinders/RecentTagVersionExtractor.cs index 49fe3e8a28..c0f13a4226 100644 --- a/GitVersionCore/GitFlow/BranchFinders/RecentTagVersionExtractor.cs +++ b/GitVersionCore/GitFlow/BranchFinders/RecentTagVersionExtractor.cs @@ -1,46 +1,33 @@ namespace GitVersion { using System.Collections.Generic; + using System.Linq; using LibGit2Sharp; class RecentTagVersionExtractor { - internal static SemanticVersionPreReleaseTag RetrieveMostRecentOptionalTagVersion(IRepository repository, ShortVersion matchVersion, IEnumerable take) + internal static SemanticVersionPreReleaseTag RetrieveMostRecentOptionalTagVersion(GitVersionContext context, ShortVersion matchVersion) { - Commit first = null; - foreach (var commit in take) + var tagsInDescendingOrder = context.Repository.SemVerTagsRelatedToVersion(matchVersion).OrderByDescending(tag => SemanticVersion.Parse(tag.Name)); + return RetrieveMostRecentOptionalTagVersion(context, tagsInDescendingOrder.ToList()); + } + + internal static SemanticVersionPreReleaseTag RetrieveMostRecentOptionalTagVersion(GitVersionContext context, List applicableTagsInDescendingOrder) + { + if (applicableTagsInDescendingOrder.Any()) { - if (first == null) + var taggedCommit = applicableTagsInDescendingOrder.First().Target; + var preReleaseVersion = applicableTagsInDescendingOrder.Select(tag => SemanticVersion.Parse(tag.Name)).FirstOrDefault(); + if (preReleaseVersion != null) { - first = commit; - } - foreach (var tag in repository.TagsByDate(commit)) - { - SemanticVersion version; - if (!SemanticVersion.TryParse(tag.Name, out version)) - { - continue; - } - - if (matchVersion.Major == version.Major && - matchVersion.Minor == version.Minor && - matchVersion.Patch == version.Patch) + if (taggedCommit != context.CurrentCommit) { - var preReleaseTag = version.PreReleaseTag; - - //If the tag is on the eact commit then dont bump the PreReleaseTag - if (first != commit) - { - preReleaseTag.Number++; - } - return preReleaseTag; + preReleaseVersion.PreReleaseTag.Number++; } + return preReleaseVersion.PreReleaseTag; } } - return null; } - - } } \ No newline at end of file diff --git a/GitVersionCore/GitFlow/BranchFinders/ReleaseVersionFinder.cs b/GitVersionCore/GitFlow/BranchFinders/ReleaseVersionFinder.cs index 04fa53515e..3df165d776 100644 --- a/GitVersionCore/GitFlow/BranchFinders/ReleaseVersionFinder.cs +++ b/GitVersionCore/GitFlow/BranchFinders/ReleaseVersionFinder.cs @@ -11,26 +11,22 @@ public SemanticVersion FindVersion(GitVersionContext context) var shortVersion = ShortVersionParser.Parse(versionString); EnsureVersionIsValid(shortVersion, context.CurrentBranch); - var semanticVersionPreReleaseTag = "beta.1"; - - var nbHotfixCommits = BranchCommitDifferenceFinder.NumberOfCommitsInBranchNotKnownFromBaseBranch(context.Repository, context.CurrentBranch, BranchType.Release, "develop"); - var tagVersion = RecentTagVersionExtractor.RetrieveMostRecentOptionalTagVersion(context.Repository, shortVersion, context.CurrentBranch.Commits.Take(nbHotfixCommits + 1)); - if (tagVersion != null) - { - semanticVersionPreReleaseTag = tagVersion; - } + var applicableTagsInDescendingOrder = context.Repository.SemVerTagsRelatedToVersion(shortVersion).OrderByDescending(tag => SemanticVersion.Parse(tag.Name)).ToList(); + var numberOfCommitsSinceLastTagOrBranchPoint = BranchCommitDifferenceFinder.NumberOfCommitsSinceLastTagOrBranchPoint(context, applicableTagsInDescendingOrder, BranchType.Release, "develop"); + var semanticVersionPreReleaseTag = RecentTagVersionExtractor.RetrieveMostRecentOptionalTagVersion(context, applicableTagsInDescendingOrder) ?? "beta.1"; + return new SemanticVersion { Major = shortVersion.Major, Minor = shortVersion.Minor, Patch = shortVersion.Patch, PreReleaseTag = semanticVersionPreReleaseTag, - BuildMetaData = new SemanticVersionBuildMetaData(nbHotfixCommits, context.CurrentBranch.Name, context.CurrentCommit.Sha, context.CurrentCommit.When()) + BuildMetaData = new SemanticVersionBuildMetaData(numberOfCommitsSinceLastTagOrBranchPoint, context.CurrentBranch.Name, context.CurrentCommit.Sha, context.CurrentCommit.When()) }; } - void EnsureVersionIsValid(ShortVersion version, Branch branch) + static void EnsureVersionIsValid(ShortVersion version, Branch branch) { if (version.Patch != 0) { diff --git a/GitVersionCore/GitHubFlow/OtherBranchVersionFinder.cs b/GitVersionCore/GitHubFlow/OtherBranchVersionFinder.cs index 0ca5a9e84c..a26c670ea3 100644 --- a/GitVersionCore/GitHubFlow/OtherBranchVersionFinder.cs +++ b/GitVersionCore/GitHubFlow/OtherBranchVersionFinder.cs @@ -15,15 +15,11 @@ public bool FindVersion(GitVersionContext context, out SemanticVersion semanticV } var shortVersion = ShortVersionParser.Parse(versionString); - SemanticVersionPreReleaseTag semanticVersionPreReleaseTag = context.CurrentBranch.Name.Replace("-" + versionString, string.Empty) + ".1"; - var nbHotfixCommits = BranchCommitDifferenceFinder.NumberOfCommitsInBranchNotKnownFromBaseBranch(context.Repository, context.CurrentBranch, BranchType.Unknown, "master"); + var applicableTagsInDescendingOrder = context.Repository.SemVerTagsRelatedToVersion(shortVersion).OrderByDescending(tag => SemanticVersion.Parse(tag.Name)).ToList(); + var nbHotfixCommits = BranchCommitDifferenceFinder.NumberOfCommitsSinceLastTagOrBranchPoint(context, applicableTagsInDescendingOrder, BranchType.Unknown, "master"); + var semanticVersionPreReleaseTag = RecentTagVersionExtractor.RetrieveMostRecentOptionalTagVersion(context, applicableTagsInDescendingOrder) ?? CreateDefaultPreReleaseTag(context, versionString); - var tagVersion = RecentTagVersionExtractor.RetrieveMostRecentOptionalTagVersion(context.Repository, shortVersion, context.CurrentBranch.Commits.Take(nbHotfixCommits + 1)); - if (tagVersion != null) - { - semanticVersionPreReleaseTag = tagVersion; - } if (semanticVersionPreReleaseTag.Name == "release") { @@ -41,6 +37,11 @@ public bool FindVersion(GitVersionContext context, out SemanticVersion semanticV return true; } + SemanticVersionPreReleaseTag CreateDefaultPreReleaseTag(GitVersionContext context, string versionString) + { + return context.CurrentBranch.Name.Replace("-" + versionString, string.Empty) + ".1"; + } + static string GetUnknownBranchSuffix(Branch branch) { var unknownBranchSuffix = branch.Name.Split('-', '/'); diff --git a/GitVersionCore/LibGitExtensions.cs b/GitVersionCore/LibGitExtensions.cs index 7bc4f92f89..36c0d31c78 100644 --- a/GitVersionCore/LibGitExtensions.cs +++ b/GitVersionCore/LibGitExtensions.cs @@ -39,6 +39,23 @@ public static IEnumerable TagsByDate(this IRepository repository, Commit co }); } + public static IEnumerable SemVerTagsRelatedToVersion(this IRepository repository, ShortVersion version) + { + foreach (var tag in repository.Tags) + { + SemanticVersion tagVersion; + if (SemanticVersion.TryParse(tag.Name, out tagVersion)) + { + if (version.Major == tagVersion.Major && + version.Minor == tagVersion.Minor && + version.Patch == tagVersion.Patch) + { + yield return tag; + } + } + } + } + public static GitObject PeeledTarget(this Tag tag) { var target = tag.Target;