diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 51c4d6a1e5..8e8b31dd34 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -56,6 +56,12 @@ * The initialization wizard has been removed. * On the `develop`, `release` and `hotfix` branch the introduced branch related property `prevent-increment.when-current-commit-tagged` has been set to `false` to get the incremented instead of the tagged semantic version. * When setting the "ignore commits before" parameter to a future value, an exception will occur if no commits are found on the current branch. This behavior mimics that of an empty repository. +* On the `GitFlow` workflow the increment property has been changed: + * in branch `release` from `None` to `Minor` and + * in branch `hotfix` from `None` to `Patch` +* On the `GitHubFlow` workflow the increment property has been changed in branch `release` from `None` to `Patch`. +* When creating a branch with name `hotfix/next` (by using the `GitFlow` workflow) or `release/next` (by the `GitHubFlow` workflow) the resulting version will yield to a patched version per default. +* If you have a tag `1.0.0` on `main` and branch from `main` to `release/1.0.1` then the next version number will be `1.1.0` when using the `GitFlow` workflow. This behavior is expected (but different compared to the `GitHubFlow` workflow) because on the `GitFlow` workflow you have an addition branch configuration with name hotfix where `is-release-branch` is set to `true`. That means if you want `1.0.1` as a next version you need to branch to `hotfix/1.0.1` or `hotfix/next`. On the other hand if you use the `GitHubFlow` workflow the next version number will be `1.0.1` because the increment on the `release` branch is set to `Patch`. ## v5.0.0 diff --git a/GitVersion.yml b/GitVersion.yml index 08802473ca..5724cb45f9 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,4 +1,4 @@ -assembly-versioning-scheme: MajorMinorPatch +workflow: GitFlow/v1 branches: main: label: beta diff --git a/src/GitVersion.Core.Tests/IntegrationTests/CompareTheDifferentWhenUsingTrunkBasedVersionStrategyWithGitFlow.cs b/src/GitVersion.Core.Tests/IntegrationTests/CompareTheDifferentWhenUsingTrunkBasedVersionStrategyWithGitFlow.cs index 373d689197..071cc53ad9 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/CompareTheDifferentWhenUsingTrunkBasedVersionStrategyWithGitFlow.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/CompareTheDifferentWhenUsingTrunkBasedVersionStrategyWithGitFlow.cs @@ -616,29 +616,13 @@ public void EnsureFeatureDevelopmentWithDevelopBranchFast(bool useTrunkBased) fixture.BranchTo("feature/foo"); - if (useTrunkBased) - { - // ❔ expected: "0.1.0-foo.1+0" - fixture.AssertFullSemver("0.0.2-foo.1+0", configuration); - } - else - { - // ✅ succeeds as expected - fixture.AssertFullSemver("0.1.0-foo.1+0", configuration); - } + // ✅ succeeds as expected + fixture.AssertFullSemver("0.1.0-foo.1+0", configuration); fixture.MakeACommit("B"); - if (useTrunkBased) - { - // ❔ expected: "0.1.0-foo.1+1" - fixture.AssertFullSemver("0.0.2-foo.1+1", configuration); - } - else - { - // ✅ succeeds as expected - fixture.AssertFullSemver("0.1.0-foo.1+1", configuration); - } + // ✅ succeeds as expected + fixture.AssertFullSemver("0.1.0-foo.1+1", configuration); fixture.ApplyTag("0.1.0-foo.1"); @@ -946,31 +930,15 @@ public void EnsureBugFixWithDevelopBranchFast(bool useTrunkBased) fixture.BranchTo("pull/2/merge"); fixture.MergeNoFF("hotfix/foo"); - if (useTrunkBased) - { - // ❔ expected: "0.1.0-PullRequest2.4" - fixture.AssertFullSemver("0.0.2-PullRequest2.4", configuration); - } - else - { - // ✅ succeeds as expected - fixture.AssertFullSemver("0.1.0-PullRequest2.4", configuration); - } + // ✅ succeeds as expected + fixture.AssertFullSemver("0.1.0-PullRequest2.4", configuration); fixture.Checkout("main"); fixture.BranchTo("pull/3/merge"); fixture.MergeNoFF("hotfix/foo"); - if (useTrunkBased) - { - // ✅ succeeds as expected - fixture.AssertFullSemver("0.0.2-PullRequest3.4", configuration); - } - else - { - // ❔ expected: "0.0.2-PullRequest3.4" - fixture.AssertFullSemver("0.1.0-PullRequest3.4", configuration); - } + // ❔ expected: "0.0.2-PullRequest3.4" + fixture.AssertFullSemver("0.1.0-PullRequest3.4", configuration); fixture.Checkout("hotfix/foo"); fixture.MergeTo("main", removeBranchAfterMerging: true); @@ -985,26 +953,6 @@ public void EnsureBugFixWithDevelopBranchFast(bool useTrunkBased) fixture.AssertFullSemver("0.0.3-1", configuration); } - [Test] - public void JustATest() - { - var configuration = configurationBuilder.WithVersionStrategy(VersionStrategies.TrunkBased).Build(); - - using var fixture = new EmptyRepositoryFixture("main"); - - fixture.MakeACommit("A"); - - // ✅ succeeds as expected - fixture.AssertFullSemver("0.0.1-1", configuration); - - fixture.ApplyTag("0.1.0"); - - for (int i = 0; i < 10; i++) fixture.MakeACommit(); - - // ✅ succeeds as expected - fixture.AssertFullSemver("0.1.10-1", configuration); - } - [TestCase(false)] [TestCase(true)] public void EnsureFeatureDevelopmentWithReleaseNextBranch(bool useTrunkBased) diff --git a/src/GitVersion.Core.Tests/IntegrationTests/OtherScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/OtherScenarios.cs index 34e7881620..eecb4da7ba 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/OtherScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/OtherScenarios.cs @@ -1364,4 +1364,42 @@ public void UnversionedHotfix() fixture.AssertFullSemver("1.2.1-3", configuration); } + + [Test] + public void AlternativeSemanticVersionsShouldBeConsidered() + { + var configuration = GitFlowConfigurationBuilder.New.Build(); + + using EmptyRepositoryFixture fixture = new("main"); + + fixture.MakeACommit("A"); + fixture.MakeATaggedCommit("4.0.0-beta.14"); + fixture.MakeACommit("B"); + + fixture.AssertFullSemver("4.0.0-3", configuration); + } + + [TestCase(null, "6.0.0-beta.6")] + [TestCase("beta", "6.0.0-beta.21")] + public void AlternativeSemanticVersionsShouldBeConsidered(string? labelOnMain, string version) + { + var configuration = GitFlowConfigurationBuilder.New + .WithLabel(null) + .WithBranch("main", _ => _.WithLabel(labelOnMain)) + .Build(); + + using EmptyRepositoryFixture fixture = new("main"); + + fixture.MakeATaggedCommit("1.0.0"); + fixture.MakeATaggedCommit("4.0.0-beta.14"); + fixture.MakeACommit("A"); + fixture.MakeATaggedCommit("6.0.0-alpha.1"); + fixture.MakeATaggedCommit("6.0.0-alpha.2"); + fixture.MakeATaggedCommit("6.0.0-alpha.3"); + fixture.MakeACommit("B"); + fixture.MakeATaggedCommit("6.0.0-beta.5"); + fixture.MakeACommit("C"); + + fixture.AssertFullSemver(version, configuration); + } } diff --git a/src/GitVersion.Core/Git/ReferenceName.cs b/src/GitVersion.Core/Git/ReferenceName.cs index 630511dda2..4ab5a6ce52 100644 --- a/src/GitVersion.Core/Git/ReferenceName.cs +++ b/src/GitVersion.Core/Git/ReferenceName.cs @@ -54,7 +54,7 @@ public static bool TryParse([NotNullWhen(true)] out ReferenceName? value, string value = new(canonicalName); } - return value != null; + return value is not null; } public static ReferenceName FromBranchName(string branchName) @@ -77,6 +77,15 @@ public static ReferenceName FromBranchName(string branchName) public override int GetHashCode() => equalityHelper.GetHashCode(this); public override string ToString() => Friendly; + public static bool operator ==(ReferenceName? left, ReferenceName? right) + { + if (ReferenceEquals(left, right)) return true; + if (left is null || right is null) return false; + return left.Equals(right); + } + + public static bool operator !=(ReferenceName? left, ReferenceName? right) => !(left == right); + public bool TryGetSemanticVersion([NotNullWhen(true)] out (SemanticVersion Value, string? Name) result, Regex versionPatternRegex, string? tagPrefix, diff --git a/src/GitVersion.Core/MergeMessage.cs b/src/GitVersion.Core/MergeMessage.cs index 36f8cca220..9dfe4416bf 100644 --- a/src/GitVersion.Core/MergeMessage.cs +++ b/src/GitVersion.Core/MergeMessage.cs @@ -100,7 +100,7 @@ public static bool TryParse( mergeMessage = null; var mergedBranch = new MergeMessage(mergeCommit.Message, configuration).MergedBranch; - var isReleaseBranch = mergedBranch != null && configuration.IsReleaseBranch(mergedBranch); + var isReleaseBranch = mergedBranch is not null && configuration.IsReleaseBranch(mergedBranch); var isValidMergeCommit = mergeCommit.IsMergeCommit() || isReleaseBranch; if (isValidMergeCommit) diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt index b4d09ebd0f..c022ac619e 100644 --- a/src/GitVersion.Core/PublicAPI.Unshipped.txt +++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt @@ -769,6 +769,8 @@ static GitVersion.Git.BranchCommit.operator !=(GitVersion.Git.BranchCommit left, static GitVersion.Git.BranchCommit.operator ==(GitVersion.Git.BranchCommit left, GitVersion.Git.BranchCommit right) -> bool static GitVersion.Git.CommitExtensions.IsMergeCommit(this GitVersion.Git.ICommit! source) -> bool static GitVersion.Git.ReferenceName.FromBranchName(string! branchName) -> GitVersion.Git.ReferenceName! +static GitVersion.Git.ReferenceName.operator !=(GitVersion.Git.ReferenceName? left, GitVersion.Git.ReferenceName? right) -> bool +static GitVersion.Git.ReferenceName.operator ==(GitVersion.Git.ReferenceName? left, GitVersion.Git.ReferenceName? right) -> bool static GitVersion.Git.ReferenceName.Parse(string! canonicalName) -> GitVersion.Git.ReferenceName! static GitVersion.Git.ReferenceName.TryParse(out GitVersion.Git.ReferenceName? value, string! canonicalName) -> bool static GitVersion.Helpers.Disposable.Create(System.Action! disposer) -> System.IDisposable! diff --git a/src/GitVersion.Core/VersionCalculation/TrunkBased/EnrichIncrement.cs b/src/GitVersion.Core/VersionCalculation/TrunkBased/EnrichIncrement.cs index 3f9b5992fb..0b1a3d4086 100644 --- a/src/GitVersion.Core/VersionCalculation/TrunkBased/EnrichIncrement.cs +++ b/src/GitVersion.Core/VersionCalculation/TrunkBased/EnrichIncrement.cs @@ -11,7 +11,9 @@ public void Enrich(TrunkBasedIteration iteration, TrunkBasedCommit commit, Trunk { var effectiveConfiguration = commit.GetEffectiveConfiguration(context.Configuration); var incrementForcedByBranch = effectiveConfiguration.Increment.ToVersionField(); - var incrementForcedByCommit = GetIncrementForcedByCommit(context, commit.Value, effectiveConfiguration); + var incrementForcedByCommit = commit.IsDummy + ? VersionField.None + : GetIncrementForcedByCommit(context, commit.Value, effectiveConfiguration); commit.Increment = incrementForcedByCommit; context.Increment = context.Increment.Consolidate(incrementForcedByBranch, incrementForcedByCommit); diff --git a/src/GitVersion.Core/VersionCalculation/TrunkBased/NonTrunk/FirstCommitOnRelease.cs b/src/GitVersion.Core/VersionCalculation/TrunkBased/NonTrunk/FirstCommitOnRelease.cs index 65d3d56fb6..94c7803fd0 100644 --- a/src/GitVersion.Core/VersionCalculation/TrunkBased/NonTrunk/FirstCommitOnRelease.cs +++ b/src/GitVersion.Core/VersionCalculation/TrunkBased/NonTrunk/FirstCommitOnRelease.cs @@ -24,7 +24,7 @@ public bool MatchPrecondition(TrunkBasedIteration iteration, TrunkBasedCommit co && commit.GetEffectiveConfiguration(context.Configuration).IsReleaseBranch && context.SemanticVersion is null && (commit.Predecessor is null - || commit.Predecessor?.BranchName != commit.BranchName); + || commit.BranchName != commit.Predecessor?.BranchName); public IEnumerable GetIncrements( TrunkBasedIteration iteration, TrunkBasedCommit commit, TrunkBasedContext context) diff --git a/src/GitVersion.Core/VersionCalculation/TrunkBased/TrunkBasedCommit.cs b/src/GitVersion.Core/VersionCalculation/TrunkBased/TrunkBasedCommit.cs index ad3f515387..d43c53951e 100644 --- a/src/GitVersion.Core/VersionCalculation/TrunkBased/TrunkBasedCommit.cs +++ b/src/GitVersion.Core/VersionCalculation/TrunkBased/TrunkBasedCommit.cs @@ -10,7 +10,7 @@ namespace GitVersion.VersionCalculation.TrunkBased; "HasSuccessor = {" + nameof(HasSuccessor) + "}, HasPredecessor = {" + nameof(HasPredecessor) + "}, " + "HasChildIteration = {" + nameof(HasChildIteration) + "}, Message = {" + nameof(Message) + @"} \}" )] -internal record TrunkBasedCommit(TrunkBasedIteration Iteration, ICommit Value, ReferenceName BranchName, IBranchConfiguration Configuration) +internal record TrunkBasedCommit(TrunkBasedIteration Iteration, ICommit? value, ReferenceName BranchName, IBranchConfiguration Configuration) { public bool IsPredecessorTheLastCommitOnTrunk(IGitVersionConfiguration configuration) => !GetEffectiveConfiguration(configuration).IsMainBranch && Predecessor?.GetEffectiveConfiguration(configuration).IsMainBranch == true; @@ -31,9 +31,12 @@ public bool IsPredecessorTheLastCommitOnTrunk(IGitVersionConfiguration configura public TrunkBasedCommit? Predecessor { get; private set; } - public ICommit Value { get; } = Value.NotNull(); + public ICommit Value => IsDummy ? (Successor?.Value)! : value!; - public string Message => Value.Message; + [MemberNotNullWhen(false, nameof(Value))] + public bool IsDummy => value is null; + + public string Message => IsDummy ? "<>" : Value.Message; public TrunkBasedIteration? ChildIteration { get; private set; } @@ -101,7 +104,7 @@ public void AddSemanticVersions(IEnumerable values) public void AddChildIteration(TrunkBasedIteration iteration) => ChildIteration = iteration.NotNull(); public TrunkBasedCommit Append( - ICommit value, ReferenceName branchName, IBranchConfiguration configuration) + ICommit? value, ReferenceName branchName, IBranchConfiguration configuration) { if (HasPredecessor) throw new InvalidOperationException(); diff --git a/src/GitVersion.Core/VersionCalculation/TrunkBased/TrunkBasedIteration.cs b/src/GitVersion.Core/VersionCalculation/TrunkBased/TrunkBasedIteration.cs index a0c910ed55..2c53fbeb74 100644 --- a/src/GitVersion.Core/VersionCalculation/TrunkBased/TrunkBasedIteration.cs +++ b/src/GitVersion.Core/VersionCalculation/TrunkBased/TrunkBasedIteration.cs @@ -63,17 +63,21 @@ public TrunkBasedIteration(string id, ReferenceName branchName, IBranchConfigura } public TrunkBasedCommit CreateCommit( - ICommit value, ReferenceName branchName, IBranchConfiguration configuration) + ICommit? value, ReferenceName branchName, IBranchConfiguration configuration) { TrunkBasedCommit commit; if (commits.Count != 0) - commit = commits.Peek().Append(value, branchName, configuration); //, increment); + commit = commits.Peek().Append(value, branchName, configuration); else { - commit = new TrunkBasedCommit(this, value, branchName, configuration); //, increment); + commit = new TrunkBasedCommit(this, value, branchName, configuration); } commits.Push(commit); - commitLookup.Add(value, commit); + + if (value is not null) + { + commitLookup.Add(value, commit); + } return commit; } diff --git a/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs b/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs index ede42d8b06..74c4b3a356 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs @@ -162,19 +162,22 @@ private NextVersion CalculateNextVersion(IBranch branch, IGitVersionConfiguratio var maxVersion = nextVersions.Max() ?? throw new GitVersionException("No base versions determined on the current branch."); - var matchingVersionsOnceIncremented = nextVersions - .Where(v => v.BaseVersion.BaseVersionSource != null && v.IncrementedVersion == maxVersion.IncrementedVersion) - .ToList(); + ICommit? latestBaseVersionSource; - if (matchingVersionsOnceIncremented.Count != 0) + var matchingVersionsOnceIncremented = nextVersions + .Where( + element => element.BaseVersion.BaseVersionSource != null + && element.IncrementedVersion == maxVersion.IncrementedVersion + ).ToArray(); + if (matchingVersionsOnceIncremented.Length > 1) { var latestVersion = matchingVersionsOnceIncremented.Aggregate(CompareVersions); latestBaseVersionSource = latestVersion.BaseVersion.BaseVersionSource; maxVersion = latestVersion; log.Info( $"Found multiple base versions which will produce the same SemVer ({maxVersion.IncrementedVersion}), " + - $"taking oldest source for commit counting ({latestVersion.BaseVersion.Source})"); + $"taking latest source for commit counting ({latestVersion.BaseVersion.Source})"); } else { diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TaggedCommitVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TaggedCommitVersionStrategy.cs index a8a2bd7f61..3e51ae753b 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TaggedCommitVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TaggedCommitVersionStrategy.cs @@ -40,13 +40,16 @@ private IEnumerable GetBaseVersionsInternal(EffectiveBranchConfigur ).SelectMany(elements => elements).Distinct().ToArray(); var label = configuration.Value.GetBranchSpecificLabel(Context.CurrentBranch.Name, null); - var maxTaggedSemanticVersion = taggedSemanticVersions - .Where(element => !element.Value.IsMatchForBranchSpecificLabel(label)) - .Max(); - var semanticVersionsWithTag = taggedSemanticVersions.Where(element => element.Value.IsMatchForBranchSpecificLabel(label)); - foreach (var semanticVersionWithTag in semanticVersionsWithTag) + List alternativeSemanticVersionsWithTag = new(); + foreach (var semanticVersionWithTag in taggedSemanticVersions) { + if (!semanticVersionWithTag.Value.IsMatchForBranchSpecificLabel(label)) + { + alternativeSemanticVersionsWithTag.Add(semanticVersionWithTag); + continue; + } + var baseVersionSource = semanticVersionWithTag.Tag.Commit; var increment = incrementStrategyFinder.DetermineIncrementedField( currentCommit: Context.CurrentCommit, @@ -55,6 +58,7 @@ private IEnumerable GetBaseVersionsInternal(EffectiveBranchConfigur configuration: configuration.Value, label: label ); + yield return new BaseVersion( $"Git tag '{semanticVersionWithTag.Tag.Name.Friendly}'", semanticVersionWithTag.Value, baseVersionSource) { @@ -63,9 +67,10 @@ private IEnumerable GetBaseVersionsInternal(EffectiveBranchConfigur Increment = increment, ForceIncrement = false, Label = label, - AlternativeSemanticVersion = maxTaggedSemanticVersion?.Value + AlternativeSemanticVersion = alternativeSemanticVersionsWithTag.Max()?.Value } }; + alternativeSemanticVersionsWithTag.Clear(); } } } diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TrunkBasedVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TrunkBasedVersionStrategy.cs index 4b6efc9697..f42c869d90 100644 --- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TrunkBasedVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/TrunkBasedVersionStrategy.cs @@ -105,6 +105,7 @@ public IEnumerable GetBaseVersions(EffectiveBranchConfiguration con IterateOverCommitsRecursive( commitsInReverseOrder: commitsInReverseOrder, iteration: iteration, + targetBranch: configuration.Branch, targetLabel: targetLabel, taggedSemanticVersions: taggedSemanticVersions ); @@ -127,61 +128,69 @@ private TrunkBasedIteration CreateIteration( } private bool IterateOverCommitsRecursive( - IEnumerable commitsInReverseOrder, TrunkBasedIteration iteration, string? targetLabel, + IEnumerable commitsInReverseOrder, TrunkBasedIteration iteration, IBranch targetBranch, string? targetLabel, ILookup taggedSemanticVersions, HashSet? traversedCommits = null) { traversedCommits ??= []; - bool exit = false; + bool returnTrueWhenTheIncrementIsKnown = false; var configuration = iteration.Configuration; var branchName = iteration.BranchName; var branch = repositoryStore.FindBranch(branchName); - Lazy> commitsWasBranchedFromLazy = new( - () => branch is null - ? new Dictionary() - : GetCommitsWasBranchedFrom(branch) + Lazy>> commitsWasBranchedFromLazy = new( + () => branch is null ? new Dictionary>() : GetCommitsWasBranchedFrom(branch) ); foreach (var item in commitsInReverseOrder) { if (!traversedCommits.Add(item)) continue; - if (commitsWasBranchedFromLazy.Value.TryGetValue(item, out var effectiveConfigurationWasBranchedFrom) - && (!(configuration.IsMainBranch == true) || effectiveConfigurationWasBranchedFrom.Value.IsMainBranch == true)) + if (commitsWasBranchedFromLazy.Value.TryGetValue(item, out var effectiveConfigurationsWasBranchedFrom)) { - var excludeBranch = branch; + var effectiveConfigurationWasBranchedFrom = effectiveConfigurationsWasBranchedFrom.First(); - configuration = effectiveConfigurationWasBranchedFrom.Value; - branchName = effectiveConfigurationWasBranchedFrom.Branch.Name; - branch = repositoryStore.FindBranch(branchName); + if (!(configuration.IsMainBranch == true) || effectiveConfigurationWasBranchedFrom.Value.IsMainBranch == true) + { + var excludeBranch = branch; + if (effectiveConfigurationsWasBranchedFrom.Any(element => + !element.Branch.Equals(effectiveConfigurationWasBranchedFrom.Branch) + && element.Branch.Equals(targetBranch))) + { + iteration.CreateCommit(null, targetBranch.Name, Context.Configuration.GetBranchConfiguration(targetBranch)); + } + configuration = effectiveConfigurationWasBranchedFrom.Value; + branchName = effectiveConfigurationWasBranchedFrom.Branch.Name; - commitsWasBranchedFromLazy = new Lazy> - (() => branch is null ? new Dictionary() - : GetCommitsWasBranchedFrom(branch, excludeBranch is null ? Array.Empty() : [excludeBranch]) - ); + branch = repositoryStore.FindBranch(branchName); - TaggedSemanticVersions taggedSemanticVersion = TaggedSemanticVersions.OfBranch; - if ((configuration.TrackMergeTarget ?? Context.Configuration.TrackMergeTarget) == true) - { - taggedSemanticVersion |= TaggedSemanticVersions.OfMergeTargets; - } - if ((configuration.TracksReleaseBranches ?? Context.Configuration.TracksReleaseBranches) == true) - { - taggedSemanticVersion |= TaggedSemanticVersions.OfReleaseBranches; - } - if (!(configuration.IsMainBranch == true || configuration.IsReleaseBranch == true)) - { - taggedSemanticVersion |= TaggedSemanticVersions.OfMainBranches; + commitsWasBranchedFromLazy = new Lazy>> + (() => branch is null ? new Dictionary>() + : GetCommitsWasBranchedFrom(branch, excludeBranch is null ? Array.Empty() : [excludeBranch]) + ); + + TaggedSemanticVersions taggedSemanticVersion = TaggedSemanticVersions.OfBranch; + if ((configuration.TrackMergeTarget ?? Context.Configuration.TrackMergeTarget) == true) + { + taggedSemanticVersion |= TaggedSemanticVersions.OfMergeTargets; + } + if ((configuration.TracksReleaseBranches ?? Context.Configuration.TracksReleaseBranches) == true) + { + taggedSemanticVersion |= TaggedSemanticVersions.OfReleaseBranches; + } + if (!(configuration.IsMainBranch == true || configuration.IsReleaseBranch == true)) + { + taggedSemanticVersion |= TaggedSemanticVersions.OfMainBranches; + } + taggedSemanticVersions = taggedSemanticVersionService.GetTaggedSemanticVersions( + branch: effectiveConfigurationWasBranchedFrom.Branch, + configuration: Context.Configuration, + label: null, + notOlderThan: Context.CurrentCommit.When, + taggedSemanticVersion: taggedSemanticVersion + ); } - taggedSemanticVersions = taggedSemanticVersionService.GetTaggedSemanticVersions( - branch: effectiveConfigurationWasBranchedFrom.Branch, - configuration: Context.Configuration, - label: null, - notOlderThan: Context.CurrentCommit.When, - taggedSemanticVersion: taggedSemanticVersion - ); } var commit = iteration.CreateCommit(item, branchName, configuration); @@ -204,12 +213,12 @@ private bool IterateOverCommitsRecursive( } else { - exit = true; + returnTrueWhenTheIncrementIsKnown = true; } } } - if (exit && configuration.Increment != IncrementStrategy.Inherit) + if (returnTrueWhenTheIncrementIsKnown && configuration.Increment != IncrementStrategy.Inherit) { return true; } @@ -249,6 +258,7 @@ private bool IterateOverCommitsRecursive( var done = IterateOverCommitsRecursive( commitsInReverseOrder: mergedCommitsInReverseOrderLazy.Value, iteration: childIteration, + targetBranch: targetBranch, targetLabel: targetLabel, traversedCommits: traversedCommits, taggedSemanticVersions: taggedSemanticVersions @@ -265,10 +275,10 @@ private bool IterateOverCommitsRecursive( return false; } - private IReadOnlyDictionary GetCommitsWasBranchedFrom( + private IReadOnlyDictionary> GetCommitsWasBranchedFrom( IBranch branch, params IBranch[] excludedBranches) { - Dictionary result = new(); + Dictionary> result = new(); var branchCommits = repositoryStore.FindCommitBranchesBranchedFrom( branch, Context.Configuration, excludedBranches: excludedBranches @@ -281,24 +291,35 @@ private bool IterateOverCommitsRecursive( { var branchConfiguration = Context.Configuration.GetBranchConfiguration(item); - if (result.ContainsKey(branchCommitDictionary[item])) + var key = branchCommitDictionary[item]; + if (result.ContainsKey(key)) { if (branchConfiguration.Increment == IncrementStrategy.Inherit && branchConfiguration.IsMainBranch is null) { throw new InvalidOperationException(); } - if ((branchConfiguration.IsMainBranch ?? Context.Configuration.IsMainBranch) == true - && result[branchCommitDictionary[item]].Configuration.IsMainBranch == false) + if ((branchConfiguration.IsMainBranch ?? Context.Configuration.IsMainBranch) == true) { - result[branchCommitDictionary[item]] = new(item, branchConfiguration); + foreach (var element in result[key].ToArray()) + { + result[key].Add(new(item, branchConfiguration)); + } } } else { - result.Add(key: branchCommitDictionary[item], value: new(item, branchConfiguration)); + result.Add(key: key, value: [new(item, branchConfiguration)]); } } + + // If a main branch existing we need to ensure that it will be present at the first position in the list. + foreach (var item in result) + { + result[item.Key] = item.Value + .OrderByDescending(element => (element.Configuration.IsMainBranch ?? Context.Configuration.IsMainBranch) == true) + .ToList(); + } return result; }