Skip to content

Commit 9d591df

Browse files
committed
Enable direct commits on master to be treated as a release
1 parent e91288d commit 9d591df

File tree

2 files changed

+116
-36
lines changed

2 files changed

+116
-36
lines changed
Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using GitTools.Testing;
1+
using System;
2+
using System.Reflection;
3+
using System.Text;
4+
using GitTools.Testing;
25
using GitVersion;
36
using GitVersionCore.Tests;
47
using LibGit2Sharp;
@@ -17,44 +20,83 @@ public void MergedFeatureBranchesToMasterImpliesRelease()
1720
using (var fixture = new EmptyRepositoryFixture())
1821
{
1922
fixture.Repository.MakeACommit("1");
20-
fixture.MakeACommit();
23+
fixture.MakeATaggedCommit("1.0.0");
2124

22-
fixture.BranchTo("feature/foo");
23-
fixture.Repository.MakeACommit("2");
24-
fixture.AssertFullSemver(config, "0.1.1-foo.1+2");
25+
fixture.BranchTo("feature/foo", "foo");
26+
fixture.MakeACommit("2");
27+
fixture.AssertFullSemver(config, "1.0.1-foo.1+1");
2528
fixture.Checkout("master");
2629
fixture.MergeNoFF("feature/foo");
2730

28-
fixture.AssertFullSemver(config, "0.1.1+3");
31+
fixture.AssertFullSemver(config, "1.0.1+2");
2932

30-
fixture.BranchTo("feature/foo2");
31-
fixture.Repository.MakeACommit("3 +semver: minor");
32-
fixture.AssertFullSemver(config, "0.2.0-foo2.1+4");
33+
fixture.BranchTo("feature/foo2", "foo2");
34+
fixture.MakeACommit("3 +semver: minor");
35+
fixture.AssertFullSemver(config, "1.1.0-foo2.1+3");
3336
fixture.Checkout("master");
3437
fixture.MergeNoFF("feature/foo2");
35-
fixture.AssertFullSemver(config, "0.2.0+5");
38+
fixture.AssertFullSemver(config, "1.1.0+4");
3639

37-
fixture.BranchTo("feature/foo3");
38-
fixture.Repository.MakeACommit("4");
40+
fixture.BranchTo("feature/foo3", "foo3");
41+
fixture.MakeACommit("4");
3942
fixture.Checkout("master");
4043
fixture.MergeNoFF("feature/foo3");
44+
fixture.SequenceDiagram.NoteOver("Merge message contains '+semver: minor'", "master");
4145
var commit = fixture.Repository.Head.Tip;
4246
// Put semver increment in merge message
4347
fixture.Repository.Commit(commit.Message + " +semver: minor", commit.Author, commit.Committer, new CommitOptions
4448
{
4549
AmendPreviousCommit = true
4650
});
47-
commit = fixture.Repository.Head.Tip;
48-
fixture.AssertFullSemver(config, "0.3.0+7");
51+
fixture.AssertFullSemver(config, "1.2.0+6");
4952

50-
fixture.BranchTo("feature/foo4");
51-
fixture.Repository.MakeACommit("5 +semver: major");
52-
fixture.AssertFullSemver(config, "1.0.0-foo4.1+8");
53+
fixture.BranchTo("feature/foo4", "foo4");
54+
fixture.MakeACommit("5 +semver: major");
55+
fixture.AssertFullSemver(config, "2.0.0-foo4.1+7");
5356
fixture.Checkout("master");
5457
fixture.MergeNoFF("feature/foo4");
55-
fixture.AssertFullSemver(config, "1.0.0+9");
58+
fixture.AssertFullSemver(config, "2.0.0+8");
59+
60+
// We should evaluate any commits not included in merge commit calculations for direct commit/push or squash to merge commits
61+
fixture.MakeACommit("6 +semver: major");
62+
fixture.AssertFullSemver(config, "3.0.0+9");
63+
fixture.MakeACommit("7 +semver: minor");
64+
fixture.AssertFullSemver(config, "3.1.0+10");
65+
fixture.MakeACommit("8");
66+
fixture.AssertFullSemver(config, "3.1.1+11");
67+
68+
// Finally verify that the merge commits still function properly
69+
fixture.BranchTo("feature/foo5", "foo5");
70+
fixture.MakeACommit("9 +semver: minor");
71+
fixture.AssertFullSemver(config, "3.2.0-foo5.1+12");
72+
fixture.Checkout("master");
73+
fixture.MergeNoFF("feature/foo5");
74+
fixture.AssertFullSemver(config, "3.2.0+13");
75+
76+
// One more direct commit for good measure
77+
fixture.MakeACommit("10 +semver: minor");
78+
fixture.AssertFullSemver(config, "3.3.0+14");
79+
Console.WriteLine(fixture.SequenceDiagram.GetDiagram());
5680
}
5781
}
58-
5982
// Write test which has a forward merge into a feature branch
6083
}
84+
85+
static class CommitExtensions
86+
{
87+
public static void MakeACommit(this RepositoryFixtureBase fixture, string commitMsg)
88+
{
89+
fixture.Repository.MakeACommit(commitMsg);
90+
var diagramBuilder = (StringBuilder)typeof(SequenceDiagram)
91+
.GetField("_diagramBuilder", BindingFlags.Instance | BindingFlags.NonPublic)
92+
.GetValue(fixture.SequenceDiagram);
93+
Func<string, string> getParticipant = participant => (string)typeof(SequenceDiagram)
94+
.GetMethod("GetParticipant", BindingFlags.Instance | BindingFlags.NonPublic)
95+
.Invoke(fixture.SequenceDiagram, new object[]
96+
{
97+
participant
98+
});
99+
diagramBuilder.AppendLineFormat("{0} -> {0}: Commit '{1}'", getParticipant(fixture.Repository.Head.FriendlyName),
100+
commitMsg);
101+
}
102+
}

src/GitVersionCore/VersionCalculation/NextVersionCalculator.cs

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace GitVersion.VersionCalculation
22
{
33
using System;
4+
using System.Collections.Generic;
45
using System.Linq;
56
using System.Text.RegularExpressions;
67
using BaseVersionCalculators;
@@ -84,49 +85,86 @@ private SemanticVersion FindMainlineModeVersion(BaseVersion baseVersion, GitVers
8485

8586
using (Logger.IndentLog("Using mainline development mode to calculate current version"))
8687
{
88+
var mainlineVersion = baseVersion.SemanticVersion;
89+
8790
var commitLog = context.Repository.Commits.QueryBy(new CommitFilter
8891
{
8992
IncludeReachableFrom = context.CurrentBranch,
9093
ExcludeReachableFrom = baseVersion.BaseVersionSource,
9194
SortBy = CommitSortStrategies.Reverse
92-
}).ToList();
93-
var mergeCommits = commitLog
94-
.Where(l => l.Parents.Count() > 1)
95-
.ToList();
96-
97-
Logger.WriteInfo(string.Format("Found {0} merge commits to evaluate increments for..", mergeCommits.Count));
95+
}).Where(c => c.Sha != baseVersion.BaseVersionSource.Sha).ToList();
96+
var directCommits = new List<Commit>();
9897

99-
var mainlineVersion = mergeCommits
100-
.Select(mergeCommit =>
98+
foreach (var commit in commitLog)
99+
{
100+
directCommits.Add(commit);
101+
if (commit.Parents.Count() > 1)
101102
{
103+
// Merge commit, process all merged commits as a batch
104+
var mergeCommit = commit;
102105
var mergedHead = GetMergedHead(mergeCommit);
103106
var findMergeBase = context.Repository.ObjectDatabase.FindMergeBase(mergeCommit.Parents.First(), mergedHead);
104-
return FindMessageIncrement(context, mergeCommit, mergedHead, findMergeBase);
105-
})
106-
.Aggregate(baseVersion.SemanticVersion, (v, i) => v.IncrementVersion(i));
107+
var findMessageIncrement = FindMessageIncrement(context, mergeCommit, mergedHead, findMergeBase, directCommits);
108+
109+
// If this collection is not empty there has been some direct commits against master
110+
// Treat each commit as it's own 'release', we need to do this before we increment the branch
111+
mainlineVersion = IncrementForEachCommit(context, directCommits, mainlineVersion);
112+
directCommits.Clear();
113+
114+
// Finally increment for the branch
115+
mainlineVersion = mainlineVersion.IncrementVersion(findMessageIncrement);
116+
Logger.WriteInfo(string.Format("Merge commit {0} incremented base versions {1}, now {2}",
117+
mergeCommit.Sha, findMessageIncrement, mainlineVersion));
118+
}
119+
}
107120

108121
if (context.CurrentBranch.FriendlyName != "master")
109122
{
110123
var mergedHead = context.CurrentCommit;
111-
var findMergeBase = context.Repository.FindBranch("master").Tip;
112-
var branchIncrement = FindMessageIncrement(context, findMergeBase, mergedHead, findMergeBase);
124+
var findMergeBase = context.Repository.ObjectDatabase.FindMergeBase(context.CurrentCommit, context.Repository.FindBranch("master").Tip);
125+
Logger.WriteInfo(string.Format("Current branch ({0}) was branch from {1}", context.CurrentBranch.FriendlyName, findMergeBase));
126+
127+
var branchIncrement = FindMessageIncrement(context, findMergeBase, mergedHead, findMergeBase, directCommits);
128+
mainlineVersion = IncrementForEachCommit(context, directCommits, mainlineVersion);
113129
Logger.WriteInfo(string.Format("Performing {0} increment for current branch ", branchIncrement));
114130
mainlineVersion = mainlineVersion.IncrementVersion(branchIncrement);
115131
}
132+
else
133+
{
134+
// If we are on master, make sure no commits get left behind
135+
mainlineVersion = IncrementForEachCommit(context, directCommits, mainlineVersion);
136+
}
137+
116138
return mainlineVersion;
117139
}
118140
}
119141

120-
private static VersionField FindMessageIncrement(GitVersionContext context, Commit mergeCommit, Commit mergedHead, Commit findMergeBase)
142+
private static SemanticVersion IncrementForEachCommit(GitVersionContext context, List<Commit> directCommits, SemanticVersion mainlineVersion)
143+
{
144+
foreach (var directCommit in directCommits)
145+
{
146+
var directCommitIncrement = IncrementStrategyFinder.GetIncrementForCommits(context, new[]
147+
{
148+
directCommit
149+
}) ?? VersionField.Patch;
150+
mainlineVersion = mainlineVersion.IncrementVersion(directCommitIncrement);
151+
Logger.WriteInfo(string.Format("Direct commit on master {0} incremented base versions {1}, now {2}",
152+
directCommit.Sha, directCommitIncrement, mainlineVersion));
153+
}
154+
return mainlineVersion;
155+
}
156+
157+
private static VersionField FindMessageIncrement(
158+
GitVersionContext context, Commit mergeCommit, Commit mergedHead, Commit findMergeBase, List<Commit> commitLog)
121159
{
122160
var filter = new CommitFilter
123161
{
124162
IncludeReachableFrom = mergedHead,
125163
ExcludeReachableFrom = findMergeBase
126164
};
127-
var commits = context.Repository.Commits.QueryBy(filter).ToList();
128-
// Need to include merge commit in increment cal
129-
return IncrementStrategyFinder.GetIncrementForCommits(context, new [] { mergeCommit }.Union(commits)) ?? VersionField.Patch;
165+
var commits = new[] { mergeCommit }.Union(context.Repository.Commits.QueryBy(filter)).ToList();
166+
commitLog.RemoveAll(c => commits.Any(c1 => c1.Sha == c.Sha));
167+
return IncrementStrategyFinder.GetIncrementForCommits(context, commits) ?? VersionField.Patch;
130168
}
131169

132170
private Commit GetMergedHead(Commit mergeCommit)

0 commit comments

Comments
 (0)