Skip to content

Commit 7d22ed6

Browse files
authored
Merge pull request #875 from ronaldbarendse/feature/tagname
Add `tagName` option to customize generated tag name
2 parents 175cea8 + edb2d5f commit 7d22ed6

File tree

6 files changed

+109
-13
lines changed

6 files changed

+109
-13
lines changed

doc/nbgv-cli.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,44 @@ For each branch, the following properties are provided:
165165
**Note:** When the current branch is already the release branch for the current version, no new branch will be created.
166166
In that case, the `NewBranch` property will be `null`.
167167

168+
## Creating a version tag
169+
170+
The `tag` command automates the task of tagging a commit with a version.
171+
172+
To create a version tag, run:
173+
174+
```ps1
175+
nbgv tag
176+
```
177+
178+
This will:
179+
180+
1. Read version.json to ascertain the version under development, and the naming convention of tag names.
181+
1. Create a new tag for that version.
182+
183+
You can optionally include a version or commit id to create a new tag for an older version/commit, e.g.:
184+
185+
```ps1
186+
nbgv tag 1.0.0
187+
```
188+
189+
### Customizing the behaviour of `tag`
190+
191+
The behaviour of the `tag` command can be customized in `version.json`:
192+
193+
```json
194+
{
195+
"version": "1.0",
196+
"release": {
197+
"tagName" : "v{version}"
198+
}
199+
}
200+
```
201+
202+
| Property | Default value | Description |
203+
|----------|---------------|-------------------------------------------------------------------------------------------------|
204+
| tagName | `v{version}` | Defines the format of tag names. Format must include a placeholder '{version}' for the version. |
205+
168206
## Learn more
169207

170208
There are several more sub-commands and switches to each to help you build and maintain your projects, find a commit that built a particular version later on, create tags, etc.

doc/versionJson.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ The content of the version.json file is a JSON serialized object with these prop
5959
}
6060
},
6161
"release" : {
62+
"tagName" : "v{version}",
6263
"branchName" : "v{version}",
6364
"versionIncrement" : "minor",
6465
"firstUnstableTag" : "alpha"

src/NerdBank.GitVersioning/VersionOptions.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,7 +1442,7 @@ public int GetHashCode(CloudBuildNumberCommitIdOptions? obj)
14421442
}
14431443

14441444
/// <summary>
1445-
/// Encapsulates settings for the "prepare-release" command.
1445+
/// Encapsulates settings for the "prepare-release" and "tag" commands.
14461446
/// </summary>
14471447
public class ReleaseOptions : IEquatable<ReleaseOptions>
14481448
{
@@ -1452,6 +1452,7 @@ public class ReleaseOptions : IEquatable<ReleaseOptions>
14521452
internal static readonly ReleaseOptions DefaultInstance = new ReleaseOptions()
14531453
{
14541454
isFrozen = true,
1455+
tagName = "v{version}",
14551456
branchName = "v{version}",
14561457
versionIncrement = ReleaseVersionIncrement.Minor,
14571458
firstUnstableTag = "alpha",
@@ -1460,6 +1461,9 @@ public class ReleaseOptions : IEquatable<ReleaseOptions>
14601461
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
14611462
private bool isFrozen;
14621463

1464+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
1465+
private string? tagName;
1466+
14631467
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
14641468
private string? branchName;
14651469

@@ -1482,11 +1486,28 @@ public ReleaseOptions()
14821486
/// <param name="copyFrom">The existing instance to copy from.</param>
14831487
public ReleaseOptions(ReleaseOptions copyFrom)
14841488
{
1489+
this.tagName = copyFrom.tagName;
14851490
this.branchName = copyFrom.branchName;
14861491
this.versionIncrement = copyFrom.versionIncrement;
14871492
this.firstUnstableTag = copyFrom.firstUnstableTag;
14881493
}
14891494

1495+
/// <summary>
1496+
/// Gets or sets the tag name template for tagging.
1497+
/// </summary>
1498+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
1499+
public string? TagName
1500+
{
1501+
get => this.tagName;
1502+
set => this.SetIfNotReadOnly(ref this.tagName, value);
1503+
}
1504+
1505+
/// <summary>
1506+
/// Gets the tag name template for tagging.
1507+
/// </summary>
1508+
[JsonIgnore]
1509+
public string TagNameOrDefault => this.TagName ?? DefaultInstance.TagName!;
1510+
14901511
/// <summary>
14911512
/// Gets or sets the branch name template for release branches.
14921513
/// </summary>
@@ -1498,7 +1519,7 @@ public string? BranchName
14981519
}
14991520

15001521
/// <summary>
1501-
/// Gets the set branch name template for release branches.
1522+
/// Gets the branch name template for release branches.
15021523
/// </summary>
15031524
[JsonIgnore]
15041525
public string BranchNameOrDefault => this.BranchName ?? DefaultInstance.BranchName!;
@@ -1593,7 +1614,8 @@ public bool Equals(ReleaseOptions? x, ReleaseOptions? y)
15931614
return false;
15941615
}
15951616

1596-
return StringComparer.Ordinal.Equals(x.BranchNameOrDefault, y.BranchNameOrDefault) &&
1617+
return StringComparer.Ordinal.Equals(x.TagNameOrDefault, y.TagNameOrDefault) &&
1618+
StringComparer.Ordinal.Equals(x.BranchNameOrDefault, y.BranchNameOrDefault) &&
15971619
x.VersionIncrementOrDefault == y.VersionIncrementOrDefault &&
15981620
StringComparer.Ordinal.Equals(x.FirstUnstableTagOrDefault, y.FirstUnstableTagOrDefault);
15991621
}
@@ -1608,7 +1630,8 @@ public int GetHashCode(ReleaseOptions? obj)
16081630

16091631
unchecked
16101632
{
1611-
int hash = StringComparer.Ordinal.GetHashCode(obj.BranchNameOrDefault) * 397;
1633+
int hash = StringComparer.Ordinal.GetHashCode(obj.TagNameOrDefault) * 397;
1634+
hash ^= StringComparer.Ordinal.GetHashCode(obj.BranchNameOrDefault);
16121635
hash ^= (int)obj.VersionIncrementOrDefault;
16131636
hash ^= StringComparer.Ordinal.GetHashCode(obj.FirstUnstableTagOrDefault);
16141637
return hash;

src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ
126126
property.ShouldSerialize = instance => !((VersionOptions)instance).ReleaseOrDefault.IsDefault;
127127
}
128128

129+
if (property.DeclaringType == typeof(VersionOptions.ReleaseOptions) && member.Name == nameof(VersionOptions.ReleaseOptions.TagName))
130+
{
131+
property.ShouldSerialize = instance => ((VersionOptions.ReleaseOptions)instance).TagNameOrDefault != VersionOptions.ReleaseOptions.DefaultInstance.TagName;
132+
}
133+
129134
if (property.DeclaringType == typeof(VersionOptions.ReleaseOptions) && member.Name == nameof(VersionOptions.ReleaseOptions.BranchName))
130135
{
131136
property.ShouldSerialize = instance => ((VersionOptions.ReleaseOptions)instance).BranchNameOrDefault != VersionOptions.ReleaseOptions.DefaultInstance.BranchName;

src/NerdBank.GitVersioning/version.schema.json

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
},
120120
"publicReleaseRefSpec": {
121121
"type": "array",
122-
"description": "An array of regular expressions that may match a ref (branch or tag) that should be built with PublicRelease=true as the default value. The ref matched against is in its canonical form (e.g. refs/heads/master)",
122+
"description": "An array of regular expressions that may match a ref (branch or tag) that should be built with PublicRelease=true as the default value. The ref matched against is in its canonical form (e.g. refs/heads/master).",
123123
"items": {
124124
"type": "string",
125125
"format": "regex"
@@ -128,12 +128,12 @@
128128
},
129129
"cloudBuild": {
130130
"type": "object",
131-
"description": "Options that are applicable specifically to cloud builds (e.g. VSTS, AppVeyor, TeamCity)",
131+
"description": "Options that are applicable specifically to cloud builds (e.g. VSTS, AppVeyor, TeamCity).",
132132
"properties": {
133133
"setAllVariables": {
134134
"type": "boolean",
135135
"default": false,
136-
"description": "Elevates all build properties to cloud build variables prefaced with \"NBGV_\""
136+
"description": "Elevates all build properties to cloud build variables prefaced with \"NBGV_\"."
137137
},
138138
"setVersionVariables": {
139139
"type": "boolean",
@@ -172,13 +172,19 @@
172172
}
173173
},
174174
"release": {
175-
"description": "Settings for the prepare-release command",
175+
"description": "Settings for the prepare-release and tag commands.",
176176
"type": "object",
177177
"properties": {
178+
"tagName": {
179+
"description": "Defines the format of tag names. Format must include a placeholder '{version}' for the version.",
180+
"type": "string",
181+
"pattern": "\\{version\\}",
182+
"default": "v{version}"
183+
},
178184
"branchName": {
179-
"description": "Defines the format of release branch names. Format must include a placeholder '{version}' for the version",
185+
"description": "Defines the format of release branch names. Format must include a placeholder '{version}' for the version.",
180186
"type": "string",
181-
"pattern": ".*\\{version\\}.*",
187+
"pattern": "\\{version\\}",
182188
"default": "v{version}"
183189
},
184190
"versionIncrement": {
@@ -188,7 +194,7 @@
188194
"default": "minor"
189195
},
190196
"firstUnstableTag": {
191-
"description": "Specifies the first/default prerelease tag for new versions",
197+
"description": "Specifies the first/default prerelease tag for new versions.",
192198
"type": "string",
193199
"default": "alpha"
194200
}

src/nbgv/Program.cs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ private enum ExitCodes
6868
PackageIdNotFound,
6969
ShallowClone,
7070
InternalError,
71+
InvalidTagNameSetting,
7172
}
7273

7374
private static bool AlwaysUseLibGit2 => string.Equals(Environment.GetEnvironmentVariable("NBGV_GitEngine"), "LibGit2", StringComparison.Ordinal);
@@ -545,6 +546,24 @@ private static Task<int> OnTagCommand(string project, string versionOrRef)
545546
return Task.FromResult((int)ExitCodes.NoGitRepo);
546547
}
547548

549+
// get tag name format
550+
VersionOptions versionOptions = context.VersionFile.GetVersion();
551+
if (versionOptions is null)
552+
{
553+
Console.Error.WriteLine($"Failed to load version file for directory '{searchPath}'.");
554+
return Task.FromResult((int)ExitCodes.NoVersionJsonFound);
555+
}
556+
557+
string tagNameFormat = versionOptions.ReleaseOrDefault.TagNameOrDefault;
558+
559+
// ensure there is a '{version}' placeholder in the tag name
560+
if (string.IsNullOrEmpty(tagNameFormat) || !tagNameFormat.Contains("{version}"))
561+
{
562+
Console.Error.WriteLine($"Invalid 'tagName' setting '{tagNameFormat}'. Missing version placeholder '{{version}}'.");
563+
return Task.FromResult((int)ExitCodes.InvalidTagNameSetting);
564+
}
565+
566+
// get commit to tag
548567
LibGit2Sharp.Repository repository = context.Repository;
549568
if (!context.TrySelectCommit(versionOrRef))
550569
{
@@ -585,8 +604,12 @@ private static Task<int> OnTagCommand(string project, string versionOrRef)
585604
return Task.FromResult((int)ExitCodes.NoVersionJsonFound);
586605
}
587606

588-
oracle.PublicRelease = true; // assume a public release so we don't get a redundant -gCOMMITID in the tag name
589-
string tagName = $"v{oracle.SemVer2}";
607+
// assume a public release so we don't get a redundant -gCOMMITID in the tag name
608+
oracle.PublicRelease = true;
609+
610+
// replace the "{version}" placeholder with the actual version
611+
string tagName = tagNameFormat.Replace("{version}", oracle.SemVer2);
612+
590613
try
591614
{
592615
context.ApplyTag(tagName);

0 commit comments

Comments
 (0)