Skip to content

Commit 90a504f

Browse files
committed
Add support for indicating change severity in commit messages
Adds two new increment strategies: CommitMessage and MergeMessage. While active, the version increment is determined by reading commit/merge commit messages for markers describing the change severity. For example, "+semver: breaking" will force a major version bump.
1 parent e7cdf5e commit 90a504f

File tree

10 files changed

+152
-12
lines changed

10 files changed

+152
-12
lines changed

src/GitVersionCore.Tests/TestEffectiveConfiguration.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ public TestEffectiveConfiguration(
1414
bool preventIncrementForMergedBranchVersion = false,
1515
string tagNumberPattern = null,
1616
string continuousDeploymentFallbackTag = "ci",
17-
bool trackMergeTarget = false) :
17+
bool trackMergeTarget = false,
18+
string majorMessage = null,
19+
string minorMessage = null,
20+
IncrementStrategy messageFallback = IncrementStrategy.Patch) :
1821
base(assemblyVersioningScheme, versioningMode, gitTagPrefix, tag, nextVersion, IncrementStrategy.Patch,
1922
branchPrefixToTrim, preventIncrementForMergedBranchVersion, tagNumberPattern, continuousDeploymentFallbackTag,
20-
trackMergeTarget)
23+
trackMergeTarget,
24+
majorMessage, minorMessage, messageFallback)
2125
{
2226
}
2327
}

src/GitVersionCore/Configuration/BranchConfig.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public BranchConfig(BranchConfig branchConfiguration)
1616
PreventIncrementOfMergedBranchVersion = branchConfiguration.PreventIncrementOfMergedBranchVersion;
1717
TagNumberPattern = branchConfiguration.TagNumberPattern;
1818
TrackMergeTarget = branchConfiguration.TrackMergeTarget;
19+
MessageFallbackStrategy = branchConfiguration.MessageFallbackStrategy;
1920
}
2021

2122
[YamlMember(Alias = "mode")]
@@ -38,5 +39,14 @@ public BranchConfig(BranchConfig branchConfiguration)
3839

3940
[YamlMember(Alias = "track-merge-target")]
4041
public bool? TrackMergeTarget { get; set; }
42+
43+
[YamlMember(Alias = "major-version-bump-message")]
44+
public string MajorVersionBumpMessage { get; set; }
45+
46+
[YamlMember(Alias = "minor-version-bump-message")]
47+
public string MinorVersionBumpMessage { get; set; }
48+
49+
[YamlMember(Alias = "message-fallback")]
50+
public IncrementStrategy? MessageFallbackStrategy { get; set; }
4151
}
4252
}

src/GitVersionCore/Configuration/IncrementStrategy.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ public enum IncrementStrategy
99
/// <summary>
1010
/// Uses the increment strategy from the branch the current branch was branched from
1111
/// </summary>
12-
Inherit
12+
Inherit,
13+
/// <summary>
14+
/// Parse commit messages for indications of change severity. If none are found, <c>CommitMessage</c> behaves like <c>Patch</c>.
15+
/// </summary>
16+
CommitMessage,
17+
/// <summary>
18+
/// Parse merge commit messages for indications of change severity. If none are found, <c>MergeMessage</c> behaves like <c>Patch</c>.
19+
/// </summary>
20+
MergeMessage
1321
}
1422
}

src/GitVersionCore/EffectiveConfiguration.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ public EffectiveConfiguration(
1313
bool preventIncrementForMergedBranchVersion,
1414
string tagNumberPattern,
1515
string continuousDeploymentFallbackTag,
16-
bool trackMergeTarget)
16+
bool trackMergeTarget,
17+
string majorVersionBumpMessage,
18+
string minorVersionBumpMessage,
19+
IncrementStrategy messageFallback)
1720
{
1821
AssemblyVersioningScheme = assemblyVersioningScheme;
1922
VersioningMode = versioningMode;
@@ -26,6 +29,9 @@ public EffectiveConfiguration(
2629
TagNumberPattern = tagNumberPattern;
2730
ContinuousDeploymentFallbackTag = continuousDeploymentFallbackTag;
2831
TrackMergeTarget = trackMergeTarget;
32+
MajorVersionBumpMessage = majorVersionBumpMessage;
33+
MinorVersionBumpMessage = minorVersionBumpMessage;
34+
MessageFallbackStrategy = messageFallback;
2935
}
3036

3137
public VersioningMode VersioningMode { get; private set; }
@@ -55,5 +61,11 @@ public EffectiveConfiguration(
5561
public string ContinuousDeploymentFallbackTag { get; private set; }
5662

5763
public bool TrackMergeTarget { get; private set; }
64+
65+
public string MajorVersionBumpMessage { get; private set; }
66+
67+
public string MinorVersionBumpMessage { get; private set; }
68+
69+
public IncrementStrategy MessageFallbackStrategy { get; private set; }
5870
}
5971
}

src/GitVersionCore/GitVersionContext.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,16 @@ void CalculateEffectiveConfiguration()
102102
var nextVersion = configuration.NextVersion;
103103
var assemblyVersioningScheme = configuration.AssemblyVersioningScheme.Value;
104104
var gitTagPrefix = configuration.TagPrefix;
105+
var majorMessage = currentBranchConfig.Value.MajorVersionBumpMessage ?? @"\+semver:\s?(breaking|major)";
106+
var minorMessage = currentBranchConfig.Value.MinorVersionBumpMessage ?? @"\+semver:\s?(feature|minor)";
107+
var messageFallback = currentBranchConfig.Value.MessageFallbackStrategy ?? IncrementStrategy.Patch;
105108
Configuration = new EffectiveConfiguration(
106109
assemblyVersioningScheme, versioningMode, gitTagPrefix,
107110
tag, nextVersion, incrementStrategy, currentBranchConfig.Key,
108111
preventIncrementForMergedBranchVersion,
109112
tagNumberPattern, configuration.ContinuousDeploymentFallbackTag,
110-
trackMergeTarget);
113+
trackMergeTarget,
114+
majorMessage, minorMessage, messageFallback);
111115
}
112116
}
113117
}

src/GitVersionCore/GitVersionCore.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
<Compile Include="Helpers\IFileSystem.cs" />
114114
<Compile Include="Helpers\ProcessHelper.cs" />
115115
<Compile Include="Helpers\ServiceMessageEscapeHelper.cs" />
116+
<Compile Include="IncrementStrategyFinder.cs" />
116117
<Compile Include="OutputVariables\VersionVariables.cs" />
117118
<Compile Include="Extensions\ExtensionMethods.git.cs" />
118119
<Compile Include="SemanticVersionExtensions.cs" />
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
namespace GitVersion
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text.RegularExpressions;
7+
using VersionCalculation.BaseVersionCalculators;
8+
using LibGit2Sharp;
9+
10+
public static class IncrementStrategyFinder
11+
{
12+
public static VersionField DetermineIncrementedField(GitVersionContext context, BaseVersion baseVersion)
13+
{
14+
if (context.Configuration.Increment != IncrementStrategy.CommitMessage && context.Configuration.Increment != IncrementStrategy.MergeMessage)
15+
{
16+
return SimpleIncrement(context.Configuration.Increment);
17+
}
18+
19+
var commits = GetIntermediateCommits(context.Repository, baseVersion.BaseVersionSource, context.CurrentCommit);
20+
21+
if (context.Configuration.Increment == IncrementStrategy.MergeMessage)
22+
{
23+
commits = commits.Where(c => c.Parents.Count() > 1);
24+
}
25+
26+
var majorRegex = MajorChangeRegex(context.Configuration.MajorVersionBumpMessage);
27+
var minorRegex = MinorChangeRegex(context.Configuration.MinorVersionBumpMessage);
28+
29+
VersionField biggestField = SimpleIncrement(context.Configuration.MessageFallbackStrategy);
30+
foreach (var commit in commits)
31+
{
32+
if (majorRegex.IsMatch(commit.Message))
33+
{
34+
biggestField = VersionField.Major;
35+
break;
36+
}
37+
38+
if (biggestField != VersionField.Minor && minorRegex.IsMatch(commit.Message))
39+
{
40+
biggestField = VersionField.Minor;
41+
}
42+
}
43+
44+
return biggestField;
45+
}
46+
47+
private static VersionField SimpleIncrement(IncrementStrategy strategy)
48+
{
49+
switch (strategy)
50+
{
51+
case IncrementStrategy.None:
52+
return VersionField.None;
53+
case IncrementStrategy.Major:
54+
return VersionField.Major;
55+
case IncrementStrategy.Minor:
56+
return VersionField.Minor;
57+
case IncrementStrategy.Patch:
58+
return VersionField.Patch;
59+
default:
60+
throw new ArgumentOutOfRangeException("strategy", strategy, null);
61+
}
62+
}
63+
64+
private static IEnumerable<Commit> GetIntermediateCommits(IRepository repo, Commit baseCommit, Commit headCommit)
65+
{
66+
var filter = new CommitFilter
67+
{
68+
Since = headCommit,
69+
Until = baseCommit,
70+
SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Reverse
71+
};
72+
73+
return repo.Commits.QueryBy(filter);
74+
}
75+
76+
private static Regex MajorChangeRegex(string pattern)
77+
{
78+
return new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
79+
}
80+
81+
private static Regex MinorChangeRegex(string pattern)
82+
{
83+
return new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
84+
}
85+
}
86+
}

src/GitVersionCore/SemanticVersion.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,25 +281,25 @@ public string ToString(string format, IFormatProvider formatProvider = null)
281281
}
282282
}
283283

284-
public SemanticVersion IncrementVersion(IncrementStrategy incrementStrategy)
284+
public SemanticVersion IncrementVersion(VersionField incrementStrategy)
285285
{
286286
var incremented = new SemanticVersion(this);
287287
if (!incremented.PreReleaseTag.HasTag())
288288
{
289289
switch (incrementStrategy)
290290
{
291-
case IncrementStrategy.None:
291+
case VersionField.None:
292292
break;
293-
case IncrementStrategy.Major:
293+
case VersionField.Major:
294294
incremented.Major++;
295295
incremented.Minor = 0;
296296
incremented.Patch = 0;
297297
break;
298-
case IncrementStrategy.Minor:
298+
case VersionField.Minor:
299299
incremented.Minor++;
300300
incremented.Patch = 0;
301301
break;
302-
case IncrementStrategy.Patch:
302+
case VersionField.Patch:
303303
incremented.Patch++;
304304
break;
305305
default:
@@ -318,4 +318,12 @@ public SemanticVersion IncrementVersion(IncrementStrategy incrementStrategy)
318318
return incremented;
319319
}
320320
}
321+
322+
public enum VersionField
323+
{
324+
None,
325+
Patch,
326+
Minor,
327+
Major
328+
}
321329
}

src/GitVersionCore/VersionCalculation/BaseVersionCalculator.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,13 @@ public BaseVersion GetBaseVersion(GitVersionContext context)
7474

7575
static SemanticVersion MaybeIncrement(GitVersionContext context, BaseVersion version)
7676
{
77-
return version.ShouldIncrement ? version.SemanticVersion.IncrementVersion(context.Configuration.Increment) : version.SemanticVersion;
77+
if (version.ShouldIncrement)
78+
{
79+
var field = IncrementStrategyFinder.DetermineIncrementedField(context, version);
80+
return version.SemanticVersion.IncrementVersion(field);
81+
}
82+
83+
return version.SemanticVersion;
7884
}
7985
}
8086
}

src/GitVersionCore/VersionCalculation/NextVersionCalculator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ public SemanticVersion FindVersion(GitVersionContext context)
4040
var semver = baseVersion.SemanticVersion;
4141
if (baseVersion.ShouldIncrement)
4242
{
43-
semver = semver.IncrementVersion(context.Configuration.Increment);
43+
var field = IncrementStrategyFinder.DetermineIncrementedField(context, baseVersion);
44+
semver = semver.IncrementVersion(field);
4445
}
4546
else Logger.WriteInfo("Skipping version increment");
4647

0 commit comments

Comments
 (0)