Skip to content

Commit d69d232

Browse files
authored
Merge pull request #301 from ap0llo/master
Allow incrementing the "build" of the version in the prepare-release command
2 parents b40cc8a + d340465 commit d69d232

File tree

9 files changed

+114
-27
lines changed

9 files changed

+114
-27
lines changed

doc/nbgv-cli.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,11 @@ The behaviour of the `prepare-release` command can be customized in
103103
}
104104
```
105105

106-
| Property | Default value | Description |
107-
|------------------|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
108-
| branchName | `v{version}` | Defines the format of release branch names. The value must include a `{version}` placeholder. |
109-
| versionIncremnt | `minor` | Specifies which part of the version on the current branch is incremented when preparing a release. Allowed values are `minor` and `major`. |
110-
| firstUnstableTag | `alpha` | Specified the unstable tag to use for the main branch. |
106+
| Property | Default value | Description |
107+
|------------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
108+
| branchName | `v{version}` | Defines the format of release branch names. The value must include a `{version}` placeholder. |
109+
| versionIncremnt | `minor` | Specifies which part of the version on the current branch is incremented when preparing a release. Allowed values are `major`, `minor` and `build`. |
110+
| firstUnstableTag | `alpha` | Specified the unstable tag to use for the main branch. |
111111

112112
## Learn more
113113

src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,16 @@ public void PrepeareRelease_ReleaseBranchWithVersionDecrement(string initialVers
209209
[InlineData("1.2-beta", "v{version}release", ReleaseVersionIncrement.Minor, "alpha", "rc", null, "v1.2release", "1.2-rc", "1.3-alpha")]
210210
[InlineData("1.2-beta.{height}", "v{version}release", ReleaseVersionIncrement.Minor, "alpha", null, null, "v1.2release", "1.2", "1.3-alpha.{height}")]
211211
[InlineData("1.2-beta.{height}", "v{version}release", ReleaseVersionIncrement.Minor, "alpha", "rc", null, "v1.2release", "1.2-rc.{height}", "1.3-alpha.{height}")]
212-
// modify release.versionIncrement
212+
// modify release.versionIncrement: "Major"
213213
[InlineData("1.2-beta", null, ReleaseVersionIncrement.Major, "alpha", null, null, "v1.2", "1.2", "2.0-alpha")]
214214
[InlineData("1.2-beta", null, ReleaseVersionIncrement.Major, "alpha", "rc", null, "v1.2", "1.2-rc", "2.0-alpha")]
215215
[InlineData("1.2-beta.{height}", null, ReleaseVersionIncrement.Major, "alpha", null, null, "v1.2", "1.2", "2.0-alpha.{height}")]
216216
[InlineData("1.2-beta.{height}", null, ReleaseVersionIncrement.Major, "alpha", "rc", null, "v1.2", "1.2-rc.{height}", "2.0-alpha.{height}")]
217+
// modify release.versionIncrement: "Build"
218+
[InlineData("1.2.3-beta", null, ReleaseVersionIncrement.Build, "alpha", null, null, "v1.2.3", "1.2.3", "1.2.4-alpha")]
219+
[InlineData("1.2.3-beta", null, ReleaseVersionIncrement.Build, "alpha", "rc", null, "v1.2.3", "1.2.3-rc", "1.2.4-alpha")]
220+
[InlineData("1.2.3-beta.{height}", null, ReleaseVersionIncrement.Build, "alpha", null, null, "v1.2.3", "1.2.3", "1.2.4-alpha.{height}")]
221+
[InlineData("1.2.3-beta.{height}", null, ReleaseVersionIncrement.Build, "alpha", "rc", null, "v1.2.3", "1.2.3-rc.{height}", "1.2.4-alpha.{height}")]
217222
// modify release.firstUnstableTag
218223
[InlineData("1.2-beta", null, ReleaseVersionIncrement.Minor, "preview", null, null, "v1.2", "1.2", "1.3-preview")]
219224
[InlineData("1.2-beta", null, ReleaseVersionIncrement.Minor, "preview", "rc", null, "v1.2", "1.2-rc", "1.3-preview")]
@@ -380,6 +385,27 @@ public void PrepareRelease_DetachedHead()
380385
Assert.Equal(ReleasePreparationError.DetachedHead, ex.Error);
381386
}
382387

388+
[Fact]
389+
public void PrepareRelease_InvalidVersionIncrement()
390+
{
391+
// create and configure repository
392+
this.InitializeSourceControl();
393+
this.Repo.Config.Set("user.name", this.Signer.Name, ConfigurationLevel.Local);
394+
this.Repo.Config.Set("user.email", this.Signer.Email, ConfigurationLevel.Local);
395+
396+
// create version.json
397+
var versionOptions = new VersionOptions()
398+
{
399+
Version = SemanticVersion.Parse("1.2"),
400+
Release = new ReleaseOptions() { VersionIncrement = ReleaseVersionIncrement.Build }
401+
};
402+
this.WriteVersionFile(versionOptions);
403+
404+
// running PrepareRelease should result in an error
405+
// because a 2-segment version is incompatibale with a increment setting of "build"
406+
this.AssertError(() => new ReleaseManager().PrepareRelease(this.RepoPath), ReleasePreparationError.InvalidVersionIncrementSetting);
407+
}
408+
383409
private void AssertError(Action testCode, ReleasePreparationError expectedError)
384410
{
385411
var ex = Assert.Throws<ReleasePreparationException>(testCode);

src/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Reflection;
34
using Nerdbank.GitVersioning;
45
using Xunit;
@@ -26,7 +27,13 @@ public class SemanticVersionExtensionsTests
2627
[InlineData("1.2.3", ReleaseVersionIncrement.Major, "2.0.0")]
2728
[InlineData("1.2.3.4", ReleaseVersionIncrement.Minor, "1.3.0.0")]
2829
[InlineData("1.2.3.4", ReleaseVersionIncrement.Major, "2.0.0.0")]
29-
public void IncrementVersion(string currentVersionString, ReleaseVersionIncrement increment, string expectedVersionString)
30+
[InlineData("1.2.3", ReleaseVersionIncrement.Build, "1.2.4")]
31+
[InlineData("1.2.3.4", ReleaseVersionIncrement.Build, "1.2.4.0")]
32+
[InlineData("1.2.3-tag", ReleaseVersionIncrement.Build, "1.2.4-tag")]
33+
[InlineData("1.2.3-tag+metadata", ReleaseVersionIncrement.Build, "1.2.4-tag+metadata")]
34+
[InlineData("1.2.3.4-tag", ReleaseVersionIncrement.Build, "1.2.4.0-tag")]
35+
[InlineData("1.2.3.4-tag+metadata", ReleaseVersionIncrement.Build, "1.2.4.0-tag+metadata")]
36+
public void Increment(string currentVersionString, ReleaseVersionIncrement increment, string expectedVersionString)
3037
{
3138
var currentVersion = SemanticVersion.Parse(currentVersionString);
3239
var expectedVersion = SemanticVersion.Parse(expectedVersionString);
@@ -36,6 +43,15 @@ public void IncrementVersion(string currentVersionString, ReleaseVersionIncremen
3643
Assert.Equal(expectedVersion, actualVersion);
3744
}
3845

46+
[Theory]
47+
[InlineData("1.0", ReleaseVersionIncrement.Build)]
48+
public void Increment_InvalidIncrement(string currentVersionString, ReleaseVersionIncrement increment)
49+
{
50+
var currentVersion = SemanticVersion.Parse(currentVersionString);
51+
52+
Assert.Throws<ArgumentException>(() => currentVersion.Increment(increment));
53+
}
54+
3955
[Theory]
4056
// no prerelease tag in input version
4157
[InlineData("1.2", "pre", "1.2-pre")]

src/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,12 @@ public void Inherit_AllowsOmissionOfVersion()
8787

8888
[Theory]
8989
[InlineData(@"{ ""version"": ""2.3"", ""release"": { } }")]
90-
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""{0}"" } }")]
91-
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""release/v{0}"" } }")]
92-
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""prefix{0}suffix"" } }")]
93-
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""{0}"", ""versionIncrement"" : ""major"" } }")]
94-
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""{0}"", ""versionIncrement"" : ""minor"" } }")]
90+
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""{version}"" } }")]
91+
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""release/v{version}"" } }")]
92+
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""prefix{version}suffix"" } }")]
93+
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""{version}"", ""versionIncrement"" : ""major"" } }")]
94+
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""{version}"", ""versionIncrement"" : ""minor"" } }")]
95+
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""{version}"", ""versionIncrement"" : ""build"" } }")]
9596
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""firstUnstableTag"" : ""pre"" } }")]
9697
public void ReleaseProperty_ValidJson(string json)
9798
{
@@ -100,9 +101,10 @@ public void ReleaseProperty_ValidJson(string json)
100101
}
101102

102103
[Theory]
103-
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""versionIncrement"" : ""build"" } }")]
104+
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""versionIncrement"" : ""revision"" } }")]
104105
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""formatWithoutPlaceholder"" } }")]
105-
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""unknownProperty"" : ""value"" } }")]
106+
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""formatWithoutPlaceholder{0}"" } }")]
107+
[InlineData(@"{ ""version"": ""2.3"", ""release"": { ""unknownProperty"" : ""value"" } }")]
106108
public void ReleaseProperty_InvalidJson(string json)
107109
{
108110
this.json = JObject.Parse(json);

src/NerdBank.GitVersioning/ReleaseManager.cs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ public enum ReleasePreparationError
5656
/// HEAD is detached. A branch must be checked out first.
5757
/// </summary>
5858
DetachedHead,
59+
60+
/// <summary>
61+
/// The versionIncrement setting cannot be applied to the current version.
62+
/// </summary>
63+
InvalidVersionIncrementSetting,
5964
}
6065

6166
/// <summary>
@@ -125,14 +130,13 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag =
125130
this.stderr.WriteLine($"Failed to load version file for directory '{projectDirectory}'.");
126131
throw new ReleasePreparationException(ReleasePreparationError.NoVersionFile);
127132
}
128-
129-
var releaseOptions = versionOptions.ReleaseOrDefault;
130-
133+
131134
var releaseBranchName = this.GetReleaseBranchName(versionOptions);
132135
var originalBranchName = repository.Head.FriendlyName;
133136
var releaseVersion = string.IsNullOrEmpty(releaseUnstableTag)
134137
? versionOptions.Version.WithoutPrepreleaseTags()
135138
: versionOptions.Version.SetFirstPrereleaseTag(releaseUnstableTag);
139+
var nextDevVersion = this.GetNextDevVersion(versionOptions, nextVersion);
136140

137141
// check if the current branch is the release branch
138142
if (string.Equals(originalBranchName, releaseBranchName, StringComparison.OrdinalIgnoreCase))
@@ -157,10 +161,6 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag =
157161

158162
// update version on main branch
159163
Commands.Checkout(repository, originalBranchName);
160-
var nextDevVersion = nextVersion ??
161-
versionOptions.Version
162-
.Increment(releaseOptions.VersionIncrementOrDefault)
163-
.SetFirstPrereleaseTag(releaseOptions.FirstUnstableTagOrDefault);
164164
this.UpdateVersion(projectDirectory, repository, versionOptions.Version, nextDevVersion);
165165
this.stdout.WriteLine($"{originalBranchName} branch now tracks v{nextDevVersion} development.");
166166

@@ -272,5 +272,30 @@ private static bool IsVersionDecrement(SemanticVersion oldVersion, SemanticVersi
272272
return true;
273273
}
274274
}
275+
276+
private SemanticVersion GetNextDevVersion(VersionOptions versionOptions, SemanticVersion nextVersion)
277+
{
278+
if (nextVersion != null)
279+
return nextVersion;
280+
281+
var releaseOptions = versionOptions.ReleaseOrDefault;
282+
283+
// the increment is only valid if the current version has the required precision
284+
// increment settings "Major" and "Minor" are always valid
285+
// increment setting "Build" is only valid if the version has at lease three segments
286+
var isValidIncrement = releaseOptions.VersionIncrementOrDefault != VersionOptions.ReleaseVersionIncrement.Build ||
287+
versionOptions.Version.Version.Build >= 0;
288+
289+
// increment is ignored when the next version was specified explicitly
290+
if (!isValidIncrement)
291+
{
292+
this.stderr.WriteLine($"Cannot apply version increment 'build' to version '{versionOptions.Version}' because it only has major and minor segments");
293+
throw new ReleasePreparationException(ReleasePreparationError.InvalidVersionIncrementSetting);
294+
}
295+
296+
return versionOptions.Version
297+
.Increment(releaseOptions.VersionIncrementOrDefault)
298+
.SetFirstPrereleaseTag(releaseOptions.FirstUnstableTagOrDefault);
299+
}
275300
}
276301
}

src/NerdBank.GitVersioning/SemanticVersionExtensions.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,29 @@ internal static class SemanticVersionExtensions
1717
internal static SemanticVersion Increment(this SemanticVersion currentVersion, VersionOptions.ReleaseVersionIncrement increment)
1818
{
1919
Requires.NotNull(currentVersion, nameof(currentVersion));
20+
Requires.That(increment != VersionOptions.ReleaseVersionIncrement.Build || currentVersion.Version.Build >= 0, nameof(increment),
21+
"Cannot apply version increment '{0}' to version '{1}'", increment, currentVersion);
2022

2123
var major = currentVersion.Version.Major;
2224
var minor = currentVersion.Version.Minor;
25+
var build = currentVersion.Version.Build;
2326

2427
switch (increment)
2528
{
2629
case VersionOptions.ReleaseVersionIncrement.Major:
2730
major += 1;
2831
minor = 0;
32+
build = 0;
2933
break;
3034
case VersionOptions.ReleaseVersionIncrement.Minor:
3135
minor += 1;
36+
build = 0;
3237
break;
38+
39+
case VersionOptions.ReleaseVersionIncrement.Build:
40+
build += 1;
41+
break;
42+
3343
default:
3444
throw new ArgumentOutOfRangeException(nameof(increment));
3545
}
@@ -40,12 +50,12 @@ internal static SemanticVersion Increment(this SemanticVersion currentVersion, V
4050
if (currentVersion.Version.Build >= 0 && currentVersion.Version.Revision > 0)
4151
{
4252
// 4 segment version
43-
newVersion = new Version(major, minor, 0, 0);
53+
newVersion = new Version(major, minor, build, 0);
4454
}
4555
else if (currentVersion.Version.Build >= 0)
4656
{
4757
// 3 segment version
48-
newVersion = new Version(major, minor, 0);
58+
newVersion = new Version(major, minor, build);
4959
}
5060
else
5161
{

src/NerdBank.GitVersioning/VersionOptions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1139,7 +1139,12 @@ public enum ReleaseVersionIncrement
11391139
/// <summary>
11401140
/// Increment the minor version after creating a release branch
11411141
/// </summary>
1142-
Minor
1142+
Minor,
1143+
1144+
/// <summary>
1145+
/// Increment the build number (the third number in a version) after creating a release branch.
1146+
/// </summary>
1147+
Build,
11431148
}
11441149
}
11451150
}

src/NerdBank.GitVersioning/version.schema.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,13 @@
142142
"branchName": {
143143
"description": "Defines the format of release branch names. Format must include a placeholder '{version}' for the version",
144144
"type": "string",
145-
"pattern": ".*\\{0\\}.*",
145+
"pattern": ".*\\{version\\}.*",
146146
"default": "v{version}"
147147
},
148148
"versionIncrement": {
149149
"description": "Specifies which part of the version on the current branch is incremented when preparing a release.",
150150
"type": "string",
151-
"enum": [ "major", "minor" ],
151+
"enum": [ "major", "minor", "build" ],
152152
"default": "minor"
153153
},
154154
"firstUnstableTag": {

src/nbgv/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ private enum ExitCodes
4545
BranchAlreadyExists,
4646
UserNotConfigured,
4747
DetachedHead,
48+
InvalidVersionIncrementSetting,
4849
}
4950

5051
private static ExitCodes exitCode;
@@ -606,6 +607,8 @@ private static ExitCodes OnPrepareReleaseCommand(string projectPath, string prer
606607
return ExitCodes.UserNotConfigured;
607608
case ReleaseManager.ReleasePreparationError.DetachedHead:
608609
return ExitCodes.DetachedHead;
610+
case ReleaseManager.ReleasePreparationError.InvalidVersionIncrementSetting:
611+
return ExitCodes.InvalidVersionIncrementSetting;
609612
default:
610613
Report.Fail($"{nameof(ReleaseManager.ReleasePreparationError)}: {ex.Error}");
611614
return (ExitCodes)(-1);

0 commit comments

Comments
 (0)