Skip to content

Commit 66ae02b

Browse files
authored
Merge pull request #3687 from CasperWSchmidt/main
Implements regular expression for determining version label
2 parents 6ffb6e1 + 9ede034 commit 66ae02b

16 files changed

+77
-52
lines changed

BREAKING_CHANGES.md

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
* A new configuration property with name `version-in-branch-pattern` has been introduced. This setting only applies on branches where the option `is-release-branch` is set to `true`. Please notice that the branch name needs to be defined after the version number by default (instead of `support/lts-2.0.0` please name the branch like `support/2.0.0-lts`).
2929
* The `is-release-branch` property of the `hotfix` branch setting has been changed from `false` to `true`. If present the hotfix number will be considered now by default.
3030
* In the GitHub and the Git Flow workflows the `label` property is by default set to an empty string on the `main` branch. This yields to a pre-release version on `main` with an empty tag. Instead of for instance `1.0.1+46` GitVersion generates the full semantic version `1.0.1-46` instead. This behavior can be changed to generate only stable versions (no pre-release version) with setting the label to `null` (Please keep in mind that the `label` property on root needs to be set to `null` as well, otherwise the fallback applies). This change is caused by issue #2347.
31+
* The `useBranchName` magic string has been removed. Instead use `{BranchName}` for `label`.
32+
* The `BranchPrefixToTrim` configuration property has been removed. `RegularExpression` is now used to capture named groups instead.
33+
* Default `RegularExpression` for feature branches is changed from `^features?[/-]` to `^features?[/-](?<BranchName>.+)` to support using `{BranchName}` out-of-the-box
34+
* Default `RegularExpression` for unknown branches is changed from `.*` to `(?<BranchName>.*)` to support using `{BranchName}` out-of-the-box
3135
3236
## v5.0.0
3337

docs/input/docs/reference/configuration.md

+10-6
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,9 @@ values, but here they are if you need to:
484484
### regex
485485

486486
This is the regex which is used to match the current branch to the correct
487-
branch configuration.
487+
branch configuration.
488+
489+
[Named groups](https://learn.microsoft.com/en-us/dotnet/standard/base-types/grouping-constructs-in-regular-expressions#named-matched-subexpressions) can be used to dynamically label pre-releases based on the branch name, or parts of it. See [Label](#label) for more details and examples.
488490

489491
### source-branches
490492

@@ -572,11 +574,13 @@ Same as for the [global configuration, explained above](#mode).
572574

573575
### label
574576

575-
The pre release label to use for this branch. Use the value `useBranchName` to use
576-
the branch name instead. For example `feature/foo` would become a pre-release
577-
label of `foo` with this value. Use the value `{BranchName}` as a placeholder to
578-
insert the branch name. For example `feature/foo` would become a pre-release label
579-
of `alpha.foo` with the value of `alpha.{BranchName}`.
577+
The pre-release label to use for this branch. Use the value `{BranchName}` as a placeholder to
578+
insert the value of the named group `BranchName` from the [regular expression](#regex).
579+
580+
For example: branch `feature/foo` would become a pre-release label
581+
of `alpha.foo` with `label: 'alpha.{BranchName}'` and `regex: '^features?[/-](?<BranchName>.+)'`.
582+
583+
Another example: branch `features/sc-12345/some-description` would become a pre-release label of `sc-12345` with `label: '{StoryNo}'` and `regex: '^features?[/-](?<StoryNo>sc-\d+)[-/].+'`.
580584

581585
**Note:** To clear a default use an empty string: `label: ''`
582586

schemas/6.0/GitVersion.configuration.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@
265265
}
266266
},
267267
"string": {
268-
"description": "The label to use for this branch. Can be \u0027useBranchName\u0027 to extract the label from the branch name. Use the value {BranchName} as a placeholder to insert the branch name.",
268+
"description": "The label to use for this branch. Use the value {BranchName} or similar as a placeholder to insert a named capture group from RegularExpression (fx. the branch name).",
269269
"type": "string"
270270
},
271271
"string1": {
@@ -557,4 +557,4 @@
557557
}
558558
}
559559
}
560-
}
560+
}

src/GitVersion.Core.Tests/Configuration/ConfigurationExtensionsTests.cs

+16
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,20 @@ public void EnsureIsReleaseBranchWithReferenceNameWorksAsExpected(string branchN
5757
actual.IsTag.ShouldBe(expectedIsTag);
5858
isReleaseBranch.ShouldBe(expectedIsReleaseBranch);
5959
}
60+
61+
[TestCase("feature/sc-1000/Description", "^features?[/-](?<BranchName>.+)", "{BranchName}", "sc-1000-Description")]
62+
[TestCase("feature/sc-1000/Description", "^features?[/-](?<StoryNo>sc-\\d+)[-/].+", "{StoryNo}", "sc-1000")]
63+
public void EnsureGetBranchSpecificLabelWorksAsExpected(string branchName, string regularExpression, string label, string expectedLabel)
64+
{
65+
var configuration = GitFlowConfigurationBuilder.New
66+
.WithoutBranches()
67+
.WithBranch(branchName, builder => builder
68+
.WithLabel(label)
69+
.WithRegularExpression(regularExpression))
70+
.Build();
71+
72+
var effectiveConfiguration = configuration.GetEffectiveConfiguration(ReferenceName.FromBranchName(branchName));
73+
var actual = effectiveConfiguration.GetBranchSpecificLabel(ReferenceName.FromBranchName(branchName), null);
74+
actual.ShouldBe(expectedLabel);
75+
}
6076
}

src/GitVersion.Core.Tests/Configuration/ConfigurationProviderTests.CanWriteOutEffectiveConfiguration.approved.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ branches:
5959
mode: ContinuousDelivery
6060
label: '{BranchName}'
6161
increment: Inherit
62-
regex: ^features?[/-]
62+
regex: ^features?[/-](?<BranchName>.+)
6363
source-branches:
6464
- develop
6565
- main
@@ -114,7 +114,7 @@ branches:
114114
mode: ContinuousDelivery
115115
label: '{BranchName}'
116116
increment: Inherit
117-
regex: .*
117+
regex: (?<BranchName>.+)
118118
source-branches:
119119
- main
120120
- develop

src/GitVersion.Core.Tests/Helpers/TestEffectiveConfiguration.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public TestEffectiveConfiguration(
1616
string tagPrefix = ConfigurationConstants.DefaultTagPrefix,
1717
string label = "ci",
1818
string? nextVersion = null,
19-
string branchPrefixToTrim = "",
19+
string regularExpression = "",
2020
bool preventIncrementOfMergedBranchVersion = false,
2121
string? labelNumberPattern = null,
2222
bool trackMergeTarget = false,
@@ -41,7 +41,7 @@ public TestEffectiveConfiguration(
4141
label,
4242
nextVersion,
4343
IncrementStrategy.Patch,
44-
branchPrefixToTrim,
44+
regularExpression,
4545
preventIncrementOfMergedBranchVersion,
4646
labelNumberPattern,
4747
trackMergeTarget,

src/GitVersion.Core.Tests/IntegrationTests/FeatureBranchScenarios.cs

+8-6
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,15 @@ public void CanUseBranchNameOffAReleaseBranch()
183183
fixture.AssertFullSemver("0.3.0-PROJ-1.1+3", configuration);
184184
}
185185

186-
[TestCase("alpha", "JIRA-123", "alpha")]
187-
[TestCase("useBranchName", "JIRA-123", "JIRA-123")]
188-
[TestCase($"alpha.{ConfigurationConstants.BranchNamePlaceholder}", "JIRA-123", "alpha.JIRA-123")]
189-
public void ShouldUseConfiguredTag(string tag, string featureName, string preReleaseTagName)
186+
[TestCase("alpha", "JIRA-123", "^features?[/-](?<BranchName>.+)", "alpha")]
187+
[TestCase($"alpha.{ConfigurationConstants.BranchNamePlaceholder}", "JIRA-123", "^features?[/-](?<BranchName>.+)", "alpha.JIRA-123")]
188+
[TestCase("{BranchName}-of-task-number-{TaskNumber}", "4711_this-is-a-feature", "^features?[/-](?<TaskNumber>\\d+)_(?<BranchName>.+)", "this-is-a-feature-of-task-number-4711")]
189+
public void ShouldUseConfiguredLabel(string label, string featureName, string regularExpression, string preReleaseLabelName)
190190
{
191191
var configuration = GitFlowConfigurationBuilder.New
192-
.WithBranch("feature", builder => builder.WithLabel(tag))
192+
.WithBranch("feature", builder => builder
193+
.WithLabel(label)
194+
.WithRegularExpression(regularExpression))
193195
.Build();
194196

195197
using var fixture = new EmptyRepositoryFixture();
@@ -198,7 +200,7 @@ public void ShouldUseConfiguredTag(string tag, string featureName, string preRel
198200
fixture.BranchTo(featureBranchName);
199201
fixture.Repository.MakeCommits(5);
200202

201-
var expectedFullSemVer = $"1.0.1-{preReleaseTagName}.1+5";
203+
var expectedFullSemVer = $"1.0.1-{preReleaseLabelName}.1+5";
202204
fixture.AssertFullSemver(expectedFullSemVer, configuration);
203205
}
204206

src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs

+4-5
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public void ShouldOnlyConsiderTagsMatchingOfCurrentBranch()
3434
public void CanTakeVersionFromReleaseBranch()
3535
{
3636
var configuration = GitFlowConfigurationBuilder.New
37-
.WithBranch("release", _ => _.WithLabel("{BranchName}"))
37+
.WithBranch("release", _ => _.WithLabel("{BranchName}").WithRegularExpression("(?<BranchName>.*)"))
3838
.Build();
3939

4040
using var fixture = new EmptyRepositoryFixture();
@@ -52,7 +52,7 @@ public void CanTakeVersionFromReleaseBranch()
5252
public void CanTakeVersionFromHotfixBranch()
5353
{
5454
var configuration = GitFlowConfigurationBuilder.New
55-
.WithBranch("hotfix", _ => _.WithLabel("{BranchName}"))
55+
.WithBranch("hotfix", _ => _.WithLabel("{BranchName}").WithRegularExpression("(?<BranchName>.*)"))
5656
.Build();
5757

5858
using var fixture = new EmptyRepositoryFixture();
@@ -83,7 +83,7 @@ public void ShouldNotGetVersionFromFeatureBranchIfNotMerged()
8383
{
8484
// * 1c08923 54 minutes ago (HEAD -> develop)
8585
// | * 03dd6d5 56 minutes ago (tag: 1.0.1-feature.1, feature)
86-
// |/
86+
// |/
8787
// * e2ff13b 58 minutes ago (tag: 1.0.0-unstable.0, main)
8888

8989
var configuration = GitFlowConfigurationBuilder.New
@@ -106,14 +106,13 @@ public void ShouldNotGetVersionFromFeatureBranchIfNotMerged()
106106
}
107107

108108
[TestCase("alpha", "JIRA-123", "alpha")]
109-
[TestCase("useBranchName", "JIRA-123", "JIRA-123")]
110109
[TestCase($"alpha.{ConfigurationConstants.BranchNamePlaceholder}", "JIRA-123", "alpha.JIRA-123")]
111110
public void LabelIsBranchNameForBranchesWithoutPrefixedBranchName(string label, string branchName, string preReleaseTagName)
112111
{
113112
var configuration = GitFlowConfigurationBuilder.New
114113
.WithBranch("other", builder => builder
115114
.WithIncrement(IncrementStrategy.Patch)
116-
.WithRegularExpression(".*")
115+
.WithRegularExpression("(?<BranchName>.*)")
117116
.WithSourceBranches()
118117
.WithLabel(label))
119118
.Build();

src/GitVersion.Core.Tests/VersionCalculation/VariableProviderTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ public void ProvidesVariablesInContinuousDeploymentModeWithTagNamePattern()
182182
}
183183

184184
[Test]
185-
public void ProvidesVariablesInContinuousDeploymentModeWithTagSetToUseBranchName()
185+
public void ProvidesVariablesInContinuousDeploymentModeWithTagSetToBranchName()
186186
{
187187
var semanticVersion = new SemanticVersion
188188
{

src/GitVersion.Core/Configuration/BranchConfiguration.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ internal record BranchConfiguration : IBranchConfiguration
1111
public VersioningMode? VersioningMode { get; internal set; }
1212

1313
[JsonPropertyName("label")]
14-
[JsonPropertyDescription("The label to use for this branch. Can be 'useBranchName' to extract the label from the branch name. Use the value {BranchName} as a placeholder to insert the branch name.")]
14+
[JsonPropertyDescription("The label to use for this branch. Use the value {BranchName} or similar as a placeholder to insert a named capture group from RegularExpression (fx. the branch name).")]
1515
public string? Label { get; internal set; }
1616

1717
[JsonPropertyName("increment")]

src/GitVersion.Core/Configuration/ConfigurationConstants.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ internal static class ConfigurationConstants
1919
public const string MainBranchRegex = "^master$|^main$";
2020
public const string DevelopBranchRegex = "^dev(elop)?(ment)?$";
2121
public const string ReleaseBranchRegex = "^releases?[/-]";
22-
public const string FeatureBranchRegex = "^features?[/-]";
22+
public const string FeatureBranchRegex = "^features?[/-](?<BranchName>.+)";
2323
public const string PullRequestBranchRegex = @"^(pull|pull\-requests|pr)[/-]";
2424
public const string HotfixBranchRegex = "^hotfix(es)?[/-]";
2525
public const string SupportBranchRegex = "^support[/-]";
26-
public const string UnknownBranchRegex = ".*";
26+
public const string UnknownBranchRegex = "(?<BranchName>.+)";
2727
}

src/GitVersion.Core/Configuration/ConfigurationExtensions.cs

+15-15
Original file line numberDiff line numberDiff line change
@@ -68,32 +68,32 @@ public static bool IsReleaseBranch(this IGitVersionConfiguration configuration,
6868
configuration.NotNull();
6969

7070
var label = configuration.Label;
71-
if (label == "useBranchName")
71+
if (label is null)
7272
{
73-
label = ConfigurationConstants.BranchNamePlaceholder;
73+
return label;
7474
}
7575

76-
var value = branchNameOverride ?? branchName;
76+
var effectiveBranchName = branchNameOverride ?? branchName;
7777

78-
if (label?.Contains(ConfigurationConstants.BranchNamePlaceholder) == true)
78+
if (!configuration.RegularExpression.IsNullOrWhiteSpace() && !effectiveBranchName.IsNullOrEmpty())
7979
{
80-
if (!configuration.BranchPrefixToTrim.IsNullOrWhiteSpace())
80+
effectiveBranchName = effectiveBranchName.RegexReplace("[^a-zA-Z0-9-_]", "-");
81+
var pattern = new Regex(configuration.RegularExpression, RegexOptions.IgnoreCase);
82+
var match = pattern.Match(effectiveBranchName);
83+
if (match.Success)
8184
{
82-
var branchNameTrimmed = value?.RegexReplace(
83-
configuration.BranchPrefixToTrim, string.Empty, RegexOptions.IgnoreCase
84-
);
85-
value = branchNameTrimmed.IsNullOrEmpty() ? value : branchNameTrimmed;
85+
// ReSharper disable once LoopCanBeConvertedToQuery
86+
foreach (var groupName in pattern.GetGroupNames())
87+
{
88+
label = label.Replace("{" + groupName + "}", match.Groups[groupName].Value);
89+
}
8690
}
87-
88-
value = value?.RegexReplace("[^a-zA-Z0-9-]", "-");
89-
90-
label = label.Replace(ConfigurationConstants.BranchNamePlaceholder, value);
9191
}
9292

9393
// Evaluate tag number pattern and append to prerelease tag, preserving build metadata
94-
if (!configuration.LabelNumberPattern.IsNullOrEmpty() && !value.IsNullOrEmpty() && label is not null)
94+
if (!configuration.LabelNumberPattern.IsNullOrEmpty() && !effectiveBranchName.IsNullOrEmpty())
9595
{
96-
var match = Regex.Match(value, configuration.LabelNumberPattern);
96+
var match = Regex.Match(effectiveBranchName, configuration.LabelNumberPattern);
9797
var numberGroup = match.Groups["number"];
9898
if (numberGroup.Success)
9999
{

src/GitVersion.Core/Configuration/EffectiveConfiguration.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public EffectiveConfiguration(IGitVersionConfiguration configuration, IBranchCon
4444
Label = branchConfiguration.Label;
4545
NextVersion = configuration.NextVersion;
4646
Increment = branchConfiguration.Increment;
47-
BranchPrefixToTrim = branchConfiguration.RegularExpression;
47+
RegularExpression = branchConfiguration.RegularExpression;
4848
PreventIncrementOfMergedBranchVersion = branchConfiguration.PreventIncrementOfMergedBranchVersion ?? false;
4949
LabelNumberPattern = branchConfiguration.LabelNumberPattern;
5050
TrackMergeTarget = branchConfiguration.TrackMergeTarget ?? false;
@@ -75,7 +75,7 @@ protected EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningSche
7575
string label,
7676
string? nextVersion,
7777
IncrementStrategy increment,
78-
string? branchPrefixToTrim,
78+
string? regularExpression,
7979
bool preventIncrementOfMergedBranchVersion,
8080
string? labelNumberPattern,
8181
bool trackMergeTarget,
@@ -104,7 +104,7 @@ protected EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningSche
104104
Label = label;
105105
NextVersion = nextVersion;
106106
Increment = increment;
107-
BranchPrefixToTrim = branchPrefixToTrim;
107+
RegularExpression = regularExpression;
108108
PreventIncrementOfMergedBranchVersion = preventIncrementOfMergedBranchVersion;
109109
LabelNumberPattern = labelNumberPattern;
110110
TrackMergeTarget = trackMergeTarget;
@@ -150,7 +150,7 @@ protected EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningSche
150150

151151
public IncrementStrategy Increment { get; }
152152

153-
public string? BranchPrefixToTrim { get; }
153+
public string? RegularExpression { get; }
154154

155155
public bool PreventIncrementOfMergedBranchVersion { get; }
156156

src/GitVersion.Core/Configuration/SupportedWorkflows/GitFlow/v1.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ branches:
5555
mode: ContinuousDelivery
5656
label: '{BranchName}'
5757
increment: Inherit
58-
regex: ^features?[/-]
58+
regex: ^features?[/-](?<BranchName>.+)
5959
source-branches:
6060
- develop
6161
- main
@@ -105,7 +105,7 @@ branches:
105105
mode: ContinuousDelivery
106106
label: '{BranchName}'
107107
increment: Inherit
108-
regex: .*
108+
regex: (?<BranchName>.*)
109109
source-branches:
110110
- main
111111
- develop

src/GitVersion.Core/Configuration/SupportedWorkflows/GitHubFlow/v1.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ branches:
4040
mode: ContinuousDelivery
4141
label: '{BranchName}'
4242
increment: Inherit
43-
regex: ^features?[/-]
43+
regex: ^features?[/-](?<BranchName>.+)
4444
source-branches:
4545
- main
4646
- release
@@ -61,7 +61,7 @@ branches:
6161
mode: ContinuousDelivery
6262
label: '{BranchName}'
6363
increment: Inherit
64-
regex: .*
64+
regex: (?<BranchName>.*)
6565
source-branches:
6666
- main
6767
- release

src/GitVersion.Core/PublicAPI.Unshipped.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,11 @@ GitVersion.Configuration.EffectiveConfiguration.AssemblyFileVersioningScheme.get
108108
GitVersion.Configuration.EffectiveConfiguration.AssemblyInformationalFormat.get -> string?
109109
GitVersion.Configuration.EffectiveConfiguration.AssemblyVersioningFormat.get -> string?
110110
GitVersion.Configuration.EffectiveConfiguration.AssemblyVersioningScheme.get -> GitVersion.Extensions.AssemblyVersioningScheme
111-
GitVersion.Configuration.EffectiveConfiguration.BranchPrefixToTrim.get -> string?
111+
GitVersion.Configuration.EffectiveConfiguration.RegularExpression.get -> string?
112112
GitVersion.Configuration.EffectiveConfiguration.CommitDateFormat.get -> string?
113113
GitVersion.Configuration.EffectiveConfiguration.CommitMessageIncrementing.get -> GitVersion.VersionCalculation.CommitMessageIncrementMode
114114
GitVersion.Configuration.EffectiveConfiguration.EffectiveConfiguration(GitVersion.Configuration.IGitVersionConfiguration! configuration, GitVersion.Configuration.IBranchConfiguration! branchConfiguration) -> void
115-
GitVersion.Configuration.EffectiveConfiguration.EffectiveConfiguration(GitVersion.Extensions.AssemblyVersioningScheme assemblyVersioningScheme, GitVersion.Extensions.AssemblyFileVersioningScheme assemblyFileVersioningScheme, string? assemblyInformationalFormat, string? assemblyVersioningFormat, string? assemblyFileVersioningFormat, GitVersion.VersionCalculation.VersioningMode versioningMode, string? tagPrefix, string! label, string? nextVersion, GitVersion.IncrementStrategy increment, string? branchPrefixToTrim, bool preventIncrementOfMergedBranchVersion, string? labelNumberPattern, bool trackMergeTarget, string? majorVersionBumpMessage, string? minorVersionBumpMessage, string? patchVersionBumpMessage, string? noBumpMessage, GitVersion.VersionCalculation.CommitMessageIncrementMode commitMessageIncrementing, System.Collections.Generic.IEnumerable<GitVersion.VersionCalculation.IVersionFilter!>! versionFilters, bool tracksReleaseBranches, bool isReleaseBranch, bool isMainline, string? commitDateFormat, bool updateBuildNumber, GitVersion.SemanticVersionFormat semanticVersionFormat, int preReleaseWeight, int tagPreReleaseWeight) -> void
115+
GitVersion.Configuration.EffectiveConfiguration.EffectiveConfiguration(GitVersion.Extensions.AssemblyVersioningScheme assemblyVersioningScheme, GitVersion.Extensions.AssemblyFileVersioningScheme assemblyFileVersioningScheme, string? assemblyInformationalFormat, string? assemblyVersioningFormat, string? assemblyFileVersioningFormat, GitVersion.VersionCalculation.VersioningMode versioningMode, string? tagPrefix, string! label, string? nextVersion, GitVersion.IncrementStrategy increment, string? regularExpression, bool preventIncrementOfMergedBranchVersion, string? labelNumberPattern, bool trackMergeTarget, string? majorVersionBumpMessage, string? minorVersionBumpMessage, string? patchVersionBumpMessage, string? noBumpMessage, GitVersion.VersionCalculation.CommitMessageIncrementMode commitMessageIncrementing, System.Collections.Generic.IEnumerable<GitVersion.VersionCalculation.IVersionFilter!>! versionFilters, bool tracksReleaseBranches, bool isReleaseBranch, bool isMainline, string? commitDateFormat, bool updateBuildNumber, GitVersion.SemanticVersionFormat semanticVersionFormat, int preReleaseWeight, int tagPreReleaseWeight) -> void
116116
GitVersion.Configuration.EffectiveConfiguration.Increment.get -> GitVersion.IncrementStrategy
117117
GitVersion.Configuration.EffectiveConfiguration.IsMainline.get -> bool
118118
GitVersion.Configuration.EffectiveConfiguration.IsReleaseBranch.get -> bool

0 commit comments

Comments
 (0)