Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure track-merge-target: Strategy which will look for tagged merge commits directly off the current branch #3406

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,28 @@ public void BranchesWithIllegalCharsShouldNotBeUsedInVersionNames()
[Test]
public void ShouldNotGetVersionFromFeatureBranchIfNotMerged()
{
// * 1c08923 54 minutes ago (HEAD -> develop)
// | * 03dd6d5 56 minutes ago (tag: 1.0.1-feature.1, feature)
// |/
// * e2ff13b 58 minutes ago (tag: 1.0.0-unstable.0, main)

var configuration = GitFlowConfigurationBuilder.New
.WithBranch("develop", builder => builder.WithTrackMergeTarget(false))
.Build();

using var fixture = new EmptyRepositoryFixture();
fixture.Repository.MakeATaggedCommit("1.0.0-unstable.0"); // initial commit in main

fixture.Repository.CreateBranch("feature");
Commands.Checkout(fixture.Repository, "feature");
fixture.Repository.MakeATaggedCommit("1.0.1-feature.1");
fixture.MakeATaggedCommit("1.0.0-unstable.0"); // initial commit in main

Commands.Checkout(fixture.Repository, MainBranch);
fixture.Repository.CreateBranch("develop");
Commands.Checkout(fixture.Repository, "develop");
fixture.BranchTo("feature");
fixture.MakeATaggedCommit("1.0.1-feature.1");
fixture.Checkout(MainBranch);
fixture.BranchTo("develop");
fixture.Repository.MakeACommit();

var version = fixture.GetVersion();
version.SemVer.ShouldBe("1.0.0-alpha.1");
fixture.AssertFullSemver("1.0.0-alpha.1", configuration);

fixture.Repository.DumpGraph();
}

[TestCase("alpha", "JIRA-123", "alpha")]
Expand Down
35 changes: 35 additions & 0 deletions src/GitVersion.Core.Tests/IntegrationTests/OtherScenarios.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Globalization;
using GitVersion.Configuration;
using GitVersion.Core.Tests.Helpers;
using GitVersion.Helpers;
using LibGit2Sharp;
Expand Down Expand Up @@ -127,4 +128,38 @@ public void NoDirtyFlagInCleanRepository()
const int zero = 0;
version.UncommittedChanges.ShouldBe(zero.ToString(CultureInfo.InvariantCulture));
}

[TestCase(false, "1.1.0-alpha.2")]
[TestCase(true, "1.2.0-alpha.1")]
public void EnusreTrackMergeTargetStrategyWhichWillLookForTaggedMergecommits(bool trackMergeTarget, string expectedVersion)
{
// * 9daa6ea 53 minutes ago (HEAD -> develop)
// | * 85536f2 55 minutes ago (tag: 1.1.0, main)
// | |\
// | |/
// |/|
// * | 4a5ef1a 56 minutes ago
// |/
// * c7f68af 58 minutes ago (tag: 1.0.0)

var configuration = GitFlowConfigurationBuilder.New
.WithBranch("main", builder => builder.WithIsMainline(false))
.WithBranch("develop", builder => builder
.WithTrackMergeTarget(trackMergeTarget).WithTracksReleaseBranches(false)
).Build();

using var fixture = new EmptyRepositoryFixture();
fixture.MakeATaggedCommit("1.0.0");
fixture.BranchTo("develop");
fixture.MakeACommit();
fixture.Checkout("main");
fixture.MergeNoFF("develop");
fixture.ApplyTag("1.1.0");
fixture.Checkout("develop");
fixture.MakeACommit();

fixture.AssertFullSemver(expectedVersion, configuration);

fixture.Repository.DumpGraph();
}
}
4 changes: 2 additions & 2 deletions src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public interface IRepositoryStore
IBranch GetTargetBranch(string? targetBranchName);
IBranch? FindBranch(string? branchName);
IBranch? FindMainBranch(GitVersionConfiguration configuration);
IEnumerable<IBranch> FindMainlineBranches(GitVersionConfiguration configuration);
IEnumerable<IBranch> GetReleaseBranches(IEnumerable<KeyValuePair<string, BranchConfiguration>> releaseBranchConfig);
IEnumerable<IBranch> ExcludingBranches(IEnumerable<IBranch> branchesToExclude);
IEnumerable<IBranch> GetBranchesContainingCommit(ICommit? commit, IEnumerable<IBranch>? branches = null, bool onlyTrackedBranches = false);
Expand All @@ -41,8 +42,7 @@ public interface IRepositoryStore
SemanticVersion? GetCurrentCommitTaggedVersion(ICommit? commit, string? tagPrefix, SemanticVersionFormat versionFormat, bool handleDetachedBranch);

IEnumerable<SemanticVersion> GetVersionTagsOnBranch(IBranch branch, string? tagPrefixRegex, SemanticVersionFormat versionFormat);
IEnumerable<(ITag Tag, SemanticVersion Semver, ICommit Commit)> GetValidVersionTags(string? tagPrefixRegex, SemanticVersionFormat versionFormat, DateTimeOffset? olderThan = null);

IEnumerable<SemanticVersionWithTag> GetSemanticVersionFromTags(string? tagPrefixRegex, SemanticVersionFormat semanticVersionFormat);
bool IsCommitOnBranch(ICommit? baseVersionSource, IBranch branch, ICommit firstMatchingCommit);

int GetNumberOfUncommittedChanges();
Expand Down
6 changes: 3 additions & 3 deletions src/GitVersion.Core/Core/MergeCommitFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace GitVersion;

internal class MergeCommitFinder
{
private readonly IEnumerable<IBranch> excludedBranches;
private readonly IEnumerable<IBranch> branches;
private readonly ILog log;
private readonly Dictionary<IBranch, List<BranchCommit>> mergeBaseCommitsCache = new();
private readonly RepositoryStore repositoryStore;
Expand All @@ -16,7 +16,7 @@ public MergeCommitFinder(RepositoryStore repositoryStore, GitVersionConfiguratio
{
this.repositoryStore = repositoryStore.NotNull();
this.configuration = configuration.NotNull();
this.excludedBranches = repositoryStore.ExcludingBranches(excludedBranches.NotNull());
this.branches = repositoryStore.ExcludingBranches(excludedBranches.NotNull());
this.log = log.NotNull();
}

Expand All @@ -41,7 +41,7 @@ public IEnumerable<BranchCommit> FindMergeCommitsFor(IBranch branch)

private IEnumerable<BranchCommit> FindMergeBases(IBranch branch)
{
var sourceBranches = new SourceBranchFinder(this.excludedBranches, this.configuration)
var sourceBranches = new SourceBranchFinder(this.branches, this.configuration)
.FindSourceBranchesOf(branch);

foreach (var sourceBranch in sourceBranches)
Expand Down
52 changes: 25 additions & 27 deletions src/GitVersion.Core/Core/RepositoryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public IBranch GetTargetBranch(string? targetBranchName)
public IBranch? FindMainBranch(GitVersionConfiguration configuration)
{
var mainBranchRegex = configuration.Branches[ConfigurationConstants.MainBranchKey].Regex
?? configuration.Branches[ConfigurationConstants.MasterBranchKey].Regex;
?? configuration.Branches[ConfigurationConstants.MasterBranchKey].Regex;

if (mainBranchRegex == null)
{
Expand All @@ -118,6 +118,20 @@ public IBranch GetTargetBranch(string? targetBranchName)
Regex.IsMatch(b.Name.Friendly, mainBranchRegex, RegexOptions.IgnoreCase));
}

public IEnumerable<IBranch> FindMainlineBranches(GitVersionConfiguration configuration)
{
configuration.NotNull();

foreach (var branch in this.repository.Branches)
{
var branchConfiguration = configuration.GetBranchConfiguration(branch);
if (branchConfiguration.IsMainline == true)
{
yield return branch;
}
}
}

public IEnumerable<IBranch> GetReleaseBranches(IEnumerable<KeyValuePair<string, BranchConfiguration>> releaseBranchConfig)
=> this.repository.Branches.Where(b => IsReleaseBranch(b, releaseBranchConfig));

Expand Down Expand Up @@ -243,37 +257,25 @@ public IEnumerable<SemanticVersion> GetVersionTagsOnBranch(IBranch branch, strin

using (this.log.IndentLog($"Getting version tags from branch '{branch.Name.Canonical}'."))
{
var tags = GetValidVersionTags(tagPrefixRegex, versionFormat);
var tagsBySha = tags.Where(t => t.Tag.TargetSha != null).ToLookup(t => t.Tag.TargetSha, t => t);
var semanticVersions = GetSemanticVersionFromTags(tagPrefixRegex, versionFormat);
var tagsBySha = semanticVersions.Where(t => t.Tag.TargetSha != null).ToLookup(t => t.Tag.TargetSha, t => t);

var versionTags = (branch.Commits?.SelectMany(c => tagsBySha[c.Sha].Select(t => t.Semver)) ?? Enumerable.Empty<SemanticVersion>()).ToList();
var versionTags = (branch.Commits?.SelectMany(c => tagsBySha[c.Sha].Select(t => t.Value)) ?? Enumerable.Empty<SemanticVersion>()).ToList();

this.semanticVersionTagsOnBranchCache.Add(branch, versionTags);
return versionTags;
}
}

public IEnumerable<(ITag Tag, SemanticVersion Semver, ICommit Commit)> GetValidVersionTags(string? tagPrefixRegex, SemanticVersionFormat versionFormat, DateTimeOffset? olderThan = null)
public IEnumerable<SemanticVersionWithTag> GetSemanticVersionFromTags(string? tagPrefixRegex, SemanticVersionFormat semanticVersionFormat)
{
var tags = new List<(ITag, SemanticVersion, ICommit)>();

foreach (var tag in this.repository.Tags)
{
if (!SemanticVersion.TryParse(tag.Name.Friendly, tagPrefixRegex, out var semver, versionFormat))
continue;

var commit = tag.PeeledTargetCommit();

if (commit == null)
continue;

if (olderThan.HasValue && commit.When > olderThan.Value)
continue;

tags.Add((tag, semver, commit));
if (SemanticVersion.TryParse(tag.Name.Friendly, tagPrefixRegex, out var semanticVersion, semanticVersionFormat))
{
yield return new SemanticVersionWithTag(semanticVersion, tag);
}
}

return tags;
}

public IEnumerable<ICommit> GetCommitLog(ICommit? baseVersionSource, ICommit? currentCommit)
Expand Down Expand Up @@ -302,15 +304,11 @@ private IEnumerable<SemanticVersion> GetCurrentCommitSemanticVersions(ICommit? c
if (commit == null)
return Array.Empty<SemanticVersion>();

var targetCommit = tag.PeeledTargetCommit();
if (targetCommit == null)
return Array.Empty<SemanticVersion>();

var commitToCompare = handleDetachedBranch ? FindMergeBase(commit, targetCommit) : commit;
var commitToCompare = handleDetachedBranch ? FindMergeBase(commit, tag.Commit) : commit;

var tagName = tag.Name.Friendly;

return Equals(targetCommit, commitToCompare) && SemanticVersion.TryParse(tagName, tagPrefix, out var version, versionFormat)
return Equals(tag.Commit, commitToCompare) && SemanticVersion.TryParse(tagName, tagPrefix, out var version, versionFormat)
? new[] { version }
: Array.Empty<SemanticVersion>();
}
Expand Down
3 changes: 2 additions & 1 deletion src/GitVersion.Core/Git/ITag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ namespace GitVersion;
public interface ITag : IEquatable<ITag?>, IComparable<ITag>, INamedReference
{
string? TargetSha { get; }
ICommit? PeeledTargetCommit();

ICommit Commit { get; }
}
5 changes: 3 additions & 2 deletions src/GitVersion.Core/GitVersionContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using GitVersion.Configuration;
using GitVersion.Extensions;

namespace GitVersion;

Expand All @@ -25,9 +26,9 @@ public class GitVersionContext
public GitVersionContext(IBranch currentBranch, ICommit? currentCommit,
GitVersionConfiguration configuration, SemanticVersion? currentCommitTaggedVersion, int numberOfUncommittedChanges)
{
CurrentBranch = currentBranch;
CurrentBranch = currentBranch.NotNull();
CurrentCommit = currentCommit;
Configuration = configuration;
Configuration = configuration.NotNull();
CurrentCommitTaggedVersion = currentCommitTaggedVersion;
NumberOfUncommittedChanges = numberOfUncommittedChanges;
}
Expand Down
Loading