Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions doc/nbgv-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,23 @@ For each branch, the following properties are provided:
**Note:** When the current branch is already the release branch for the current version, no new branch will be created.
In that case, the `NewBranch` property will be `null`.

### Customizing the `prepare-release` commit message

By default, the `prepare-release` command generates a commit message with the format "Set version to {version}".
A switch allows you to customize the commit message, using `{0}` as a placeholder for the version.

For example, running the following command:

```
nbgv prepare-release --commit-message-pattern "Custom commit message pattern - {0} custom message"
```

So your commit message is going to be this:

```
Custom commit message pattern - 1.0 custom message
```

## Creating a version tag

The `tag` command automates the task of tagging a commit with a version.
Expand Down
22 changes: 16 additions & 6 deletions src/NerdBank.GitVersioning/ReleaseManager.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation and Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Globalization;
using LibGit2Sharp;
using Nerdbank.GitVersioning.LibGit2;
using Newtonsoft.Json;
Expand Down Expand Up @@ -127,7 +128,10 @@ public enum ReleaseManagerOutputMode
/// <param name="outputMode">
/// The output format to use for writing to stdout.
/// </param>
public void PrepareRelease(string projectDirectory, string releaseUnstableTag = null, Version nextVersion = null, VersionOptions.ReleaseVersionIncrement? versionIncrement = null, ReleaseManagerOutputMode outputMode = default)
/// <param name="unformattedCommitMessage">
/// An optional, custom message to use for the commit that sets the new version number. May use <c>{0}</c> to substitute the new version number.
/// </param>
public void PrepareRelease(string projectDirectory, string releaseUnstableTag = null, Version nextVersion = null, VersionOptions.ReleaseVersionIncrement? versionIncrement = null, ReleaseManagerOutputMode outputMode = default, string unformattedCommitMessage = null)
{
Requires.NotNull(projectDirectory, nameof(projectDirectory));

Expand Down Expand Up @@ -168,7 +172,7 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag =
this.WriteToOutput(releaseInfo);
}

this.UpdateVersion(context, versionOptions.Version, releaseVersion);
this.UpdateVersion(context, versionOptions.Version, releaseVersion, unformattedCommitMessage);
return;
}

Expand All @@ -192,7 +196,7 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag =
// create release branch and update version
Branch releaseBranch = repository.CreateBranch(releaseBranchName);
global::LibGit2Sharp.Commands.Checkout(repository, releaseBranch);
this.UpdateVersion(context, versionOptions.Version, releaseVersion);
this.UpdateVersion(context, versionOptions.Version, releaseVersion, unformattedCommitMessage);

if (outputMode == ReleaseManagerOutputMode.Text)
{
Expand All @@ -201,7 +205,7 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag =

// update version on main branch
global::LibGit2Sharp.Commands.Checkout(repository, originalBranchName);
this.UpdateVersion(context, versionOptions.Version, nextDevVersion);
this.UpdateVersion(context, versionOptions.Version, nextDevVersion, unformattedCommitMessage);

if (outputMode == ReleaseManagerOutputMode.Text)
{
Expand Down Expand Up @@ -261,7 +265,7 @@ private string GetReleaseBranchName(VersionOptions versionOptions)
return branchNameFormat.Replace("{version}", versionOptions.Version.Version.ToString());
}

private void UpdateVersion(LibGit2Context context, SemanticVersion oldVersion, SemanticVersion newVersion)
private void UpdateVersion(LibGit2Context context, SemanticVersion oldVersion, SemanticVersion newVersion, string unformattedCommitMessage)
{
Requires.NotNull(context, nameof(context));

Expand Down Expand Up @@ -290,7 +294,13 @@ private void UpdateVersion(LibGit2Context context, SemanticVersion oldVersion, S
// Author a commit only if we effectively changed something.
if (!context.Repository.Head.Tip.Tree.Equals(context.Repository.Index.WriteToTree()))
{
context.Repository.Commit($"Set version to '{versionOptions.Version}'", signature, signature, new CommitOptions() { AllowEmptyCommit = false });
if (string.IsNullOrEmpty(unformattedCommitMessage))
{
unformattedCommitMessage = "Set version to '{0}'";
}

string commitMessage = string.Format(CultureInfo.CurrentCulture, unformattedCommitMessage, versionOptions.Version);
context.Repository.Commit(commitMessage, signature, signature, new CommitOptions() { AllowEmptyCommit = false });
}
}
}
Expand Down
23 changes: 20 additions & 3 deletions src/nbgv/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Build.Construction;
Expand Down Expand Up @@ -69,6 +70,7 @@ private enum ExitCodes
ShallowClone,
InternalError,
InvalidTagNameSetting,
InvalidUnformattedCommitMessage,
}

private static bool AlwaysUseLibGit2 => string.Equals(Environment.GetEnvironmentVariable("NBGV_GitEngine"), "LibGit2", StringComparison.Ordinal);
Expand Down Expand Up @@ -217,6 +219,7 @@ private static Parser BuildCommandLine()
var nextVersion = new Option<string>("--nextVersion", "The version to set for the current branch. If omitted, the next version is determined automatically by incrementing the current version.");
var versionIncrement = new Option<string>("--versionIncrement", "Overrides the 'versionIncrement' setting set in version.json for determining the next version of the current branch.");
var format = new Option<string>(new[] { "--format", "-f" }, $"The format to write information about the release. Allowed values are: {string.Join(", ", SupportedFormats)}. The default is {DefaultOutputFormat}.").FromAmong(SupportedFormats);
var unformattedCommitMessage = new Option<string>("--commit-message-pattern", "A custom message to use for the commit that changes the version number. May include {0} for the version number. If not specified, the default is \"Set version to '{0}'\".");
var tagArgument = new Argument<string>("tag", "The prerelease tag to apply on the release branch (if any). If not specified, any existing prerelease tag will be removed. The preceding hyphen may be omitted.")
{
Arity = ArgumentArity.ZeroOrOne,
Expand All @@ -227,10 +230,11 @@ private static Parser BuildCommandLine()
nextVersion,
versionIncrement,
format,
unformattedCommitMessage,
tagArgument,
};

prepareRelease.SetHandler(OnPrepareReleaseCommand, project, nextVersion, versionIncrement, format, tagArgument);
prepareRelease.SetHandler(OnPrepareReleaseCommand, project, nextVersion, versionIncrement, format, tagArgument, unformattedCommitMessage);
}

var root = new RootCommand($"{ThisAssembly.AssemblyTitle} v{ThisAssembly.AssemblyInformationalVersion}")
Expand Down Expand Up @@ -710,7 +714,7 @@ private static Task<int> OnCloudCommand(string project, string[] metadata, strin
return Task.FromResult((int)ExitCodes.OK);
}

private static Task<int> OnPrepareReleaseCommand(string project, string nextVersion, string versionIncrement, string format, string tag)
private static Task<int> OnPrepareReleaseCommand(string project, string nextVersion, string versionIncrement, string format, string tag, string unformattedCommitMessage)
{
// validate project path property
string searchPath = GetSpecifiedOrCurrentDirectoryPath(project);
Expand Down Expand Up @@ -763,11 +767,24 @@ private static Task<int> OnPrepareReleaseCommand(string project, string nextVers
return Task.FromResult((int)ExitCodes.UnsupportedFormat);
}

if (!string.IsNullOrEmpty(unformattedCommitMessage))
{
try
{
string.Format(unformattedCommitMessage, "FormatValidator");
}
catch (FormatException ex)
{
Console.Error.WriteLine($"Invalid commit message pattern: {ex.Message}");
return Task.FromResult((int)ExitCodes.InvalidUnformattedCommitMessage);
}
}

// run prepare-release
try
{
var releaseManager = new ReleaseManager(Console.Out, Console.Error);
releaseManager.PrepareRelease(searchPath, tag, nextVersionParsed, versionIncrementParsed, outputMode);
releaseManager.PrepareRelease(searchPath, tag, nextVersionParsed, versionIncrementParsed, outputMode, unformattedCommitMessage);
return Task.FromResult((int)ExitCodes.OK);
}
catch (ReleaseManager.ReleasePreparationException ex)
Expand Down
28 changes: 28 additions & 0 deletions test/Nerdbank.GitVersioning.Tests/ReleaseManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,34 @@ public void PrepareRelease_ResetsVersionHeightOffset()
Assert.Equal(expectedReleaseVersionOptions, releaseVersion);
}

[Theory]
[InlineData("1.0-beta", "{0} Custom commit message pattern", "1.0 Custom commit message pattern")]
[InlineData("1.0-beta", "Custom commit message pattern - {0} custom message", "Custom commit message pattern - 1.0 custom message")]
[InlineData("1.0-beta", "Custom commit message pattern - {0}", "Custom commit message pattern - 1.0")]
[InlineData("1.0-beta", "{0}", "1.0")]
public void PrepareRelease_WithCustomCommitMessagePattern(string initialVersion, string commitMessagePattern, string expectedCommitMessage)
{
// Create and configure the repository
this.InitializeSourceControl();

var versionOptions = new VersionOptions()
{
Version = SemanticVersion.Parse(initialVersion),
};

this.WriteVersionFile(versionOptions);

// Run PrepareRelease with the custom commit message pattern
var releaseManager = new ReleaseManager();
releaseManager.PrepareRelease(this.RepoPath, unformattedCommitMessage: commitMessagePattern);

// Verify that the commit message on the release branch matches the expected pattern
string releaseBranchName = "v1.0";
Branch releaseBranch = this.LibGit2Repository.Branches[releaseBranchName];
Commit releaseBranchCommit = releaseBranch.Tip;
Assert.Equal(expectedCommitMessage, releaseBranchCommit.MessageShort);
}

/// <inheritdoc/>
protected override void InitializeSourceControl(bool withInitialCommit = true)
{
Expand Down