Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements regular expression for determining version label #3687

Merged
merged 7 commits into from
Sep 29, 2023
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
4 changes: 4 additions & 0 deletions BREAKING_CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
* 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`).
* 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.
* 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.
* The `useBranchName` magic string has been removed. Instead use `{BranchName}` for `label`.
* The `BranchPrefixToTrim` configuration property has been removed. `RegularExpression` is now used to capture named groups instead.
* Default `RegularExpression` for feature branches is changed from `^features?[/-]` to `^features?[/-](?<BranchName>.+)` to support using `{BranchName}` out-of-the-box
* Default `RegularExpression` for unknown branches is changed from `.*` to `(?<BranchName>.*)` to support using `{BranchName}` out-of-the-box

## v5.0.0

Expand Down
16 changes: 10 additions & 6 deletions docs/input/docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,9 @@ values, but here they are if you need to:
### regex

This is the regex which is used to match the current branch to the correct
branch configuration.
branch configuration.

[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.

### source-branches

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

### label

The pre release label to use for this branch. Use the value `useBranchName` to use
the branch name instead. For example `feature/foo` would become a pre-release
label of `foo` with this value. Use the value `{BranchName}` as a placeholder to
insert the branch name. For example `feature/foo` would become a pre-release label
of `alpha.foo` with the value of `alpha.{BranchName}`.
The pre-release label to use for this branch. Use the value `{BranchName}` as a placeholder to
insert the value of the named group `BranchName` from the [regular expression](#regex).

For example: branch `feature/foo` would become a pre-release label
of `alpha.foo` with `label: 'alpha.{BranchName}'` and `regex: '^features?[/-](?<BranchName>.+)'`.

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+)[-/].+'`.

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

Expand Down
4 changes: 2 additions & 2 deletions schemas/6.0/GitVersion.configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@
}
},
"string": {
"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.",
"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).",
"type": "string"
},
"string1": {
Expand Down Expand Up @@ -557,4 +557,4 @@
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,20 @@ public void EnsureIsReleaseBranchWithReferenceNameWorksAsExpected(string branchN
actual.IsTag.ShouldBe(expectedIsTag);
isReleaseBranch.ShouldBe(expectedIsReleaseBranch);
}

[TestCase("feature/sc-1000/Description", "^features?[/-](?<BranchName>.+)", "{BranchName}", "sc-1000-Description")]
[TestCase("feature/sc-1000/Description", "^features?[/-](?<StoryNo>sc-\\d+)[-/].+", "{StoryNo}", "sc-1000")]
public void EnsureGetBranchSpecificLabelWorksAsExpected(string branchName, string regularExpression, string label, string expectedLabel)
{
var configuration = GitFlowConfigurationBuilder.New
.WithoutBranches()
.WithBranch(branchName, builder => builder
.WithLabel(label)
.WithRegularExpression(regularExpression))
.Build();

var effectiveConfiguration = configuration.GetEffectiveConfiguration(ReferenceName.FromBranchName(branchName));
var actual = effectiveConfiguration.GetBranchSpecificLabel(ReferenceName.FromBranchName(branchName), null);
actual.ShouldBe(expectedLabel);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ branches:
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
regex: ^features?[/-]
regex: ^features?[/-](?<BranchName>.+)
source-branches:
- develop
- main
Expand Down Expand Up @@ -114,7 +114,7 @@ branches:
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
regex: .*
regex: (?<BranchName>.+)
source-branches:
- main
- develop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public TestEffectiveConfiguration(
string tagPrefix = ConfigurationConstants.DefaultTagPrefix,
string label = "ci",
string? nextVersion = null,
string branchPrefixToTrim = "",
string regularExpression = "",
bool preventIncrementOfMergedBranchVersion = false,
string? labelNumberPattern = null,
bool trackMergeTarget = false,
Expand All @@ -41,7 +41,7 @@ public TestEffectiveConfiguration(
label,
nextVersion,
IncrementStrategy.Patch,
branchPrefixToTrim,
regularExpression,
preventIncrementOfMergedBranchVersion,
labelNumberPattern,
trackMergeTarget,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,15 @@ public void CanUseBranchNameOffAReleaseBranch()
fixture.AssertFullSemver("0.3.0-PROJ-1.1+3", configuration);
}

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

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void ShouldOnlyConsiderTagsMatchingOfCurrentBranch()
public void CanTakeVersionFromReleaseBranch()
{
var configuration = GitFlowConfigurationBuilder.New
.WithBranch("release", _ => _.WithLabel("{BranchName}"))
.WithBranch("release", _ => _.WithLabel("{BranchName}").WithRegularExpression("(?<BranchName>.*)"))
.Build();

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

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

var configuration = GitFlowConfigurationBuilder.New
Expand All @@ -106,14 +106,13 @@ public void ShouldNotGetVersionFromFeatureBranchIfNotMerged()
}

[TestCase("alpha", "JIRA-123", "alpha")]
[TestCase("useBranchName", "JIRA-123", "JIRA-123")]
[TestCase($"alpha.{ConfigurationConstants.BranchNamePlaceholder}", "JIRA-123", "alpha.JIRA-123")]
public void LabelIsBranchNameForBranchesWithoutPrefixedBranchName(string label, string branchName, string preReleaseTagName)
{
var configuration = GitFlowConfigurationBuilder.New
.WithBranch("other", builder => builder
.WithIncrement(IncrementStrategy.Patch)
.WithRegularExpression(".*")
.WithRegularExpression("(?<BranchName>.*)")
.WithSourceBranches()
.WithLabel(label))
.Build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public void ProvidesVariablesInContinuousDeploymentModeWithTagNamePattern()
}

[Test]
public void ProvidesVariablesInContinuousDeploymentModeWithTagSetToUseBranchName()
public void ProvidesVariablesInContinuousDeploymentModeWithTagSetToBranchName()
{
var semanticVersion = new SemanticVersion
{
Expand Down
2 changes: 1 addition & 1 deletion src/GitVersion.Core/Configuration/BranchConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ internal record BranchConfiguration : IBranchConfiguration
public VersioningMode? VersioningMode { get; internal set; }

[JsonPropertyName("label")]
[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.")]
[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).")]
public string? Label { get; internal set; }

[JsonPropertyName("increment")]
Expand Down
4 changes: 2 additions & 2 deletions src/GitVersion.Core/Configuration/ConfigurationConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ internal static class ConfigurationConstants
public const string MainBranchRegex = "^master$|^main$";
public const string DevelopBranchRegex = "^dev(elop)?(ment)?$";
public const string ReleaseBranchRegex = "^releases?[/-]";
public const string FeatureBranchRegex = "^features?[/-]";
public const string FeatureBranchRegex = "^features?[/-](?<BranchName>.+)";
public const string PullRequestBranchRegex = @"^(pull|pull\-requests|pr)[/-]";
public const string HotfixBranchRegex = "^hotfix(es)?[/-]";
public const string SupportBranchRegex = "^support[/-]";
public const string UnknownBranchRegex = ".*";
public const string UnknownBranchRegex = "(?<BranchName>.+)";
}
30 changes: 15 additions & 15 deletions src/GitVersion.Core/Configuration/ConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,32 +68,32 @@ public static bool IsReleaseBranch(this IGitVersionConfiguration configuration,
configuration.NotNull();

var label = configuration.Label;
if (label == "useBranchName")
if (label is null)
{
label = ConfigurationConstants.BranchNamePlaceholder;
return label;
}

var value = branchNameOverride ?? branchName;
var effectiveBranchName = branchNameOverride ?? branchName;

if (label?.Contains(ConfigurationConstants.BranchNamePlaceholder) == true)
if (!configuration.RegularExpression.IsNullOrWhiteSpace() && !effectiveBranchName.IsNullOrEmpty())
{
if (!configuration.BranchPrefixToTrim.IsNullOrWhiteSpace())
effectiveBranchName = effectiveBranchName.RegexReplace("[^a-zA-Z0-9-_]", "-");
var pattern = new Regex(configuration.RegularExpression, RegexOptions.IgnoreCase);
var match = pattern.Match(effectiveBranchName);
if (match.Success)
{
var branchNameTrimmed = value?.RegexReplace(
configuration.BranchPrefixToTrim, string.Empty, RegexOptions.IgnoreCase
);
value = branchNameTrimmed.IsNullOrEmpty() ? value : branchNameTrimmed;
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var groupName in pattern.GetGroupNames())
{
label = label.Replace("{" + groupName + "}", match.Groups[groupName].Value);
}
}

value = value?.RegexReplace("[^a-zA-Z0-9-]", "-");

label = label.Replace(ConfigurationConstants.BranchNamePlaceholder, value);
}

// Evaluate tag number pattern and append to prerelease tag, preserving build metadata
if (!configuration.LabelNumberPattern.IsNullOrEmpty() && !value.IsNullOrEmpty() && label is not null)
if (!configuration.LabelNumberPattern.IsNullOrEmpty() && !effectiveBranchName.IsNullOrEmpty())
{
var match = Regex.Match(value, configuration.LabelNumberPattern);
var match = Regex.Match(effectiveBranchName, configuration.LabelNumberPattern);
var numberGroup = match.Groups["number"];
if (numberGroup.Success)
{
Expand Down
8 changes: 4 additions & 4 deletions src/GitVersion.Core/Configuration/EffectiveConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public EffectiveConfiguration(IGitVersionConfiguration configuration, IBranchCon
Label = branchConfiguration.Label;
NextVersion = configuration.NextVersion;
Increment = branchConfiguration.Increment;
BranchPrefixToTrim = branchConfiguration.RegularExpression;
RegularExpression = branchConfiguration.RegularExpression;
PreventIncrementOfMergedBranchVersion = branchConfiguration.PreventIncrementOfMergedBranchVersion ?? false;
LabelNumberPattern = branchConfiguration.LabelNumberPattern;
TrackMergeTarget = branchConfiguration.TrackMergeTarget ?? false;
Expand Down Expand Up @@ -75,7 +75,7 @@ protected EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningSche
string label,
string? nextVersion,
IncrementStrategy increment,
string? branchPrefixToTrim,
string? regularExpression,
bool preventIncrementOfMergedBranchVersion,
string? labelNumberPattern,
bool trackMergeTarget,
Expand Down Expand Up @@ -104,7 +104,7 @@ protected EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningSche
Label = label;
NextVersion = nextVersion;
Increment = increment;
BranchPrefixToTrim = branchPrefixToTrim;
RegularExpression = regularExpression;
PreventIncrementOfMergedBranchVersion = preventIncrementOfMergedBranchVersion;
LabelNumberPattern = labelNumberPattern;
TrackMergeTarget = trackMergeTarget;
Expand Down Expand Up @@ -150,7 +150,7 @@ protected EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningSche

public IncrementStrategy Increment { get; }

public string? BranchPrefixToTrim { get; }
public string? RegularExpression { get; }

public bool PreventIncrementOfMergedBranchVersion { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ branches:
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
regex: ^features?[/-]
regex: ^features?[/-](?<BranchName>.+)
source-branches:
- develop
- main
Expand Down Expand Up @@ -105,7 +105,7 @@ branches:
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
regex: .*
regex: (?<BranchName>.*)
source-branches:
- main
- develop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ branches:
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
regex: ^features?[/-]
regex: ^features?[/-](?<BranchName>.+)
source-branches:
- main
- release
Expand All @@ -61,7 +61,7 @@ branches:
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
regex: .*
regex: (?<BranchName>.*)
source-branches:
- main
- release
Expand Down
4 changes: 2 additions & 2 deletions src/GitVersion.Core/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ GitVersion.Configuration.EffectiveConfiguration.AssemblyFileVersioningScheme.get
GitVersion.Configuration.EffectiveConfiguration.AssemblyInformationalFormat.get -> string?
GitVersion.Configuration.EffectiveConfiguration.AssemblyVersioningFormat.get -> string?
GitVersion.Configuration.EffectiveConfiguration.AssemblyVersioningScheme.get -> GitVersion.Extensions.AssemblyVersioningScheme
GitVersion.Configuration.EffectiveConfiguration.BranchPrefixToTrim.get -> string?
GitVersion.Configuration.EffectiveConfiguration.RegularExpression.get -> string?
GitVersion.Configuration.EffectiveConfiguration.CommitDateFormat.get -> string?
GitVersion.Configuration.EffectiveConfiguration.CommitMessageIncrementing.get -> GitVersion.VersionCalculation.CommitMessageIncrementMode
GitVersion.Configuration.EffectiveConfiguration.EffectiveConfiguration(GitVersion.Configuration.IGitVersionConfiguration! configuration, GitVersion.Configuration.IBranchConfiguration! branchConfiguration) -> void
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
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
GitVersion.Configuration.EffectiveConfiguration.Increment.get -> GitVersion.IncrementStrategy
GitVersion.Configuration.EffectiveConfiguration.IsMainline.get -> bool
GitVersion.Configuration.EffectiveConfiguration.IsReleaseBranch.get -> bool
Expand Down
Loading