diff --git a/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs index efcec62241..c8d6109fa2 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs @@ -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")] diff --git a/src/GitVersion.Core.Tests/IntegrationTests/OtherScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/OtherScenarios.cs index 8b669025f7..608b0e3865 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/OtherScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/OtherScenarios.cs @@ -1,4 +1,5 @@ using System.Globalization; +using GitVersion.Configuration; using GitVersion.Core.Tests.Helpers; using GitVersion.Helpers; using LibGit2Sharp; @@ -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(); + } } diff --git a/src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs b/src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs index 99ef2f36bf..75dcf38a6e 100644 --- a/src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs +++ b/src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs @@ -18,6 +18,7 @@ public interface IRepositoryStore IBranch GetTargetBranch(string? targetBranchName); IBranch? FindBranch(string? branchName); IBranch? FindMainBranch(GitVersionConfiguration configuration); + IEnumerable FindMainlineBranches(GitVersionConfiguration configuration); IEnumerable GetReleaseBranches(IEnumerable> releaseBranchConfig); IEnumerable ExcludingBranches(IEnumerable branchesToExclude); IEnumerable GetBranchesContainingCommit(ICommit? commit, IEnumerable? branches = null, bool onlyTrackedBranches = false); @@ -41,8 +42,7 @@ public interface IRepositoryStore SemanticVersion? GetCurrentCommitTaggedVersion(ICommit? commit, string? tagPrefix, SemanticVersionFormat versionFormat, bool handleDetachedBranch); IEnumerable GetVersionTagsOnBranch(IBranch branch, string? tagPrefixRegex, SemanticVersionFormat versionFormat); - IEnumerable<(ITag Tag, SemanticVersion Semver, ICommit Commit)> GetValidVersionTags(string? tagPrefixRegex, SemanticVersionFormat versionFormat, DateTimeOffset? olderThan = null); - + IEnumerable GetSemanticVersionFromTags(string? tagPrefixRegex, SemanticVersionFormat semanticVersionFormat); bool IsCommitOnBranch(ICommit? baseVersionSource, IBranch branch, ICommit firstMatchingCommit); int GetNumberOfUncommittedChanges(); diff --git a/src/GitVersion.Core/Core/MergeCommitFinder.cs b/src/GitVersion.Core/Core/MergeCommitFinder.cs index 11e682dc81..555541fa8e 100644 --- a/src/GitVersion.Core/Core/MergeCommitFinder.cs +++ b/src/GitVersion.Core/Core/MergeCommitFinder.cs @@ -6,7 +6,7 @@ namespace GitVersion; internal class MergeCommitFinder { - private readonly IEnumerable excludedBranches; + private readonly IEnumerable branches; private readonly ILog log; private readonly Dictionary> mergeBaseCommitsCache = new(); private readonly RepositoryStore repositoryStore; @@ -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(); } @@ -41,7 +41,7 @@ public IEnumerable FindMergeCommitsFor(IBranch branch) private IEnumerable 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) diff --git a/src/GitVersion.Core/Core/RepositoryStore.cs b/src/GitVersion.Core/Core/RepositoryStore.cs index 062cfe1a8f..f74572d7f9 100644 --- a/src/GitVersion.Core/Core/RepositoryStore.cs +++ b/src/GitVersion.Core/Core/RepositoryStore.cs @@ -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) { @@ -118,6 +118,20 @@ public IBranch GetTargetBranch(string? targetBranchName) Regex.IsMatch(b.Name.Friendly, mainBranchRegex, RegexOptions.IgnoreCase)); } + public IEnumerable 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 GetReleaseBranches(IEnumerable> releaseBranchConfig) => this.repository.Branches.Where(b => IsReleaseBranch(b, releaseBranchConfig)); @@ -243,37 +257,25 @@ public IEnumerable 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()).ToList(); + var versionTags = (branch.Commits?.SelectMany(c => tagsBySha[c.Sha].Select(t => t.Value)) ?? Enumerable.Empty()).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 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 GetCommitLog(ICommit? baseVersionSource, ICommit? currentCommit) @@ -302,15 +304,11 @@ private IEnumerable GetCurrentCommitSemanticVersions(ICommit? c if (commit == null) return Array.Empty(); - var targetCommit = tag.PeeledTargetCommit(); - if (targetCommit == null) - return Array.Empty(); - - 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(); } diff --git a/src/GitVersion.Core/Git/ITag.cs b/src/GitVersion.Core/Git/ITag.cs index adf08a549f..c856aab033 100644 --- a/src/GitVersion.Core/Git/ITag.cs +++ b/src/GitVersion.Core/Git/ITag.cs @@ -3,5 +3,6 @@ namespace GitVersion; public interface ITag : IEquatable, IComparable, INamedReference { string? TargetSha { get; } - ICommit? PeeledTargetCommit(); + + ICommit Commit { get; } } diff --git a/src/GitVersion.Core/GitVersionContext.cs b/src/GitVersion.Core/GitVersionContext.cs index 8c694fcff0..3700008425 100644 --- a/src/GitVersion.Core/GitVersionContext.cs +++ b/src/GitVersion.Core/GitVersionContext.cs @@ -1,4 +1,5 @@ using GitVersion.Configuration; +using GitVersion.Extensions; namespace GitVersion; @@ -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; } diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt index 8dc3b064c0..97d5384b23 100644 --- a/src/GitVersion.Core/PublicAPI.Unshipped.txt +++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt @@ -72,6 +72,7 @@ GitVersion.Common.IRepositoryStore.FindCommitBranchWasBranchedFrom(GitVersion.IB GitVersion.Common.IRepositoryStore.FindCommitBranchesWasBranchedFrom(GitVersion.IBranch! branch, GitVersion.Configuration.GitVersionConfiguration! configuration, System.Collections.Generic.IEnumerable! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.FindCommitBranchesWasBranchedFrom(GitVersion.IBranch! branch, GitVersion.Configuration.GitVersionConfiguration! configuration, params GitVersion.IBranch![]! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.FindMainBranch(GitVersion.Configuration.GitVersionConfiguration! configuration) -> GitVersion.IBranch? +GitVersion.Common.IRepositoryStore.FindMainlineBranches(GitVersion.Configuration.GitVersionConfiguration! configuration) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.FindMergeBase(GitVersion.IBranch? branch, GitVersion.IBranch? otherBranch) -> GitVersion.ICommit? GitVersion.Common.IRepositoryStore.FindMergeBase(GitVersion.ICommit! commit, GitVersion.ICommit! mainlineTip) -> GitVersion.ICommit? GitVersion.Common.IRepositoryStore.GetBranchesContainingCommit(GitVersion.ICommit? commit, System.Collections.Generic.IEnumerable? branches = null, bool onlyTrackedBranches = false) -> System.Collections.Generic.IEnumerable! @@ -83,10 +84,10 @@ GitVersion.Common.IRepositoryStore.GetMainlineCommitLog(GitVersion.ICommit? base GitVersion.Common.IRepositoryStore.GetMergeBaseCommits(GitVersion.ICommit? mergeCommit, GitVersion.ICommit? mergedHead, GitVersion.ICommit? findMergeBase) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.GetNumberOfUncommittedChanges() -> int GitVersion.Common.IRepositoryStore.GetReleaseBranches(System.Collections.Generic.IEnumerable>! releaseBranchConfig) -> System.Collections.Generic.IEnumerable! +GitVersion.Common.IRepositoryStore.GetSemanticVersionFromTags(string? tagPrefixRegex, GitVersion.SemanticVersionFormat semanticVersionFormat) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.GetSourceBranches(GitVersion.IBranch! branch, GitVersion.Configuration.GitVersionConfiguration! configuration, System.Collections.Generic.IEnumerable! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.GetSourceBranches(GitVersion.IBranch! branch, GitVersion.Configuration.GitVersionConfiguration! configuration, params GitVersion.IBranch![]! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.GetTargetBranch(string? targetBranchName) -> GitVersion.IBranch! -GitVersion.Common.IRepositoryStore.GetValidVersionTags(string? tagPrefixRegex, GitVersion.SemanticVersionFormat versionFormat, System.DateTimeOffset? olderThan = null) -> System.Collections.Generic.IEnumerable<(GitVersion.ITag! Tag, GitVersion.SemanticVersion! Semver, GitVersion.ICommit! Commit)>! GitVersion.Common.IRepositoryStore.GetVersionTagsOnBranch(GitVersion.IBranch! branch, string? tagPrefixRegex, GitVersion.SemanticVersionFormat versionFormat) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.IsCommitOnBranch(GitVersion.ICommit? baseVersionSource, GitVersion.IBranch! branch, GitVersion.ICommit! firstMatchingCommit) -> bool GitVersion.Configuration.BranchConfiguration @@ -528,7 +529,7 @@ GitVersion.IRemoteCollection.Remove(string! remoteName) -> void GitVersion.IRemoteCollection.Update(string! remoteName, string! refSpec) -> void GitVersion.IRemoteCollection.this[string! name].get -> GitVersion.IRemote? GitVersion.ITag -GitVersion.ITag.PeeledTargetCommit() -> GitVersion.ICommit? +GitVersion.ITag.Commit.get -> GitVersion.ICommit! GitVersion.ITag.TargetSha.get -> string? GitVersion.ITagCollection GitVersion.IVersionConverter @@ -730,6 +731,7 @@ GitVersion.RepositoryStore.FindCommitBranchWasBranchedFrom(GitVersion.IBranch? b GitVersion.RepositoryStore.FindCommitBranchesWasBranchedFrom(GitVersion.IBranch! branch, GitVersion.Configuration.GitVersionConfiguration! configuration, System.Collections.Generic.IEnumerable! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.RepositoryStore.FindCommitBranchesWasBranchedFrom(GitVersion.IBranch! branch, GitVersion.Configuration.GitVersionConfiguration! configuration, params GitVersion.IBranch![]! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.RepositoryStore.FindMainBranch(GitVersion.Configuration.GitVersionConfiguration! configuration) -> GitVersion.IBranch? +GitVersion.RepositoryStore.FindMainlineBranches(GitVersion.Configuration.GitVersionConfiguration! configuration) -> System.Collections.Generic.IEnumerable! GitVersion.RepositoryStore.FindMergeBase(GitVersion.IBranch? branch, GitVersion.IBranch? otherBranch) -> GitVersion.ICommit? GitVersion.RepositoryStore.FindMergeBase(GitVersion.ICommit! commit, GitVersion.ICommit! mainlineTip) -> GitVersion.ICommit? GitVersion.RepositoryStore.GetBranchesContainingCommit(GitVersion.ICommit? commit, System.Collections.Generic.IEnumerable? branches = null, bool onlyTrackedBranches = false) -> System.Collections.Generic.IEnumerable! @@ -741,10 +743,10 @@ GitVersion.RepositoryStore.GetMainlineCommitLog(GitVersion.ICommit? baseVersionS GitVersion.RepositoryStore.GetMergeBaseCommits(GitVersion.ICommit? mergeCommit, GitVersion.ICommit? mergedHead, GitVersion.ICommit? findMergeBase) -> System.Collections.Generic.IEnumerable! GitVersion.RepositoryStore.GetNumberOfUncommittedChanges() -> int GitVersion.RepositoryStore.GetReleaseBranches(System.Collections.Generic.IEnumerable>! releaseBranchConfig) -> System.Collections.Generic.IEnumerable! +GitVersion.RepositoryStore.GetSemanticVersionFromTags(string? tagPrefixRegex, GitVersion.SemanticVersionFormat semanticVersionFormat) -> System.Collections.Generic.IEnumerable! GitVersion.RepositoryStore.GetSourceBranches(GitVersion.IBranch! branch, GitVersion.Configuration.GitVersionConfiguration! configuration, System.Collections.Generic.IEnumerable! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.RepositoryStore.GetSourceBranches(GitVersion.IBranch! branch, GitVersion.Configuration.GitVersionConfiguration! configuration, params GitVersion.IBranch![]! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.RepositoryStore.GetTargetBranch(string? targetBranchName) -> GitVersion.IBranch! -GitVersion.RepositoryStore.GetValidVersionTags(string? tagPrefixRegex, GitVersion.SemanticVersionFormat versionFormat, System.DateTimeOffset? olderThan = null) -> System.Collections.Generic.IEnumerable<(GitVersion.ITag! Tag, GitVersion.SemanticVersion! Semver, GitVersion.ICommit! Commit)>! GitVersion.RepositoryStore.GetVersionTagsOnBranch(GitVersion.IBranch! branch, string? tagPrefixRegex, GitVersion.SemanticVersionFormat versionFormat) -> System.Collections.Generic.IEnumerable! GitVersion.RepositoryStore.IsCommitOnBranch(GitVersion.ICommit? baseVersionSource, GitVersion.IBranch! branch, GitVersion.ICommit! firstMatchingCommit) -> bool GitVersion.RepositoryStore.RepositoryStore(GitVersion.Logging.ILog! log, GitVersion.IGitRepository! repository) -> void @@ -825,6 +827,12 @@ GitVersion.SemanticVersionPreReleaseTag.SemanticVersionPreReleaseTag(GitVersion. GitVersion.SemanticVersionPreReleaseTag.SemanticVersionPreReleaseTag(string? name, long? number) -> void GitVersion.SemanticVersionPreReleaseTag.ToString(string! format) -> string! GitVersion.SemanticVersionPreReleaseTag.ToString(string? format, System.IFormatProvider? formatProvider) -> string! +GitVersion.SemanticVersionWithTag +GitVersion.SemanticVersionWithTag.SemanticVersionWithTag(GitVersion.SemanticVersion! Value, GitVersion.ITag! Tag) -> void +GitVersion.SemanticVersionWithTag.Tag.get -> GitVersion.ITag! +GitVersion.SemanticVersionWithTag.Tag.init -> void +GitVersion.SemanticVersionWithTag.Value.get -> GitVersion.SemanticVersion! +GitVersion.SemanticVersionWithTag.Value.init -> void GitVersion.Settings GitVersion.Settings.NoCache -> bool GitVersion.Settings.NoFetch -> bool @@ -906,11 +914,6 @@ GitVersion.VersionCalculation.ShaVersionFilter.Exclude(GitVersion.VersionCalcula GitVersion.VersionCalculation.ShaVersionFilter.ShaVersionFilter(System.Collections.Generic.IEnumerable! shas) -> void GitVersion.VersionCalculation.TaggedCommitVersionStrategy GitVersion.VersionCalculation.TaggedCommitVersionStrategy.TaggedCommitVersionStrategy(GitVersion.Common.IRepositoryStore! repositoryStore, System.Lazy! versionContext) -> void -GitVersion.VersionCalculation.TaggedCommitVersionStrategy.VersionTaggedCommit -GitVersion.VersionCalculation.TaggedCommitVersionStrategy.VersionTaggedCommit.Commit -> GitVersion.ICommit! -GitVersion.VersionCalculation.TaggedCommitVersionStrategy.VersionTaggedCommit.SemVer -> GitVersion.SemanticVersion! -GitVersion.VersionCalculation.TaggedCommitVersionStrategy.VersionTaggedCommit.Tag -> string! -GitVersion.VersionCalculation.TaggedCommitVersionStrategy.VersionTaggedCommit.VersionTaggedCommit(GitVersion.ICommit! commit, GitVersion.SemanticVersion! semVer, string! tag) -> void GitVersion.VersionCalculation.TrackReleaseBranchesVersionStrategy GitVersion.VersionCalculation.TrackReleaseBranchesVersionStrategy.TrackReleaseBranchesVersionStrategy(GitVersion.Common.IRepositoryStore! repositoryStore, System.Lazy! versionContext) -> void GitVersion.VersionCalculation.VariableProvider @@ -1040,6 +1043,7 @@ override GitVersion.SemanticVersionBuildMetaData.ToString() -> string! override GitVersion.SemanticVersionPreReleaseTag.Equals(object? obj) -> bool override GitVersion.SemanticVersionPreReleaseTag.GetHashCode() -> int override GitVersion.SemanticVersionPreReleaseTag.ToString() -> string! +override GitVersion.SemanticVersionWithTag.ToString() -> string! override GitVersion.VersionCalculation.BaseVersion.ToString() -> string! override GitVersion.VersionCalculation.ConfigNextVersionVersionStrategy.GetBaseVersions(GitVersion.Configuration.EffectiveBranchConfiguration! configuration) -> System.Collections.Generic.IEnumerable! override GitVersion.VersionCalculation.MergeMessageVersionStrategy.GetBaseVersions(GitVersion.Configuration.EffectiveBranchConfiguration! configuration) -> System.Collections.Generic.IEnumerable! @@ -1047,7 +1051,6 @@ override GitVersion.VersionCalculation.NextVersion.Equals(object? other) -> bool override GitVersion.VersionCalculation.NextVersion.GetHashCode() -> int override GitVersion.VersionCalculation.NextVersion.ToString() -> string! override GitVersion.VersionCalculation.TaggedCommitVersionStrategy.GetBaseVersions(GitVersion.Configuration.EffectiveBranchConfiguration! configuration) -> System.Collections.Generic.IEnumerable! -override GitVersion.VersionCalculation.TaggedCommitVersionStrategy.VersionTaggedCommit.ToString() -> string! override GitVersion.VersionCalculation.TrackReleaseBranchesVersionStrategy.GetBaseVersions(GitVersion.Configuration.EffectiveBranchConfiguration! configuration) -> System.Collections.Generic.IEnumerable! override GitVersion.VersionCalculation.VersionInBranchNameVersionStrategy.GetBaseVersions(GitVersion.Configuration.EffectiveBranchConfiguration! configuration) -> System.Collections.Generic.IEnumerable! override GitVersion.VersionCalculation.VersionStrategyModule.RegisterTypes(Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> void @@ -1210,4 +1213,4 @@ virtual GitVersion.Configuration.IgnoreConfiguration.ToFilters() -> System.Colle virtual GitVersion.VersionCalculation.EffectiveBranchConfigurationFinder.GetConfigurations(GitVersion.IBranch! branch, GitVersion.Configuration.GitVersionConfiguration! configuration) -> System.Collections.Generic.IEnumerable! virtual GitVersion.VersionCalculation.FallbackVersionStrategy.GetBaseVersions(GitVersion.Configuration.EffectiveBranchConfiguration! configuration) -> System.Collections.Generic.IEnumerable! virtual GitVersion.VersionCalculation.NextVersionCalculator.FindVersion() -> GitVersion.VersionCalculation.NextVersion! -virtual GitVersion.VersionCalculation.TaggedCommitVersionStrategy.FormatSource(GitVersion.VersionCalculation.TaggedCommitVersionStrategy.VersionTaggedCommit! version) -> string! +virtual GitVersion.VersionCalculation.TaggedCommitVersionStrategy.FormatSource(GitVersion.SemanticVersionWithTag! semanticVersion) -> string! diff --git a/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/TaggedCommitVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/TaggedCommitVersionStrategy.cs index 1d431f0c3d..b00ce20b34 100644 --- a/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/TaggedCommitVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/TaggedCommitVersionStrategy.cs @@ -16,48 +16,80 @@ public class TaggedCommitVersionStrategy : VersionStrategyBase public TaggedCommitVersionStrategy(IRepositoryStore repositoryStore, Lazy versionContext) : base(versionContext) => this.repositoryStore = repositoryStore.NotNull(); - public override IEnumerable GetBaseVersions(EffectiveBranchConfiguration configuration) => - GetTaggedVersions(Context.CurrentBranch, Context.CurrentCommit?.When); - - internal IEnumerable GetTaggedVersions(IBranch currentBranch, DateTimeOffset? olderThan) + public override IEnumerable GetBaseVersions(EffectiveBranchConfiguration configuration) { - if (currentBranch is null) - return Enumerable.Empty(); - var versionTags = this.repositoryStore.GetValidVersionTags(Context.Configuration.LabelPrefix, Context.Configuration.SemanticVersionFormat, olderThan); - var versionTagsByCommit = versionTags.ToLookup(vt => vt.Commit.Id.Sha); - var commitsOnBranch = currentBranch.Commits; - if (commitsOnBranch == null) - return Enumerable.Empty(); - - var versionTagsOnBranch = commitsOnBranch.SelectMany(commit => versionTagsByCommit[commit.Id.Sha]); - var versionTaggedCommits = versionTagsOnBranch.Select(t => new VersionTaggedCommit(t.Commit, t.Semver, t.Tag.Name.Friendly)); - var taggedVersions = versionTaggedCommits.Select(versionTaggedCommit => CreateBaseVersion(Context, versionTaggedCommit)).ToList(); + var taggedVersions = GetSemanticVersions(configuration) + .Select(versionTaggedCommit => CreateBaseVersion(Context, versionTaggedCommit)) + .ToList(); var taggedVersionsOnCurrentCommit = taggedVersions.Where(version => !version.ShouldIncrement).ToList(); return taggedVersionsOnCurrentCommit.Any() ? taggedVersionsOnCurrentCommit : taggedVersions; } - private BaseVersion CreateBaseVersion(GitVersionContext context, VersionTaggedCommit version) + private IEnumerable GetSemanticVersions(EffectiveBranchConfiguration configuration) { - var shouldUpdateVersion = version.Commit.Sha != context.CurrentCommit?.Sha; - var baseVersion = new BaseVersion(FormatSource(version), shouldUpdateVersion, version.SemVer, version.Commit, null); - return baseVersion; - } + var alreadyReturnedValues = new HashSet(); - protected virtual string FormatSource(VersionTaggedCommit version) => $"Git tag '{version.Tag}'"; + var olderThan = Context.CurrentCommit?.When; - protected class VersionTaggedCommit - { - public string Tag; - public ICommit Commit; - public SemanticVersion SemVer; + var semanticVersions = this.repositoryStore.GetSemanticVersionFromTags( + Context.Configuration.LabelPrefix, Context.Configuration.SemanticVersionFormat + ).ToList(); + ILookup semanticVersionsByCommit = semanticVersions.ToLookup(element => element.Tag.Commit.Id.Sha); - public VersionTaggedCommit(ICommit commit, SemanticVersion semVer, string tag) + var commitsOnCurrentBranch = Context.CurrentBranch.Commits?.ToArray() ?? Array.Empty(); + if (commitsOnCurrentBranch.Any()) { - this.Tag = tag; - this.Commit = commit; - this.SemVer = semVer; + foreach (var commit in commitsOnCurrentBranch) + { + foreach (var semanticVersion in semanticVersionsByCommit[commit.Id.Sha]) + { + if (commit.When <= olderThan) + { + if (alreadyReturnedValues.Add(semanticVersion)) yield return semanticVersion; + } + } + } + + if (configuration.Value.TrackMergeTarget) + { + var commitsOnCurrentBranchByCommit = commitsOnCurrentBranch.ToLookup(commit => commit.Id.Sha); + foreach (var semanticVersion in semanticVersions) + { + if (semanticVersion.Tag.Commit.When > olderThan) continue; + + var parentCommits = semanticVersion.Tag.Commit.Parents ?? Array.Empty(); + if (parentCommits.Any(element => commitsOnCurrentBranchByCommit.Contains(element.Id.Sha))) + { + if (alreadyReturnedValues.Add(semanticVersion)) yield return semanticVersion; + } + } + } } - public override string ToString() => $"{this.Tag} | {this.Commit} | {this.SemVer}"; + if (configuration.Value.TracksReleaseBranches) + { + var mainBranches = this.repositoryStore.FindMainlineBranches(Context.Configuration); + foreach (var mainBranche in mainBranches) + { + var commitsOnMainBranch = mainBranche.Commits?.ToArray() ?? Array.Empty(); + foreach (var commit in commitsOnMainBranch) + { + foreach (var semanticVersion in semanticVersionsByCommit[commit.Id.Sha]) + { + if (alreadyReturnedValues.Add(semanticVersion)) yield return semanticVersion; + } + } + } + } + } + + private BaseVersion CreateBaseVersion(GitVersionContext context, SemanticVersionWithTag semanticVersion) + { + var tagCommit = semanticVersion.Tag.Commit; + var shouldUpdateVersion = tagCommit.Sha != context.CurrentCommit?.Sha; + var baseVersion = new BaseVersion(FormatSource(semanticVersion), shouldUpdateVersion, semanticVersion.Value, tagCommit, null); + return baseVersion; } + + protected virtual string FormatSource(SemanticVersionWithTag semanticVersion) => $"Git tag '{semanticVersion.Tag.Name.Friendly}'"; } diff --git a/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/TrackReleaseBranchesVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/TrackReleaseBranchesVersionStrategy.cs index 27f91a9909..d2030ede50 100644 --- a/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/TrackReleaseBranchesVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/TrackReleaseBranchesVersionStrategy.cs @@ -36,17 +36,7 @@ public TrackReleaseBranchesVersionStrategy(IRepositoryStore repositoryStore, Laz } public override IEnumerable GetBaseVersions(EffectiveBranchConfiguration configuration) => - configuration.Value.TracksReleaseBranches ? ReleaseBranchBaseVersions().Union(MainTagsVersions()) : Array.Empty(); - - private IEnumerable MainTagsVersions() - { - var configuration = Context.Configuration; - var mainBranch = this.repositoryStore.FindMainBranch(configuration); - - return mainBranch != null - ? this.taggedCommitVersionStrategy.GetTaggedVersions(mainBranch, null) - : Array.Empty(); - } + configuration.Value.TracksReleaseBranches ? ReleaseBranchBaseVersions() : Array.Empty(); private IEnumerable ReleaseBranchBaseVersions() { diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionWithTag.cs b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionWithTag.cs new file mode 100644 index 0000000000..f15685d2b3 --- /dev/null +++ b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionWithTag.cs @@ -0,0 +1,6 @@ +namespace GitVersion; + +public sealed record SemanticVersionWithTag(SemanticVersion Value, ITag Tag) +{ + public override string ToString() => $"{Tag} | {Tag.Commit} | {Value}"; +} diff --git a/src/GitVersion.LibGit2Sharp/Git/Tag.cs b/src/GitVersion.LibGit2Sharp/Git/Tag.cs index ddcfa92e3b..aacba15466 100644 --- a/src/GitVersion.LibGit2Sharp/Git/Tag.cs +++ b/src/GitVersion.LibGit2Sharp/Git/Tag.cs @@ -9,19 +9,22 @@ internal sealed class Tag : ITag private static readonly LambdaEqualityHelper equalityHelper = new(x => x.Name.Canonical); private static readonly LambdaKeyComparer comparerHelper = new(x => x.Name.Canonical); private readonly LibGit2Sharp.Tag innerTag; + private readonly Lazy _commitLazy; internal Tag(LibGit2Sharp.Tag tag) { this.innerTag = tag.NotNull(); Name = new ReferenceName(this.innerTag.CanonicalName); + _commitLazy = new Lazy(PeeledTargetCommit); } public ReferenceName Name { get; } public int CompareTo(ITag? other) => comparerHelper.Compare(this, other); public bool Equals(ITag? other) => equalityHelper.Equals(this, other); public string? TargetSha => this.innerTag.Target.Sha; + public ICommit Commit => _commitLazy.Value.NotNull(); - public ICommit? PeeledTargetCommit() + private ICommit? PeeledTargetCommit() { var target = this.innerTag.Target;