diff --git a/new-cli/GitVersion.Common/GitVersion.Common.csproj b/new-cli/GitVersion.Common/GitVersion.Common.csproj
index 96f23e8568..f224f9e121 100644
--- a/new-cli/GitVersion.Common/GitVersion.Common.csproj
+++ b/new-cli/GitVersion.Common/GitVersion.Common.csproj
@@ -7,6 +7,7 @@
+
diff --git a/src/GitVersion.App.Tests/ArgumentParserTests.cs b/src/GitVersion.App.Tests/ArgumentParserTests.cs
index d8456c7d12..b8650499c8 100644
--- a/src/GitVersion.App.Tests/ArgumentParserTests.cs
+++ b/src/GitVersion.App.Tests/ArgumentParserTests.cs
@@ -450,7 +450,7 @@ private static IEnumerable OverrideConfigWithSingleOptionTestData(
"tag-prefix=sample",
new GitVersionConfiguration
{
- TagPrefix = "sample"
+ TagPrefixPattern = "sample"
}
);
yield return new TestCaseData(
@@ -546,7 +546,7 @@ private static IEnumerable OverrideConfigWithMultipleOptionsTestDa
"/overrideconfig tag-prefix=sample /overrideconfig assembly-versioning-scheme=MajorMinor",
new GitVersionConfiguration
{
- TagPrefix = "sample",
+ TagPrefixPattern = "sample",
AssemblyVersioningScheme = AssemblyVersioningScheme.MajorMinor
}
);
@@ -554,7 +554,7 @@ private static IEnumerable OverrideConfigWithMultipleOptionsTestDa
"/overrideconfig tag-prefix=sample /overrideconfig assembly-versioning-format=\"{Major}.{Minor}.{Patch}.{env:CI_JOB_ID ?? 0}\"",
new GitVersionConfiguration
{
- TagPrefix = "sample",
+ TagPrefixPattern = "sample",
AssemblyVersioningFormat = "{Major}.{Minor}.{Patch}.{env:CI_JOB_ID ?? 0}"
}
);
@@ -562,7 +562,7 @@ private static IEnumerable OverrideConfigWithMultipleOptionsTestDa
"/overrideconfig tag-prefix=sample /overrideconfig assembly-versioning-format=\"{Major}.{Minor}.{Patch}.{env:CI_JOB_ID ?? 0}\" /overrideconfig update-build-number=true /overrideconfig assembly-versioning-scheme=MajorMinorPatchTag /overrideconfig mode=ContinuousDelivery /overrideconfig tag-pre-release-weight=4",
new GitVersionConfiguration
{
- TagPrefix = "sample",
+ TagPrefixPattern = "sample",
AssemblyVersioningFormat = "{Major}.{Minor}.{Patch}.{env:CI_JOB_ID ?? 0}",
UpdateBuildNumber = true,
AssemblyVersioningScheme = AssemblyVersioningScheme.MajorMinorPatchTag,
diff --git a/src/GitVersion.BuildAgents/Agents/AzurePipelines.cs b/src/GitVersion.BuildAgents/Agents/AzurePipelines.cs
index 0978007fde..31d44ea671 100644
--- a/src/GitVersion.BuildAgents/Agents/AzurePipelines.cs
+++ b/src/GitVersion.BuildAgents/Agents/AzurePipelines.cs
@@ -1,4 +1,3 @@
-using System.Text.RegularExpressions;
using GitVersion.Extensions;
using GitVersion.Logging;
using GitVersion.OutputVariables;
@@ -52,7 +51,7 @@ private static string ReplaceVariables(string buildNumberEnv, KeyValuePair buildNumberEnv,
- _ => buildNumberEnv.RegexReplace(pattern, replacement, RegexOptions.IgnoreCase)
+ _ => buildNumberEnv.RegexReplace(pattern, replacement)
};
}
}
diff --git a/src/GitVersion.Configuration.Tests/Configuration/ConfigurationProviderTests.cs b/src/GitVersion.Configuration.Tests/Configuration/ConfigurationProviderTests.cs
index a07d47d8c9..9ece53a3f5 100644
--- a/src/GitVersion.Configuration.Tests/Configuration/ConfigurationProviderTests.cs
+++ b/src/GitVersion.Configuration.Tests/Configuration/ConfigurationProviderTests.cs
@@ -246,7 +246,7 @@ public void CanReadDefaultDocument()
configuration.AssemblyInformationalFormat.ShouldBe(null);
configuration.Branches["develop"].Label.ShouldBe("alpha");
configuration.Branches["release"].Label.ShouldBe("beta");
- configuration.TagPrefix.ShouldBe(ConfigurationConstants.DefaultTagPrefix);
+ configuration.TagPrefixPattern.ShouldBe(RegexPatterns.Configuration.DefaultTagPrefixPattern);
configuration.NextVersion.ShouldBe(null);
}
@@ -361,7 +361,7 @@ public void ShouldNotOverrideAnythingWhenOverrideConfigIsEmpty()
var expectedConfig = GitFlowConfigurationBuilder.New
.WithNextVersion("1.2.3")
- .WithTagPrefix("custom-tag-prefix-from-yml")
+ .WithTagPrefixPattern("custom-tag-prefix-from-yml")
.Build();
var configuration = this.configurationProvider.ProvideForDirectory(this.repoPath);
@@ -370,7 +370,7 @@ public void ShouldNotOverrideAnythingWhenOverrideConfigIsEmpty()
configuration.AssemblyInformationalFormat.ShouldBe(expectedConfig.AssemblyInformationalFormat);
configuration.AssemblyVersioningFormat.ShouldBe(expectedConfig.AssemblyVersioningFormat);
configuration.AssemblyFileVersioningFormat.ShouldBe(expectedConfig.AssemblyFileVersioningFormat);
- configuration.TagPrefix.ShouldBe(expectedConfig.TagPrefix);
+ configuration.TagPrefixPattern.ShouldBe(expectedConfig.TagPrefixPattern);
configuration.NextVersion.ShouldBe(expectedConfig.NextVersion);
configuration.MajorVersionBumpMessage.ShouldBe(expectedConfig.MajorVersionBumpMessage);
configuration.MinorVersionBumpMessage.ShouldBe(expectedConfig.MinorVersionBumpMessage);
@@ -398,7 +398,7 @@ public void ShouldUseDefaultTagPrefixWhenNotSetInConfigFile()
using var _ = this.fileSystem.SetupConfigFile(path: this.repoPath, text: text);
var configuration = this.configurationProvider.ProvideForDirectory(this.repoPath);
- configuration.TagPrefix.ShouldBe(ConfigurationConstants.DefaultTagPrefix);
+ configuration.TagPrefixPattern.ShouldBe(RegexPatterns.Configuration.DefaultTagPrefixPattern);
}
[Test]
@@ -408,7 +408,7 @@ public void ShouldUseTagPrefixFromConfigFileWhenProvided()
using var _ = this.fileSystem.SetupConfigFile(path: this.repoPath, text: text);
var configuration = this.configurationProvider.ProvideForDirectory(this.repoPath);
- configuration.TagPrefix.ShouldBe("custom-tag-prefix-from-yml");
+ configuration.TagPrefixPattern.ShouldBe("custom-tag-prefix-from-yml");
}
[Test]
@@ -422,7 +422,7 @@ public void ShouldOverrideTagPrefixWithOverrideConfigValue([Values] bool tagPref
};
var configuration = this.configurationProvider.ProvideForDirectory(this.repoPath, overrideConfiguration);
- configuration.TagPrefix.ShouldBe("tag-prefix-from-override-configuration");
+ configuration.TagPrefixPattern.ShouldBe("tag-prefix-from-override-configuration");
}
[Test]
@@ -437,7 +437,7 @@ public void ShouldNotOverrideDefaultTagPrefixWhenNotSetInOverrideConfig()
var configuration = this.configurationProvider.ProvideForDirectory(this.repoPath, overrideConfiguration);
- configuration.TagPrefix.ShouldBe(ConfigurationConstants.DefaultTagPrefix);
+ configuration.TagPrefixPattern.ShouldBe(RegexPatterns.Configuration.DefaultTagPrefixPattern);
}
[Test]
@@ -451,7 +451,7 @@ public void ShouldNotOverrideTagPrefixFromConfigFileWhenNotSetInOverrideConfig()
};
var configuration = this.configurationProvider.ProvideForDirectory(this.repoPath, overrideConfiguration);
- configuration.TagPrefix.ShouldBe("custom-tag-prefix-from-yml");
+ configuration.TagPrefixPattern.ShouldBe("custom-tag-prefix-from-yml");
}
[Test]
@@ -465,6 +465,6 @@ public void ShouldOverrideTagPrefixFromConfigFileWhenSetInOverrideConfig()
};
var configuration = this.configurationProvider.ProvideForDirectory(this.repoPath, overrideConfiguration);
- configuration.TagPrefix.ShouldBe("custom-tag-prefix-from-console");
+ configuration.TagPrefixPattern.ShouldBe("custom-tag-prefix-from-console");
}
}
diff --git a/src/GitVersion.Configuration/BranchConfiguration.cs b/src/GitVersion.Configuration/BranchConfiguration.cs
index b49054a7d3..5f8cbd07bf 100644
--- a/src/GitVersion.Configuration/BranchConfiguration.cs
+++ b/src/GitVersion.Configuration/BranchConfiguration.cs
@@ -1,4 +1,5 @@
using GitVersion.Configuration.Attributes;
+using GitVersion.Core;
using GitVersion.Extensions;
using GitVersion.VersionCalculation;
@@ -26,8 +27,8 @@ internal record BranchConfiguration : IBranchConfiguration
public PreventIncrementConfiguration PreventIncrement { get; internal set; } = new();
[JsonPropertyName("label-number-pattern")]
- [JsonPropertyDescription($"The regular expression pattern to use to extract the number from the branch name. Defaults to '{ConfigurationConstants.DefaultLabelNumberPattern}'.")]
- [JsonPropertyDefault(ConfigurationConstants.DefaultLabelNumberPattern)]
+ [JsonPropertyDescription($"The regular expression pattern to use to extract the number from the branch name. Defaults to '{RegexPatterns.Configuration.DefaultLabelNumberPattern}'.")]
+ [JsonPropertyDefault(RegexPatterns.Configuration.DefaultLabelNumberPattern)]
[JsonPropertyFormat(Format.Regex)]
public string? LabelNumberPattern { get; internal set; }
diff --git a/src/GitVersion.Configuration/Builders/ConfigurationBuilderBase.cs b/src/GitVersion.Configuration/Builders/ConfigurationBuilderBase.cs
index 465b16c59c..80d6437579 100644
--- a/src/GitVersion.Configuration/Builders/ConfigurationBuilderBase.cs
+++ b/src/GitVersion.Configuration/Builders/ConfigurationBuilderBase.cs
@@ -1,3 +1,4 @@
+using GitVersion.Core;
using GitVersion.Extensions;
using GitVersion.Helpers;
using GitVersion.VersionCalculation;
@@ -47,49 +48,49 @@ internal abstract class ConfigurationBuilderBase : IConfi
protected readonly BranchMetaData MainBranch = new()
{
Name = ConfigurationConstants.MainBranchKey,
- RegexPattern = ConfigurationConstants.MainBranchRegex
+ RegexPattern = RegexPatterns.Configuration.MainBranchRegexPattern
};
protected readonly BranchMetaData DevelopBranch = new()
{
Name = ConfigurationConstants.DevelopBranchKey,
- RegexPattern = ConfigurationConstants.DevelopBranchRegex
+ RegexPattern = RegexPatterns.Configuration.DevelopBranchRegexPattern
};
protected readonly BranchMetaData ReleaseBranch = new()
{
Name = ConfigurationConstants.ReleaseBranchKey,
- RegexPattern = ConfigurationConstants.ReleaseBranchRegex
+ RegexPattern = RegexPatterns.Configuration.ReleaseBranchRegexPattern
};
protected readonly BranchMetaData FeatureBranch = new()
{
Name = ConfigurationConstants.FeatureBranchKey,
- RegexPattern = ConfigurationConstants.FeatureBranchRegex
+ RegexPattern = RegexPatterns.Configuration.FeatureBranchRegexPattern
};
protected readonly BranchMetaData PullRequestBranch = new()
{
Name = ConfigurationConstants.PullRequestBranchKey,
- RegexPattern = ConfigurationConstants.PullRequestBranchRegex
+ RegexPattern = RegexPatterns.Configuration.PullRequestBranchRegexPattern
};
protected readonly BranchMetaData HotfixBranch = new()
{
Name = ConfigurationConstants.HotfixBranchKey,
- RegexPattern = ConfigurationConstants.HotfixBranchRegex
+ RegexPattern = RegexPatterns.Configuration.HotfixBranchRegexPattern
};
protected readonly BranchMetaData SupportBranch = new()
{
Name = ConfigurationConstants.SupportBranchKey,
- RegexPattern = ConfigurationConstants.SupportBranchRegex
+ RegexPattern = RegexPatterns.Configuration.SupportBranchRegexPattern
};
protected readonly BranchMetaData UnknownBranch = new()
{
Name = ConfigurationConstants.UnknownBranchKey,
- RegexPattern = ConfigurationConstants.UnknownBranchRegex
+ RegexPattern = RegexPatterns.Configuration.UnknownBranchRegexPattern
};
protected ConfigurationBuilderBase()
@@ -130,7 +131,7 @@ public virtual TConfigurationBuilder WithAssemblyFileVersioningFormat(string? va
return (TConfigurationBuilder)this;
}
- public virtual TConfigurationBuilder WithTagPrefix(string? value)
+ public virtual TConfigurationBuilder WithTagPrefixPattern(string? value)
{
this.tagPrefix = value;
return (TConfigurationBuilder)this;
@@ -338,7 +339,7 @@ public virtual TConfigurationBuilder WithConfiguration(IGitVersionConfiguration
WithAssemblyInformationalFormat(value.AssemblyInformationalFormat);
WithAssemblyVersioningFormat(value.AssemblyVersioningFormat);
WithAssemblyFileVersioningFormat(value.AssemblyFileVersioningFormat);
- WithTagPrefix(value.TagPrefix);
+ WithTagPrefixPattern(value.TagPrefixPattern);
WithVersionInBranchPattern(value.VersionInBranchPattern);
WithNextVersion(value.NextVersion);
WithMajorVersionBumpMessage(value.MajorVersionBumpMessage);
@@ -397,7 +398,7 @@ public virtual IGitVersionConfiguration Build()
AssemblyInformationalFormat = this.assemblyInformationalFormat,
AssemblyVersioningFormat = this.assemblyVersioningFormat,
AssemblyFileVersioningFormat = this.assemblyFileVersioningFormat,
- TagPrefix = this.tagPrefix,
+ TagPrefixPattern = this.tagPrefix,
VersionInBranchPattern = this.versionInBranchPattern,
NextVersion = this.nextVersion,
MajorVersionBumpMessage = this.majorVersionBumpMessage,
diff --git a/src/GitVersion.Configuration/Builders/GitFlowConfigurationBuilder.cs b/src/GitVersion.Configuration/Builders/GitFlowConfigurationBuilder.cs
index b7ed9aff44..0122d54b8d 100644
--- a/src/GitVersion.Configuration/Builders/GitFlowConfigurationBuilder.cs
+++ b/src/GitVersion.Configuration/Builders/GitFlowConfigurationBuilder.cs
@@ -20,8 +20,8 @@ private GitFlowConfigurationBuilder()
PatchVersionBumpMessage = RegexPatterns.VersionCalculation.DefaultPatchPattern,
SemanticVersionFormat = ConfigurationConstants.DefaultSemanticVersionFormat,
VersionStrategies = ConfigurationConstants.DefaultVersionStrategies,
- TagPrefix = ConfigurationConstants.DefaultTagPrefix,
- VersionInBranchPattern = ConfigurationConstants.DefaultVersionInBranchPattern,
+ TagPrefixPattern = RegexPatterns.Configuration.DefaultTagPrefixPattern,
+ VersionInBranchPattern = RegexPatterns.Configuration.DefaultVersionInBranchPattern,
TagPreReleaseWeight = ConfigurationConstants.DefaultTagPreReleaseWeight,
UpdateBuildNumber = ConfigurationConstants.DefaultUpdateBuildNumber,
DeploymentMode = DeploymentMode.ContinuousDelivery,
@@ -145,7 +145,7 @@ private GitFlowConfigurationBuilder()
OfMergedBranch = true,
WhenCurrentCommitTagged = false
},
- LabelNumberPattern = ConfigurationConstants.DefaultLabelNumberPattern,
+ LabelNumberPattern = RegexPatterns.Configuration.DefaultLabelNumberPattern,
TrackMergeMessage = true,
PreReleaseWeight = 30000
});
diff --git a/src/GitVersion.Configuration/Builders/GitHubFlowConfigurationBuilder.cs b/src/GitVersion.Configuration/Builders/GitHubFlowConfigurationBuilder.cs
index 8af099bcdc..b31db0c152 100644
--- a/src/GitVersion.Configuration/Builders/GitHubFlowConfigurationBuilder.cs
+++ b/src/GitVersion.Configuration/Builders/GitHubFlowConfigurationBuilder.cs
@@ -20,8 +20,8 @@ private GitHubFlowConfigurationBuilder()
PatchVersionBumpMessage = RegexPatterns.VersionCalculation.DefaultPatchPattern,
SemanticVersionFormat = ConfigurationConstants.DefaultSemanticVersionFormat,
VersionStrategies = ConfigurationConstants.DefaultVersionStrategies,
- TagPrefix = ConfigurationConstants.DefaultTagPrefix,
- VersionInBranchPattern = ConfigurationConstants.DefaultVersionInBranchPattern,
+ TagPrefixPattern = RegexPatterns.Configuration.DefaultTagPrefixPattern,
+ VersionInBranchPattern = RegexPatterns.Configuration.DefaultVersionInBranchPattern,
TagPreReleaseWeight = ConfigurationConstants.DefaultTagPreReleaseWeight,
UpdateBuildNumber = ConfigurationConstants.DefaultUpdateBuildNumber,
DeploymentMode = DeploymentMode.ContinuousDelivery,
@@ -114,7 +114,7 @@ private GitHubFlowConfigurationBuilder()
OfMergedBranch = true,
WhenCurrentCommitTagged = false
},
- LabelNumberPattern = ConfigurationConstants.DefaultLabelNumberPattern,
+ LabelNumberPattern = RegexPatterns.Configuration.DefaultLabelNumberPattern,
RegularExpression = PullRequestBranch.RegexPattern,
SourceBranches =
[
diff --git a/src/GitVersion.Configuration/Builders/TrunkBasedConfigurationBuilder.cs b/src/GitVersion.Configuration/Builders/TrunkBasedConfigurationBuilder.cs
index c1fbcdf519..74ccd921e6 100644
--- a/src/GitVersion.Configuration/Builders/TrunkBasedConfigurationBuilder.cs
+++ b/src/GitVersion.Configuration/Builders/TrunkBasedConfigurationBuilder.cs
@@ -23,8 +23,8 @@ private TrunkBasedConfigurationBuilder()
VersionStrategies.ConfiguredNextVersion,
VersionStrategies.Mainline
],
- TagPrefix = ConfigurationConstants.DefaultTagPrefix,
- VersionInBranchPattern = ConfigurationConstants.DefaultVersionInBranchPattern,
+ TagPrefixPattern = RegexPatterns.Configuration.DefaultTagPrefixPattern,
+ VersionInBranchPattern = RegexPatterns.Configuration.DefaultVersionInBranchPattern,
TagPreReleaseWeight = ConfigurationConstants.DefaultTagPreReleaseWeight,
UpdateBuildNumber = ConfigurationConstants.DefaultUpdateBuildNumber,
DeploymentMode = DeploymentMode.ContinuousDelivery,
@@ -112,7 +112,7 @@ private TrunkBasedConfigurationBuilder()
OfMergedBranch = true,
WhenCurrentCommitTagged = false
},
- LabelNumberPattern = ConfigurationConstants.DefaultLabelNumberPattern,
+ LabelNumberPattern = RegexPatterns.Configuration.DefaultLabelNumberPattern,
RegularExpression = PullRequestBranch.RegexPattern,
SourceBranches =
[
diff --git a/src/GitVersion.Configuration/GitVersionConfiguration.cs b/src/GitVersion.Configuration/GitVersionConfiguration.cs
index ee6981920c..0a8c23e4d3 100644
--- a/src/GitVersion.Configuration/GitVersionConfiguration.cs
+++ b/src/GitVersion.Configuration/GitVersionConfiguration.cs
@@ -1,8 +1,6 @@
using System.Globalization;
-using System.Text.RegularExpressions;
using GitVersion.Configuration.Attributes;
using GitVersion.Core;
-using GitVersion.Extensions;
using GitVersion.VersionCalculation;
using static GitVersion.Configuration.ConfigurationConstants;
@@ -38,28 +36,17 @@ internal sealed record GitVersionConfiguration : BranchConfiguration, IGitVersio
public string? AssemblyFileVersioningFormat { get; internal set; }
[JsonPropertyName("tag-prefix")]
- [JsonPropertyDescription($"A regular expression which is used to trim Git tags before processing. Defaults to '{DefaultTagPrefix}'")]
- [JsonPropertyDefault(DefaultTagPrefix)]
+ [JsonPropertyDescription($"A regular expression which is used to trim Git tags before processing. Defaults to '{RegexPatterns.Configuration.DefaultTagPrefixPattern}'")]
+ [JsonPropertyDefault(RegexPatterns.Configuration.DefaultTagPrefixPattern)]
[JsonPropertyFormat(Format.Regex)]
- public string? TagPrefix { get; internal set; }
+ public string? TagPrefixPattern { get; internal set; }
[JsonPropertyName("version-in-branch-pattern")]
- [JsonPropertyDescription($"A regular expression which is used to determine the version number in the branch name or commit message (e.g., v1.0.0-LTS). Defaults to '{DefaultVersionInBranchPattern}'.")]
- [JsonPropertyDefault(DefaultVersionInBranchPattern)]
+ [JsonPropertyDescription($"A regular expression which is used to determine the version number in the branch name or commit message (e.g., v1.0.0-LTS). Defaults to '{RegexPatterns.Configuration.DefaultVersionInBranchPattern}'.")]
+ [JsonPropertyDefault(RegexPatterns.Configuration.DefaultVersionInBranchPattern)]
[JsonPropertyFormat(Format.Regex)]
public string? VersionInBranchPattern { get; internal set; }
- [JsonIgnore]
- public Regex VersionInBranchRegex => versionInBranchRegex ??= new(GetVersionInBranchPattern(), RegexOptions.Compiled);
- private Regex? versionInBranchRegex;
-
- private string GetVersionInBranchPattern()
- {
- var versionInBranchPattern = VersionInBranchPattern;
- if (versionInBranchPattern.IsNullOrEmpty()) versionInBranchPattern = DefaultVersionInBranchPattern;
- return $"^{versionInBranchPattern.TrimStart('^')}";
- }
-
[JsonPropertyName("next-version")]
[JsonPropertyDescription("Allows you to bump the next version explicitly. Useful for bumping main or a feature branch with breaking changes")]
public string? NextVersion
@@ -103,9 +90,7 @@ public string? NextVersion
[JsonPropertyName("commit-date-format")]
[JsonPropertyDescription($"The format to use when calculating the commit date. Defaults to '{DefaultCommitDateFormat}'. See [Standard Date and Time Format Strings](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings) and [Custom Date and Time Format Strings](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings).")]
[JsonPropertyDefault(DefaultCommitDateFormat)]
-#if NET7_0_OR_GREATER
- [System.Diagnostics.CodeAnalysis.StringSyntax("DateTimeFormat")] // See https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.stringsyntaxattribute, https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.stringsyntaxattribute.datetimeformat?view=net-7.0#system-diagnostics-codeanalysis-stringsyntaxattribute-datetimeformat
-#endif
+ [System.Diagnostics.CodeAnalysis.StringSyntax("DateTimeFormat")]
public string? CommitDateFormat { get; internal set; }
[JsonPropertyName("merge-message-formats")]
diff --git a/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs b/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs
index 6d02601c72..ebd81f0957 100644
--- a/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs
+++ b/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs
@@ -205,7 +205,7 @@ public void CacheFileExistsOnDiskWhenOverrideConfigIsSpecifiedVersionShouldBeDyn
var cacheDirectoryTimestamp = this.fileSystem.GetLastDirectoryWrite(cacheDirectory);
- var configuration = GitFlowConfigurationBuilder.New.WithTagPrefix("prefix").Build();
+ var configuration = GitFlowConfigurationBuilder.New.WithTagPrefixPattern("prefix").Build();
var overrideConfiguration = new ConfigurationHelper(configuration).Dictionary;
gitVersionOptions = new() { WorkingDirectory = fixture.RepositoryPath, ConfigurationInfo = { OverrideConfiguration = overrideConfiguration } };
diff --git a/src/GitVersion.Core.Tests/IntegrationTests/MainScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/MainScenarios.cs
index 709263c825..9609853812 100644
--- a/src/GitVersion.Core.Tests/IntegrationTests/MainScenarios.cs
+++ b/src/GitVersion.Core.Tests/IntegrationTests/MainScenarios.cs
@@ -208,14 +208,14 @@ public void CanSpecifyTagPrefixes()
fixture.Repository.MakeATaggedCommit(taggedVersion);
fixture.Repository.MakeCommits(5);
- var configuration = GitFlowConfigurationBuilder.New.WithTagPrefix("version-").Build();
+ var configuration = GitFlowConfigurationBuilder.New.WithTagPrefixPattern("version-").Build();
fixture.AssertFullSemver("1.0.4-5", configuration);
}
[Test]
public void CanSpecifyTagPrefixesAsRegex()
{
- var configuration = GitFlowConfigurationBuilder.New.WithTagPrefix($"version-|{ConfigurationConstants.DefaultTagPrefix}").Build();
+ var configuration = GitFlowConfigurationBuilder.New.WithTagPrefixPattern($"version-|{RegexPatterns.Configuration.DefaultTagPrefixPattern}").Build();
using var fixture = new EmptyRepositoryFixture();
var taggedVersion = "v1.0.3";
fixture.Repository.MakeATaggedCommit(taggedVersion);
@@ -233,7 +233,7 @@ public void CanSpecifyTagPrefixesAsRegex()
[Test]
public void AreTagsNotAdheringToTagPrefixIgnored()
{
- var configuration = GitFlowConfigurationBuilder.New.WithTagPrefix("").Build();
+ var configuration = GitFlowConfigurationBuilder.New.WithTagPrefixPattern("").Build();
using var fixture = new EmptyRepositoryFixture();
var taggedVersion = "version-1.0.3";
fixture.Repository.MakeATaggedCommit(taggedVersion);
diff --git a/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs
index 597ac26ba2..8412d0b015 100644
--- a/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs
+++ b/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs
@@ -22,7 +22,7 @@ public void CanUseCommitMessagesToBumpVersion_TagsTakePriorityOnlyIfVersions(
string expectedVersionAfterNewCommit)
{
var configuration = GitFlowConfigurationBuilder.New
- .WithTagPrefix(tagPrefix)
+ .WithTagPrefixPattern(tagPrefix)
.Build();
using var fixture = new EmptyRepositoryFixture();
@@ -61,7 +61,7 @@ public void CanUseCommitMessagesToBumpVersion_TagsTakePriorityOnlyIfVersions(
[TestCase("prefix", "bar", "2.1.0-1", "2.0.0-bar.1+1", ExpectedResult = "2.0.0-bar.1+1")]
public string WhenTaggingACommitAsPreRelease(string tagPrefix, string? label, string tag, string expectedVersion)
{
- var configuration = GitFlowConfigurationBuilder.New.WithLabel(null).WithTagPrefix(tagPrefix)
+ var configuration = GitFlowConfigurationBuilder.New.WithLabel(null).WithTagPrefixPattern(tagPrefix)
.WithBranch("main", b => b.WithLabel(label).WithDeploymentMode(DeploymentMode.ManualDeployment))
.Build();
diff --git a/src/GitVersion.Core.Tests/MergeMessageTests.cs b/src/GitVersion.Core.Tests/MergeMessageTests.cs
index 546355d2b6..79d7590f39 100644
--- a/src/GitVersion.Core.Tests/MergeMessageTests.cs
+++ b/src/GitVersion.Core.Tests/MergeMessageTests.cs
@@ -35,7 +35,7 @@ public void EmptyTagPrefix(string? prefix)
{
// Arrange
const string message = "Updated some code.";
- var configuration = GitHubFlowConfigurationBuilder.New.WithTagPrefix(prefix).Build();
+ var configuration = GitHubFlowConfigurationBuilder.New.WithTagPrefixPattern(prefix).Build();
// Act
var sut = new MergeMessage(message, configuration);
diff --git a/src/GitVersion.Core.Tests/VersionCalculation/SemanticVersionTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/SemanticVersionTests.cs
index 6a59b13317..ae8fdb55db 100644
--- a/src/GitVersion.Core.Tests/VersionCalculation/SemanticVersionTests.cs
+++ b/src/GitVersion.Core.Tests/VersionCalculation/SemanticVersionTests.cs
@@ -1,4 +1,3 @@
-using GitVersion.Configuration;
using GitVersion.Core.Tests.Helpers;
namespace GitVersion.Core.Tests;
@@ -23,9 +22,9 @@ public class SemanticVersionTests : TestBase
[TestCase("1.2.3+4.Branch.Foo", 1, 2, 3, "", null, 4, "Foo", null, null, null, null, SemanticVersionFormat.Strict)]
[TestCase("1.2.3+randomMetaData", 1, 2, 3, "", null, null, null, null, "randomMetaData", null, null, SemanticVersionFormat.Strict)]
[TestCase("1.2.3-beta.1+4.Sha.12234.Othershiz", 1, 2, 3, "beta", 1, 4, null, "12234", "Othershiz", null, null, SemanticVersionFormat.Strict)]
- [TestCase("1.2.3", 1, 2, 3, "", null, null, null, null, null, null, ConfigurationConstants.DefaultTagPrefix, SemanticVersionFormat.Strict)]
- [TestCase("v1.2.3", 1, 2, 3, "", null, null, null, null, null, "1.2.3", ConfigurationConstants.DefaultTagPrefix, SemanticVersionFormat.Strict)]
- [TestCase("V1.2.3", 1, 2, 3, "", null, null, null, null, null, "1.2.3", ConfigurationConstants.DefaultTagPrefix, SemanticVersionFormat.Strict)]
+ [TestCase("1.2.3", 1, 2, 3, "", null, null, null, null, null, null, RegexPatterns.Configuration.DefaultTagPrefixPattern, SemanticVersionFormat.Strict)]
+ [TestCase("v1.2.3", 1, 2, 3, "", null, null, null, null, null, "1.2.3", RegexPatterns.Configuration.DefaultTagPrefixPattern, SemanticVersionFormat.Strict)]
+ [TestCase("V1.2.3", 1, 2, 3, "", null, null, null, null, null, "1.2.3", RegexPatterns.Configuration.DefaultTagPrefixPattern, SemanticVersionFormat.Strict)]
[TestCase("version-1.2.3", 1, 2, 3, "", null, null, null, null, null, "1.2.3", "version-", SemanticVersionFormat.Strict)]
[TestCase("1.0.0-develop-20201007113711", 1, 0, 0, "develop-20201007113711", null, null, null, null, null, "1.0.0-develop-20201007113711", null, SemanticVersionFormat.Strict)]
[TestCase("20201007113711.658165168461351.64136516984163213-develop-20201007113711.98848747823+65416321321", 20201007113711, 658165168461351, 64136516984163213, "develop-20201007113711", 98848747823, 65416321321, null, null, null, "20201007113711.658165168461351.64136516984163213-develop-20201007113711.98848747823+65416321321", null, SemanticVersionFormat.Strict)]
@@ -63,7 +62,7 @@ public void ValidateVersionParsing(
[TestCase("someText")]
[TestCase("some-T-ext")]
- [TestCase("v.1.2.3", ConfigurationConstants.DefaultTagPrefix)]
+ [TestCase("v.1.2.3", RegexPatterns.Configuration.DefaultTagPrefixPattern)]
public void ValidateInvalidVersionParsing(string versionString, string? tagPrefixRegex = null) =>
Assert.That(SemanticVersion.TryParse(versionString, tagPrefixRegex, out _), Is.False, "TryParse Result");
diff --git a/src/GitVersion.Core/Configuration/ConfigurationConstants.cs b/src/GitVersion.Core/Configuration/ConfigurationConstants.cs
index f09f24f83d..f8774c93ba 100644
--- a/src/GitVersion.Core/Configuration/ConfigurationConstants.cs
+++ b/src/GitVersion.Core/Configuration/ConfigurationConstants.cs
@@ -22,14 +22,8 @@ internal static class ConfigurationConstants
VersionStrategies.VersionInBranchName
];
public const string DefaultAssemblyInformationalFormat = "{InformationalVersion}";
- //language=regexp
- public const string DefaultTagPrefix = "[vV]?";
- //language=regexp
- public const string DefaultVersionInBranchPattern = @"(?[vV]?\d+(\.\d+)?(\.\d+)?).*";
public const string DefaultCommitDateFormat = "yyyy-MM-dd";
public const string BranchNamePlaceholder = "{BranchName}";
- //language=regexp
- public const string DefaultLabelNumberPattern = @"[/-](?\d+)";
public const bool DefaultUpdateBuildNumber = true;
public const int DefaultTagPreReleaseWeight = 60000;
@@ -42,21 +36,4 @@ internal static class ConfigurationConstants
public const string HotfixBranchKey = "hotfix";
public const string SupportBranchKey = "support";
public const string UnknownBranchKey = "unknown";
-
- //language=regexp
- public const string MainBranchRegex = "^master$|^main$";
- //language=regexp
- public const string DevelopBranchRegex = "^dev(elop)?(ment)?$";
- //language=regexp
- public const string ReleaseBranchRegex = "^releases?[/-](?.+)";
- //language=regexp
- public const string FeatureBranchRegex = "^features?[/-](?.+)";
- //language=regexp
- public const string PullRequestBranchRegex = @"^(pull|pull\-requests|pr)[/-]";
- //language=regexp
- public const string HotfixBranchRegex = "^hotfix(es)?[/-](?.+)";
- //language=regexp
- public const string SupportBranchRegex = "^support[/-](?.+)";
- //language=regexp
- public const string UnknownBranchRegex = "(?.+)";
}
diff --git a/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs b/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs
index 9708f95329..c7514c34cc 100644
--- a/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs
+++ b/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs
@@ -1,4 +1,3 @@
-using System.Text.RegularExpressions;
using GitVersion.Extensions;
using GitVersion.VersionCalculation;
@@ -10,7 +9,9 @@ namespace GitVersion.Configuration;
///
public record EffectiveConfiguration
{
- public EffectiveConfiguration(IGitVersionConfiguration configuration, IBranchConfiguration branchConfiguration,
+ public EffectiveConfiguration(
+ IGitVersionConfiguration configuration,
+ IBranchConfiguration branchConfiguration,
EffectiveConfiguration? fallbackConfiguration = null)
{
configuration.NotNull();
@@ -50,8 +51,8 @@ public EffectiveConfiguration(IGitVersionConfiguration configuration, IBranchCon
AssemblyVersioningFormat = configuration.AssemblyVersioningFormat;
AssemblyFileVersioningFormat = configuration.AssemblyFileVersioningFormat;
DeploymentMode = branchConfiguration.DeploymentMode.Value;
- TagPrefix = configuration.TagPrefix;
- VersionInBranchRegex = configuration.VersionInBranchRegex;
+ TagPrefix = configuration.TagPrefixPattern;
+ VersionInBranchPattern = configuration.VersionInBranchPattern;
Label = branchConfiguration.Label;
NextVersion = configuration.NextVersion;
Increment = branchConfiguration.Increment;
@@ -90,16 +91,10 @@ public EffectiveConfiguration(IGitVersionConfiguration configuration, IBranchCon
public string? AssemblyVersioningFormat { get; }
public string? AssemblyFileVersioningFormat { get; }
- ///
- /// Git tag prefix
- ///
public string? TagPrefix { get; }
- public Regex VersionInBranchRegex { get; }
+ public string? VersionInBranchPattern { get; }
- ///
- /// Label to use when calculating SemVer
- ///
public string? Label { get; }
public string? NextVersion { get; }
diff --git a/src/GitVersion.Core/Configuration/IBranchConfiguration.cs b/src/GitVersion.Core/Configuration/IBranchConfiguration.cs
index 52d05a612f..cf81ef3dcc 100644
--- a/src/GitVersion.Core/Configuration/IBranchConfiguration.cs
+++ b/src/GitVersion.Core/Configuration/IBranchConfiguration.cs
@@ -1,4 +1,5 @@
-using System.Text.RegularExpressions;
+using GitVersion.Core;
+using GitVersion.Extensions;
using GitVersion.VersionCalculation;
namespace GitVersion.Configuration;
@@ -24,7 +25,15 @@ public interface IBranchConfiguration
public string? RegularExpression { get; }
public bool IsMatch(string branchName)
- => RegularExpression != null && Regex.IsMatch(branchName, RegularExpression, RegexOptions.IgnoreCase);
+ {
+ if (string.IsNullOrWhiteSpace(RegularExpression))
+ {
+ return false;
+ }
+
+ var regex = RegexPatterns.Cache.GetOrAdd(RegularExpression);
+ return regex.IsMatch(branchName);
+ }
IReadOnlyCollection SourceBranches { get; }
diff --git a/src/GitVersion.Core/Configuration/IGitVersionConfiguration.cs b/src/GitVersion.Core/Configuration/IGitVersionConfiguration.cs
index 60307b3cd1..1461d38034 100644
--- a/src/GitVersion.Core/Configuration/IGitVersionConfiguration.cs
+++ b/src/GitVersion.Core/Configuration/IGitVersionConfiguration.cs
@@ -1,4 +1,3 @@
-using System.Text.RegularExpressions;
using GitVersion.VersionCalculation;
namespace GitVersion.Configuration;
@@ -17,12 +16,10 @@ public interface IGitVersionConfiguration : IBranchConfiguration
string? AssemblyFileVersioningFormat { get; }
- string? TagPrefix { get; }
+ string? TagPrefixPattern { get; }
string? VersionInBranchPattern { get; }
- Regex VersionInBranchRegex { get; }
-
string? NextVersion { get; }
string? MajorVersionBumpMessage { get; }
diff --git a/src/GitVersion.Core/Configuration/ReferenceNameExtensions.cs b/src/GitVersion.Core/Configuration/ReferenceNameExtensions.cs
index dd05cab0f2..630d637746 100644
--- a/src/GitVersion.Core/Configuration/ReferenceNameExtensions.cs
+++ b/src/GitVersion.Core/Configuration/ReferenceNameExtensions.cs
@@ -1,14 +1,54 @@
+using GitVersion.Core;
+using GitVersion.Extensions;
using GitVersion.Git;
namespace GitVersion.Configuration;
public static class ReferenceNameExtensions
{
- public static bool TryGetSemanticVersion(
- this ReferenceName source, out (SemanticVersion Value, string? Name) result, IGitVersionConfiguration configuration)
- => source.TryGetSemanticVersion(out result, configuration.VersionInBranchRegex, configuration.TagPrefix, configuration.SemanticVersionFormat);
+ public static bool TryGetSemanticVersion(this ReferenceName source, out (SemanticVersion Value, string? Name) result, EffectiveConfiguration configuration)
+ => source.TryGetSemanticVersion(out result, configuration.VersionInBranchPattern, configuration.TagPrefix, configuration.SemanticVersionFormat);
- public static bool TryGetSemanticVersion(
- this ReferenceName source, out (SemanticVersion Value, string? Name) result, EffectiveConfiguration configuration)
- => source.TryGetSemanticVersion(out result, configuration.VersionInBranchRegex, configuration.TagPrefix, configuration.SemanticVersionFormat);
+ public static bool TryGetSemanticVersion(this ReferenceName source, out (SemanticVersion Value, string? Name) result, IGitVersionConfiguration configuration)
+ => source.TryGetSemanticVersion(out result, configuration.VersionInBranchPattern, configuration.TagPrefixPattern, configuration.SemanticVersionFormat);
+
+ private static bool TryGetSemanticVersion(this ReferenceName referenceName, out (SemanticVersion Value, string? Name) result,
+ string? versionPatternPattern,
+ string? tagPrefix,
+ SemanticVersionFormat format)
+ {
+ var versionPatternRegex = RegexPatterns.Cache.GetOrAdd(GetVersionInBranchPattern(versionPatternPattern));
+ result = default;
+
+ int length = 0;
+ foreach (var branchPart in referenceName.WithoutOrigin.Split(GetBranchSeparator()))
+ {
+ if (string.IsNullOrEmpty(branchPart)) return false;
+
+ var match = versionPatternRegex.Match(branchPart);
+ if (match.Success)
+ {
+ var versionPart = match.Groups["version"].Value;
+ if (SemanticVersion.TryParse(versionPart, tagPrefix, out var semanticVersion, format))
+ {
+ length += versionPart.Length;
+ var name = referenceName.WithoutOrigin[length..].Trim('-');
+ result = new(semanticVersion, name.Length == 0 ? null : name);
+ return true;
+ }
+ }
+
+ length += branchPart.Length + 1;
+ }
+
+ return false;
+
+ char GetBranchSeparator() => referenceName.WithoutOrigin.Contains('/') || !referenceName.WithoutOrigin.Contains('-') ? '/' : '-';
+
+ static string GetVersionInBranchPattern(string? versionInBranchPattern)
+ {
+ if (versionInBranchPattern.IsNullOrEmpty()) versionInBranchPattern = RegexPatterns.Configuration.DefaultVersionInBranchPattern;
+ return $"^{versionInBranchPattern.TrimStart('^')}";
+ }
+ }
}
diff --git a/src/GitVersion.Core/Core/GitVersionContextFactory.cs b/src/GitVersion.Core/Core/GitVersionContextFactory.cs
index d75bc4ab6b..537c6145b9 100644
--- a/src/GitVersion.Core/Core/GitVersionContextFactory.cs
+++ b/src/GitVersion.Core/Core/GitVersionContextFactory.cs
@@ -41,7 +41,7 @@ public GitVersionContext Create(GitVersionOptions gitVersionOptions)
}
bool isCurrentCommitTagged = this.taggedSemanticVersionRepository.GetTaggedSemanticVersions(
- tagPrefix: configuration.TagPrefix,
+ tagPrefix: configuration.TagPrefixPattern,
format: configuration.SemanticVersionFormat,
ignore: configuration.Ignore
).Contains(currentCommit);
diff --git a/src/GitVersion.Core/Core/MainlineBranchFinder.cs b/src/GitVersion.Core/Core/MainlineBranchFinder.cs
index 2e2ad2fe96..8f818cf303 100644
--- a/src/GitVersion.Core/Core/MainlineBranchFinder.cs
+++ b/src/GitVersion.Core/Core/MainlineBranchFinder.cs
@@ -1,6 +1,6 @@
-using System.Text.RegularExpressions;
using GitVersion.Common;
using GitVersion.Configuration;
+using GitVersion.Core;
using GitVersion.Extensions;
using GitVersion.Git;
using GitVersion.Logging;
@@ -47,10 +47,10 @@ public bool IsMainBranch(IBranchConfiguration value)
if (value.RegularExpression == null)
return false;
- var mainlineRegex = value.RegularExpression;
+ var regex = RegexPatterns.Cache.GetOrAdd(value.RegularExpression);
var branchName = this.branch.Name.WithoutOrigin;
- var match = Regex.IsMatch(branchName, mainlineRegex);
- this.log.Info($"'{mainlineRegex}' {(match ? "matches" : "does not match")} '{branchName}'.");
+ var match = regex.IsMatch(branchName);
+ this.log.Info($"'{value.RegularExpression}' {(match ? "matches" : "does not match")} '{branchName}'.");
return match;
}
}
diff --git a/src/GitVersion.Core/Core/RegexPatterns.cs b/src/GitVersion.Core/Core/RegexPatterns.cs
index 3b57dc5c4f..23f7b82d0a 100644
--- a/src/GitVersion.Core/Core/RegexPatterns.cs
+++ b/src/GitVersion.Core/Core/RegexPatterns.cs
@@ -1,61 +1,168 @@
+using System.Collections.Concurrent;
+using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
namespace GitVersion.Core;
internal static class RegexPatterns
{
+ private const RegexOptions Options = RegexOptions.IgnoreCase | RegexOptions.Compiled;
+
+ internal static readonly ConcurrentDictionary Cache = new();
+
+ static RegexPatterns()
+ {
+ Cache.TryAdd(Common.SwitchArgumentRegex.ToString(), Common.SwitchArgumentRegex);
+ Cache.TryAdd(Common.ObscurePasswordRegex.ToString(), Common.ObscurePasswordRegex);
+ Cache.TryAdd(Common.ExpandTokensRegex.ToString(), Common.ExpandTokensRegex);
+
+ Cache.TryAdd(Configuration.DefaultTagPrefixRegex.ToString(), Configuration.DefaultTagPrefixRegex);
+ Cache.TryAdd(Configuration.DefaultVersionInBranchRegex.ToString(), Configuration.DefaultVersionInBranchRegex);
+ Cache.TryAdd(Configuration.DefaultLabelNumberRegex.ToString(), Configuration.DefaultLabelNumberRegex);
+ Cache.TryAdd(Configuration.MainBranchRegex.ToString(), Configuration.MainBranchRegex);
+ Cache.TryAdd(Configuration.DevelopBranchRegex.ToString(), Configuration.DevelopBranchRegex);
+ Cache.TryAdd(Configuration.ReleaseBranchRegex.ToString(), Configuration.ReleaseBranchRegex);
+ Cache.TryAdd(Configuration.FeatureBranchRegex.ToString(), Configuration.FeatureBranchRegex);
+ Cache.TryAdd(Configuration.PullRequestBranchRegex.ToString(), Configuration.PullRequestBranchRegex);
+ Cache.TryAdd(Configuration.HotfixBranchRegex.ToString(), Configuration.HotfixBranchRegex);
+ Cache.TryAdd(Configuration.SupportBranchRegex.ToString(), Configuration.SupportBranchRegex);
+ Cache.TryAdd(Configuration.UnknownBranchRegex.ToString(), Configuration.UnknownBranchRegex);
+
+ Cache.TryAdd(MergeMessage.DefaultMergeMessageRegex.ToString(), MergeMessage.DefaultMergeMessageRegex);
+ Cache.TryAdd(MergeMessage.SmartGitMergeMessageRegex.ToString(), MergeMessage.SmartGitMergeMessageRegex);
+ Cache.TryAdd(MergeMessage.BitBucketPullMergeMessageRegex.ToString(), MergeMessage.BitBucketPullMergeMessageRegex);
+ Cache.TryAdd(MergeMessage.BitBucketPullv7MergeMessageRegex.ToString(), MergeMessage.BitBucketPullv7MergeMessageRegex);
+ Cache.TryAdd(MergeMessage.BitBucketCloudPullMergeMessageRegex.ToString(), MergeMessage.BitBucketCloudPullMergeMessageRegex);
+ Cache.TryAdd(MergeMessage.GitHubPullMergeMessageRegex.ToString(), MergeMessage.GitHubPullMergeMessageRegex);
+ Cache.TryAdd(MergeMessage.RemoteTrackingMergeMessageRegex.ToString(), MergeMessage.RemoteTrackingMergeMessageRegex);
+ Cache.TryAdd(MergeMessage.AzureDevOpsPullMergeMessageRegex.ToString(), MergeMessage.AzureDevOpsPullMergeMessageRegex);
+
+ Cache.TryAdd(Output.AssemblyVersionRegex.ToString(), Output.AssemblyVersionRegex);
+ Cache.TryAdd(Output.AssemblyInfoVersionRegex.ToString(), Output.AssemblyInfoVersionRegex);
+ Cache.TryAdd(Output.AssemblyFileVersionRegex.ToString(), Output.AssemblyFileVersionRegex);
+ Cache.TryAdd(Output.CsharpAssemblyAttributeRegex.ToString(), Output.CsharpAssemblyAttributeRegex);
+ Cache.TryAdd(Output.FsharpAssemblyAttributeRegex.ToString(), Output.FsharpAssemblyAttributeRegex);
+ Cache.TryAdd(Output.VisualBasicAssemblyAttributeRegex.ToString(), Output.VisualBasicAssemblyAttributeRegex);
+
+ Cache.TryAdd(VersionCalculation.DefaultMajorRegex.ToString(), VersionCalculation.DefaultMajorRegex);
+ Cache.TryAdd(VersionCalculation.DefaultMinorRegex.ToString(), VersionCalculation.DefaultMinorRegex);
+ Cache.TryAdd(VersionCalculation.DefaultPatchRegex.ToString(), VersionCalculation.DefaultPatchRegex);
+ Cache.TryAdd(VersionCalculation.DefaultNoBumpRegex.ToString(), VersionCalculation.DefaultNoBumpRegex);
+
+ Cache.TryAdd(SemanticVersion.ParseStrictRegex.ToString(), SemanticVersion.ParseStrictRegex);
+ Cache.TryAdd(SemanticVersion.ParseLooseRegex.ToString(), SemanticVersion.ParseLooseRegex);
+ Cache.TryAdd(SemanticVersion.ParseBuildMetaDataRegex.ToString(), SemanticVersion.ParseBuildMetaDataRegex);
+ Cache.TryAdd(SemanticVersion.FormatBuildMetaDataRegex.ToString(), SemanticVersion.FormatBuildMetaDataRegex);
+ Cache.TryAdd(SemanticVersion.ParsePreReleaseTagRegex.ToString(), SemanticVersion.ParsePreReleaseTagRegex);
+
+ Cache.TryAdd(AssemblyVersion.CSharp.TriviaRegex.ToString(), AssemblyVersion.CSharp.TriviaRegex);
+ Cache.TryAdd(AssemblyVersion.CSharp.AttributeRegex.ToString(), AssemblyVersion.CSharp.AttributeRegex);
+ Cache.TryAdd(AssemblyVersion.FSharp.TriviaRegex.ToString(), AssemblyVersion.FSharp.TriviaRegex);
+ Cache.TryAdd(AssemblyVersion.FSharp.AttributeRegex.ToString(), AssemblyVersion.FSharp.AttributeRegex);
+ Cache.TryAdd(AssemblyVersion.VisualBasic.TriviaRegex.ToString(), AssemblyVersion.VisualBasic.TriviaRegex);
+ Cache.TryAdd(AssemblyVersion.VisualBasic.AttributeRegex.ToString(), AssemblyVersion.VisualBasic.AttributeRegex);
+ }
+
internal static class Common
{
- public static Regex SwitchArgumentRegex { get; } = new(@"/\w+:", RegexOptions.Compiled);
- public static Regex ObscurePasswordRegex { get; } = new("(https?://)(.+)(:.+@)", RegexOptions.Compiled);
+ public static Regex SwitchArgumentRegex { get; } = new(@"/\w+:", Options);
+ public static Regex ObscurePasswordRegex { get; } = new("(https?://)(.+)(:.+@)", Options);
// This regex matches an expression to replace.
// - env:ENV name OR a member name
// - optional fallback value after " ?? "
// - the fallback value should be a quoted string, but simple unquoted text is allowed for back compat
- public static Regex ExpandTokensRegex { get; } = new("""{((env:(?\w+))|(?\w+))(\s+(\?\?)??\s+((?\w+)|"(?.*)"))??}""", RegexOptions.Compiled);
+ public static Regex ExpandTokensRegex { get; } = new("""{((env:(?\w+))|(?\w+))(\s+(\?\?)??\s+((?\w+)|"(?.*)"))??}""", Options);
+ }
+
+ internal static class Configuration
+ {
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string DefaultTagPrefixPattern = "[vV]?";
+
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string DefaultVersionInBranchPattern = @"(?[vV]?\d+(\.\d+)?(\.\d+)?).*";
+
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string DefaultLabelNumberPattern = @"[/-](?\d+)";
+
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string MainBranchRegexPattern = "^master$|^main$";
+
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string DevelopBranchRegexPattern = "^dev(elop)?(ment)?$";
+
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string ReleaseBranchRegexPattern = "^releases?[/-](?.+)";
+
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string FeatureBranchRegexPattern = "^features?[/-](?.+)";
+
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string PullRequestBranchRegexPattern = @"^(pull|pull\-requests|pr)[/-]";
+
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string HotfixBranchRegexPattern = "^hotfix(es)?[/-](?.+)";
+
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string SupportBranchRegexPattern = "^support[/-](?.+)";
+
+ [StringSyntax(StringSyntaxAttribute.Regex)]
+ public const string UnknownBranchRegexPattern = "(?.+)";
+
+ public static Regex DefaultTagPrefixRegex { get; } = new(DefaultTagPrefixPattern, Options);
+ public static Regex DefaultVersionInBranchRegex { get; } = new(DefaultVersionInBranchPattern, Options);
+ public static Regex DefaultLabelNumberRegex { get; } = new(DefaultLabelNumberPattern, Options);
+ public static Regex MainBranchRegex { get; } = new(MainBranchRegexPattern, Options);
+ public static Regex DevelopBranchRegex { get; } = new(DevelopBranchRegexPattern, Options);
+ public static Regex ReleaseBranchRegex { get; } = new(ReleaseBranchRegexPattern, Options);
+ public static Regex FeatureBranchRegex { get; } = new(FeatureBranchRegexPattern, Options);
+ public static Regex PullRequestBranchRegex { get; } = new(PullRequestBranchRegexPattern, Options);
+ public static Regex HotfixBranchRegex { get; } = new(HotfixBranchRegexPattern, Options);
+ public static Regex SupportBranchRegex { get; } = new(SupportBranchRegexPattern, Options);
+ public static Regex UnknownBranchRegex { get; } = new(UnknownBranchRegexPattern, Options);
}
internal static class MergeMessage
{
- public static Regex DefaultMergeMessageRegex { get; } = new(@"^Merge (branch|tag) '(?[^']*)'(?: into (?[^\s]*))*", RegexOptions.IgnoreCase | RegexOptions.Compiled);
- public static Regex SmartGitMergeMessageRegex { get; } = new(@"^Finish (?[^\s]*)(?: into (?[^\s]*))*", RegexOptions.IgnoreCase | RegexOptions.Compiled);
- public static Regex BitBucketPullMergeMessageRegex { get; } = new(@"^Merge pull request #(?\d+) (from|in) (?.*) from (?[^\s]*) to (?[^\s]*)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
- public static Regex BitBucketPullv7MergeMessageRegex { get; } = new(@"^Pull request #(?\d+).*\r?\n\r?\nMerge in (?.*) from (?[^\s]*) to (?[^\s]*)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
- public static Regex BitBucketCloudPullMergeMessageRegex { get; } = new(@"^Merged in (?[^\s]*) \(pull request #(?\d+)\)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
- public static Regex GitHubPullMergeMessageRegex { get; } = new(@"^Merge pull request #(?\d+) (from|in) (?:[^\s\/]+\/)?(?[^\s]*)(?: into (?[^\s]*))*", RegexOptions.IgnoreCase | RegexOptions.Compiled);
- public static Regex RemoteTrackingMergeMessageRegex { get; } = new(@"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*", RegexOptions.IgnoreCase | RegexOptions.Compiled);
- public static Regex AzureDevOpsPullMergeMessageRegex { get; } = new(@"^Merge pull request (?\d+) from (?[^\s]*) into (?[^\s]*)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ public static Regex DefaultMergeMessageRegex { get; } = new(@"^Merge (branch|tag) '(?[^']*)'(?: into (?[^\s]*))*", Options);
+ public static Regex SmartGitMergeMessageRegex { get; } = new(@"^Finish (?[^\s]*)(?: into (?[^\s]*))*", Options);
+ public static Regex BitBucketPullMergeMessageRegex { get; } = new(@"^Merge pull request #(?\d+) (from|in) (?.*) from (?[^\s]*) to (?[^\s]*)", Options);
+ public static Regex BitBucketPullv7MergeMessageRegex { get; } = new(@"^Pull request #(?\d+).*\r?\n\r?\nMerge in (?.*) from (?[^\s]*) to (?[^\s]*)", Options);
+ public static Regex BitBucketCloudPullMergeMessageRegex { get; } = new(@"^Merged in (?[^\s]*) \(pull request #(?\d+)\)", Options);
+ public static Regex GitHubPullMergeMessageRegex { get; } = new(@"^Merge pull request #(?\d+) (from|in) (?:[^\s\/]+\/)?(?[^\s]*)(?: into (?[^\s]*))*", Options);
+ public static Regex RemoteTrackingMergeMessageRegex { get; } = new(@"^Merge remote-tracking branch '(?[^\s]*)'(?: into (?[^\s]*))*", Options);
+ public static Regex AzureDevOpsPullMergeMessageRegex { get; } = new(@"^Merge pull request (?\d+) from (?[^\s]*) into (?[^\s]*)", Options);
}
internal static class Output
{
- public static Regex AssemblyVersionRegex { get; } = new(@"AssemblyVersion(Attribute)?\s*\(.*\)\s*");
- public static Regex AssemblyInfoVersionRegex { get; } = new(@"AssemblyInformationalVersion(Attribute)?\s*\(.*\)\s*");
- public static Regex AssemblyFileVersionRegex { get; } = new(@"AssemblyFileVersion(Attribute)?\s*\(.*\)\s*");
- public static Regex CsharpAssemblyAttributeRegex { get; } = new(@"(\s*\[\s*assembly:\s*(?:.*)\s*\]\s*$(\r?\n)?)", RegexOptions.Multiline);
- public static Regex FsharpAssemblyAttributeRegex { get; } = new(@"(\s*\[\s*\\s*\]\s*$(\r?\n)?)", RegexOptions.Multiline);
- public static Regex VisualBasicAssemblyAttributeRegex { get; } = new(@"(\s*\\s*$(\r?\n)?)", RegexOptions.Multiline);
+ public static Regex AssemblyVersionRegex { get; } = new(@"AssemblyVersion(Attribute)?\s*\(.*\)\s*", Options);
+ public static Regex AssemblyInfoVersionRegex { get; } = new(@"AssemblyInformationalVersion(Attribute)?\s*\(.*\)\s*", Options);
+ public static Regex AssemblyFileVersionRegex { get; } = new(@"AssemblyFileVersion(Attribute)?\s*\(.*\)\s*", Options);
+ public static Regex CsharpAssemblyAttributeRegex { get; } = new(@"(\s*\[\s*assembly:\s*(?:.*)\s*\]\s*$(\r?\n)?)", Options | RegexOptions.Multiline);
+ public static Regex FsharpAssemblyAttributeRegex { get; } = new(@"(\s*\[\s*\\s*\]\s*$(\r?\n)?)", Options | RegexOptions.Multiline);
+ public static Regex VisualBasicAssemblyAttributeRegex { get; } = new(@"(\s*\\s*$(\r?\n)?)", Options | RegexOptions.Multiline);
}
internal static class VersionCalculation
{
- //language=regexp
+ [StringSyntax(StringSyntaxAttribute.Regex)]
public const string DefaultMajorPattern = @"\+semver:\s?(breaking|major)";
- //language=regexp
+ [StringSyntax(StringSyntaxAttribute.Regex)]
public const string DefaultMinorPattern = @"\+semver:\s?(feature|minor)";
- //language=regexp
+ [StringSyntax(StringSyntaxAttribute.Regex)]
public const string DefaultPatchPattern = @"\+semver:\s?(fix|patch)";
- //language=regexp
+ [StringSyntax(StringSyntaxAttribute.Regex)]
public const string DefaultNoBumpPattern = @"\+semver:\s?(none|skip)";
- public static Regex DefaultMajorPatternRegex { get; } = new(DefaultMajorPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
- public static Regex DefaultMinorPatternRegex { get; } = new(DefaultMinorPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
- public static Regex DefaultPatchPatternRegex { get; } = new(DefaultPatchPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
- public static Regex DefaultNoBumpPatternRegex { get; } = new(DefaultNoBumpPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ public static Regex DefaultMajorRegex { get; } = new(DefaultMajorPattern, Options);
+ public static Regex DefaultMinorRegex { get; } = new(DefaultMinorPattern, Options);
+ public static Regex DefaultPatchRegex { get; } = new(DefaultPatchPattern, Options);
+ public static Regex DefaultNoBumpRegex { get; } = new(DefaultNoBumpPattern, Options);
}
internal static class SemanticVersion
@@ -63,21 +170,71 @@ internal static class SemanticVersion
// uses the git-semver spec https://github.com/semver/semver/blob/master/semver.md
public static Regex ParseStrictRegex { get; } = new(
@"^(?0|[1-9]\d*)\.(?0|[1-9]\d*)\.(?0|[1-9]\d*)(?:-(?(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$",
- RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ Options);
public static Regex ParseLooseRegex { get; } = new(
@"^(?(?\d+)(\.(?\d+))?(\.(?\d+))?)(\.(?\d+))?(-(?[^\+]*))?(\+(?.*))?$",
- RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ Options);
public static Regex ParseBuildMetaDataRegex { get; } = new(
@"(?\d+)?(\.?Branch(Name)?\.(?[^\.]+))?(\.?Sha?\.(?[^\.]+))?(?.*)",
- RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ Options);
public static Regex FormatBuildMetaDataRegex { get; } = new("[^0-9A-Za-z-.]",
- RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ Options);
public static Regex ParsePreReleaseTagRegex { get; } = new(
@"(?.*?)\.?(?\d+)?$",
- RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ Options);
+ }
+
+ internal static class AssemblyVersion
+ {
+ internal static class CSharp
+ {
+ public static Regex TriviaRegex { get; } = new(@"
+ /\*(.*?)\*/ # Block comments: matches /* ... */
+ |//(.*?)\r?\n # Line comments: matches // ... followed by a newline
+ |""((\\[^\n]|[^""\n])*)"" # Strings: matches "" ... "" including escaped quotes",
+ RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options);
+
+ public static Regex AttributeRegex { get; } = new(@"(?x) # IgnorePatternWhitespace
+\[\s*assembly\s*:\s* # The [assembly: part
+(System\s*\.\s*Reflection\s*\.\s*)? # The System.Reflection. part (optional)
+Assembly(File|Informational)?Version # The attribute AssemblyVersion, AssemblyFileVersion, or AssemblyInformationalVersion
+\s*\(\s*\)\s*\] # End brackets ()]",
+ RegexOptions.IgnorePatternWhitespace | Options);
+ }
+
+ internal static class FSharp
+ {
+ public static Regex TriviaRegex { get; } = new(@"
+ /\*(.*?)\*/ # Block comments: matches /* ... */
+ |//(.*?)\r?\n # Line comments: matches // ... followed by a newline
+ |""((\\[^\n]|[^""\n])*)"" # Strings: matches "" ... "" including escaped quotes",
+ RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options);
+
+ public static Regex AttributeRegex { get; } = new(@"(?x) # IgnorePatternWhitespace
+\[\s*<\s*assembly\s*:\s* # The [\s*\] # End brackets ()>]",
+ RegexOptions.IgnorePatternWhitespace | Options);
+ }
+
+ internal static class VisualBasic
+ {
+ public static Regex TriviaRegex { get; } = new(@"
+ '(.*?)\r?\n # Line comments: matches // ... followed by a newline
+ |""((\\[^\n]|[^""\n])*)"" # Strings: matches "" ... "" including escaped quotes",
+ RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options);
+
+ public static Regex AttributeRegex { get; } = new(@"(?x) # IgnorePatternWhitespace
+\<\s*Assembly\s*:\s* # The # End brackets ()>",
+ RegexOptions.IgnorePatternWhitespace | Options);
+ }
}
}
diff --git a/src/GitVersion.Core/Core/SourceBranchFinder.cs b/src/GitVersion.Core/Core/SourceBranchFinder.cs
index 21dad72d68..5eccba40bf 100644
--- a/src/GitVersion.Core/Core/SourceBranchFinder.cs
+++ b/src/GitVersion.Core/Core/SourceBranchFinder.cs
@@ -1,5 +1,6 @@
using System.Text.RegularExpressions;
using GitVersion.Configuration;
+using GitVersion.Core;
using GitVersion.Extensions;
using GitVersion.Git;
@@ -18,7 +19,7 @@ public IEnumerable FindSourceBranchesOf(IBranch branch)
private class SourceBranchPredicate(IBranch branch, IGitVersionConfiguration configuration)
{
- private readonly IEnumerable sourceBranchRegexes = GetSourceBranchRegexes(branch, configuration);
+ private readonly IEnumerable sourceBranchRegexes = GetSourceBranchRegexes(branch, configuration);
public bool IsSourceBranch(INamedReference sourceBranchCandidate)
{
@@ -27,15 +28,15 @@ public bool IsSourceBranch(INamedReference sourceBranchCandidate)
var branchName = sourceBranchCandidate.Name.WithoutOrigin;
- return this.sourceBranchRegexes.Any(regex => Regex.IsMatch(branchName, regex));
+ return this.sourceBranchRegexes.Any(regex => regex.IsMatch(branchName));
}
- private static IEnumerable GetSourceBranchRegexes(INamedReference branch, IGitVersionConfiguration configuration)
+ private static IEnumerable GetSourceBranchRegexes(INamedReference branch, IGitVersionConfiguration configuration)
{
var currentBranchConfig = configuration.GetBranchConfiguration(branch.Name);
if (currentBranchConfig.SourceBranches == null)
{
- yield return ".*";
+ yield return RegexPatterns.Cache.GetOrAdd(".*");
}
else
{
@@ -44,7 +45,7 @@ private static IEnumerable GetSourceBranchRegexes(INamedReference branch
{
var regex = branches[sourceBranch].RegularExpression;
if (regex != null)
- yield return regex;
+ yield return RegexPatterns.Cache.GetOrAdd(regex);
}
}
}
diff --git a/src/GitVersion.Core/Core/TaggedSemanticVersionService.cs b/src/GitVersion.Core/Core/TaggedSemanticVersionService.cs
index e7e8acffa9..86a99c8849 100644
--- a/src/GitVersion.Core/Core/TaggedSemanticVersionService.cs
+++ b/src/GitVersion.Core/Core/TaggedSemanticVersionService.cs
@@ -25,7 +25,7 @@ IEnumerable>> GetEleme
{
yield return GetTaggedSemanticVersionsOfBranchInternal(
branch: branch,
- tagPrefix: configuration.TagPrefix,
+ tagPrefix: configuration.TagPrefixPattern,
format: configuration.SemanticVersionFormat,
ignore: configuration.Ignore,
label: label,
@@ -37,7 +37,7 @@ IEnumerable>> GetEleme
{
yield return GetTaggedSemanticVersionsOfMergeTargetInternal(
branch: branch,
- tagPrefix: configuration.TagPrefix,
+ tagPrefix: configuration.TagPrefixPattern,
format: configuration.SemanticVersionFormat,
ignore: configuration.Ignore,
label: label,
@@ -192,7 +192,7 @@ private IEnumerable> GetTaggedSema
{
var taggedSemanticVersions = GetTaggedSemanticVersionsOfBranchInternal(
branch: releaseBranch,
- tagPrefix: configuration.TagPrefix,
+ tagPrefix: configuration.TagPrefixPattern,
format: configuration.SemanticVersionFormat,
ignore: configuration.Ignore,
label: label,
@@ -232,7 +232,7 @@ private IEnumerable> GetTaggedSema
{
var taggedSemanticVersions = GetTaggedSemanticVersionsOfBranchInternal(
branch: releaseBranch,
- tagPrefix: configuration.TagPrefix,
+ tagPrefix: configuration.TagPrefixPattern,
format: configuration.SemanticVersionFormat,
ignore: configuration.Ignore,
label: label,
diff --git a/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs b/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs
index 66686ba81b..caa4032bdd 100644
--- a/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs
+++ b/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs
@@ -1,4 +1,4 @@
-using System.Text.RegularExpressions;
+using GitVersion.Core;
using GitVersion.Extensions;
using GitVersion.Git;
using GitVersion.Helpers;
@@ -94,12 +94,12 @@ public static bool IsReleaseBranch(this IGitVersionConfiguration configuration,
if (!configuration.RegularExpression.IsNullOrWhiteSpace() && !effectiveBranchName.IsNullOrEmpty())
{
effectiveBranchName = effectiveBranchName.RegexReplace("[^a-zA-Z0-9-_]", "-");
- var pattern = new Regex(configuration.RegularExpression, RegexOptions.IgnoreCase);
- var match = pattern.Match(effectiveBranchName);
+ var regex = RegexPatterns.Cache.GetOrAdd(configuration.RegularExpression);
+ var match = regex.Match(effectiveBranchName);
if (match.Success)
{
// ReSharper disable once LoopCanBeConvertedToQuery
- foreach (var groupName in pattern.GetGroupNames())
+ foreach (var groupName in regex.GetGroupNames())
{
label = label.Replace("{" + groupName + "}", match.Groups[groupName].Value);
}
@@ -111,7 +111,8 @@ public static bool IsReleaseBranch(this IGitVersionConfiguration configuration,
// Evaluate tag number pattern and append to prerelease tag, preserving build metadata
if (!configuration.LabelNumberPattern.IsNullOrEmpty() && !effectiveBranchName.IsNullOrEmpty())
{
- var match = Regex.Match(effectiveBranchName, configuration.LabelNumberPattern);
+ var regex = RegexPatterns.Cache.GetOrAdd(configuration.LabelNumberPattern);
+ var match = regex.Match(effectiveBranchName);
var numberGroup = match.Groups["number"];
if (numberGroup.Success)
{
diff --git a/src/GitVersion.Core/Extensions/DictionaryExtensions.cs b/src/GitVersion.Core/Extensions/DictionaryExtensions.cs
index 7a1ab3723c..4f5c670692 100644
--- a/src/GitVersion.Core/Extensions/DictionaryExtensions.cs
+++ b/src/GitVersion.Core/Extensions/DictionaryExtensions.cs
@@ -1,17 +1,27 @@
+using System.Collections.Concurrent;
+using System.Diagnostics.CodeAnalysis;
+using System.Text.RegularExpressions;
+
namespace GitVersion.Extensions;
public static class DictionaryExtensions
{
- public static TValue GetOrAdd(this IDictionary dict, TKey key, Func getValue)
+ public static TValue GetOrAdd(this Dictionary dict, TKey key, Func getValue) where TKey : notnull
{
- if (dict is null) throw new ArgumentNullException(nameof(dict));
- if (getValue is null) throw new ArgumentNullException(nameof(getValue));
+ ArgumentNullException.ThrowIfNull(dict);
+ ArgumentNullException.ThrowIfNull(getValue);
- if (!dict.TryGetValue(key, out var value))
- {
- value = getValue();
- dict.Add(key, value);
- }
+ if (dict.TryGetValue(key, out var value)) return value;
+ value = getValue();
+ dict.Add(key, value);
return value;
}
+
+ public static Regex GetOrAdd(this ConcurrentDictionary dict, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern)
+ {
+ ArgumentNullException.ThrowIfNull(dict);
+ ArgumentNullException.ThrowIfNull(pattern);
+
+ return dict.GetOrAdd(pattern, regex => new(regex, RegexOptions.IgnoreCase | RegexOptions.Compiled));
+ }
}
diff --git a/src/GitVersion.Core/Extensions/StringExtensions.cs b/src/GitVersion.Core/Extensions/StringExtensions.cs
index b45126b8c2..317fe51704 100644
--- a/src/GitVersion.Core/Extensions/StringExtensions.cs
+++ b/src/GitVersion.Core/Extensions/StringExtensions.cs
@@ -1,5 +1,5 @@
using System.Diagnostics.CodeAnalysis;
-using System.Text.RegularExpressions;
+using GitVersion.Core;
namespace GitVersion.Extensions;
@@ -11,7 +11,11 @@ public static void AppendLineFormat(this StringBuilder stringBuilder, string for
stringBuilder.AppendLine();
}
- public static string RegexReplace(this string input, string pattern, string replace, RegexOptions options = RegexOptions.None) => Regex.Replace(input, pattern, replace, options);
+ public static string RegexReplace(this string input, string pattern, string replace)
+ {
+ var regex = RegexPatterns.Cache.GetOrAdd(pattern);
+ return regex.Replace(input, replace);
+ }
public static bool IsEquivalentTo(this string self, string? other) =>
string.Equals(self, other, StringComparison.OrdinalIgnoreCase);
diff --git a/src/GitVersion.Core/Git/ReferenceName.cs b/src/GitVersion.Core/Git/ReferenceName.cs
index bb86f2d09e..5e38c3cc60 100644
--- a/src/GitVersion.Core/Git/ReferenceName.cs
+++ b/src/GitVersion.Core/Git/ReferenceName.cs
@@ -1,5 +1,4 @@
using System.Diagnostics.CodeAnalysis;
-using System.Text.RegularExpressions;
using GitVersion.Extensions;
using GitVersion.Helpers;
@@ -42,39 +41,33 @@ public static ReferenceName Parse(string canonicalName)
throw new ArgumentException($"The {nameof(canonicalName)} is not a Canonical name");
}
- public static bool TryParse([NotNullWhen(true)] out ReferenceName? value, string canonicalName)
- {
- value = null;
-
- if (IsPrefixedBy(canonicalName, LocalBranchPrefix)
- || IsPrefixedBy(canonicalName, RemoteTrackingBranchPrefix)
- || IsPrefixedBy(canonicalName, TagPrefix)
- || IsPrefixedBy(canonicalName, PullRequestPrefixes))
- {
- value = new(canonicalName);
- }
-
- return value is not null;
- }
-
public static ReferenceName FromBranchName(string branchName)
- {
- if (TryParse(out ReferenceName? value, branchName)) return value;
- return Parse(LocalBranchPrefix + branchName);
- }
+ => TryParse(out ReferenceName? value, branchName)
+ ? value
+ : Parse(LocalBranchPrefix + branchName);
public string Canonical { get; }
+
public string Friendly { get; }
+
public string WithoutOrigin { get; }
+
public bool IsLocalBranch { get; }
+
public bool IsRemoteBranch { get; }
+
public bool IsTag { get; }
+
public bool IsPullRequest { get; }
public bool Equals(ReferenceName? other) => equalityHelper.Equals(this, other);
+
public int CompareTo(ReferenceName? other) => comparerHelper.Compare(this, other);
+
public override bool Equals(object? obj) => Equals(obj as ReferenceName);
+
public override int GetHashCode() => equalityHelper.GetHashCode(this);
+
public override string ToString() => Friendly;
public static bool operator ==(ReferenceName? left, ReferenceName? right)
@@ -86,38 +79,6 @@ public static ReferenceName FromBranchName(string branchName)
public static bool operator !=(ReferenceName? left, ReferenceName? right) => !(left == right);
- public bool TryGetSemanticVersion(out (SemanticVersion Value, string? Name) result,
- Regex versionPatternRegex,
- string? tagPrefix,
- SemanticVersionFormat format)
- {
- result = default;
-
- int length = 0;
- foreach (var branchPart in WithoutOrigin.Split(GetBranchSeparator()))
- {
- if (string.IsNullOrEmpty(branchPart)) return false;
-
- var match = versionPatternRegex.NotNull().Match(branchPart);
- if (match.Success)
- {
- var versionPart = match.Groups["version"].Value;
- if (SemanticVersion.TryParse(versionPart, tagPrefix, out var semanticVersion, format))
- {
- length += versionPart.Length;
- var name = WithoutOrigin[length..].Trim('-');
- result = new(semanticVersion, name == string.Empty ? null : name);
- return true;
- }
- }
- length += branchPart.Length + 1;
- }
-
- return false;
- }
-
- private char GetBranchSeparator() => WithoutOrigin.Contains('/') || !WithoutOrigin.Contains('-') ? '/' : '-';
-
public bool EquivalentTo(string? name) =>
Canonical.Equals(name, StringComparison.OrdinalIgnoreCase)
|| Friendly.Equals(name, StringComparison.OrdinalIgnoreCase)
@@ -143,9 +104,25 @@ private string RemoveOrigin()
{
return Friendly[OriginPrefix.Length..];
}
+
return Friendly;
}
+ private static bool TryParse([NotNullWhen(true)] out ReferenceName? value, string canonicalName)
+ {
+ value = null;
+
+ if (IsPrefixedBy(canonicalName, LocalBranchPrefix)
+ || IsPrefixedBy(canonicalName, RemoteTrackingBranchPrefix)
+ || IsPrefixedBy(canonicalName, TagPrefix)
+ || IsPrefixedBy(canonicalName, PullRequestPrefixes))
+ {
+ value = new(canonicalName);
+ }
+
+ return value is not null;
+ }
+
private static bool IsPrefixedBy(string input, string prefix) => input.StartsWith(prefix, StringComparison.Ordinal);
private static bool IsPrefixedBy(string input, string[] prefixes) => prefixes.Any(prefix => IsPrefixedBy(input, prefix));
diff --git a/src/GitVersion.Core/MergeMessage.cs b/src/GitVersion.Core/MergeMessage.cs
index 036fb7c177..8d195f1b22 100644
--- a/src/GitVersion.Core/MergeMessage.cs
+++ b/src/GitVersion.Core/MergeMessage.cs
@@ -9,7 +9,7 @@ namespace GitVersion;
public class MergeMessage
{
- private static readonly IList DefaultFormats =
+ private static readonly IList<(string Name, Regex Pattern)> DefaultFormats =
[
new("Default", RegexPatterns.MergeMessage.DefaultMergeMessageRegex),
new("SmartGit", RegexPatterns.MergeMessage.SmartGitMergeMessageRegex),
@@ -25,21 +25,21 @@ public MergeMessage(string mergeMessage, IGitVersionConfiguration configuration)
{
mergeMessage.NotNull();
- if (mergeMessage == string.Empty) return;
+ if (mergeMessage.Length == 0) return;
// Concatenate configuration formats with the defaults.
// Ensure configurations are processed first.
var allFormats = configuration.MergeMessageFormats
- .Select(x => new MergeMessageFormat(x.Key, new(x.Value, RegexOptions.IgnoreCase | RegexOptions.Compiled)))
+ .Select(x => (Name: x.Key, Pattern: RegexPatterns.Cache.GetOrAdd(x.Value)))
.Concat(DefaultFormats);
- foreach (var format in allFormats)
+ foreach (var (Name, Pattern) in allFormats)
{
- var match = format.Pattern.Match(mergeMessage);
+ var match = Pattern.Match(mergeMessage);
if (!match.Success)
continue;
- FormatName = format.Name;
+ FormatName = Name;
var sourceBranch = match.Groups["SourceBranch"].Value;
MergedBranch = GetMergedBranchName(sourceBranch);
@@ -53,9 +53,7 @@ public MergeMessage(string mergeMessage, IGitVersionConfiguration configuration)
PullRequestNumber = pullNumber;
}
- Version = ParseVersion(
- configuration.VersionInBranchRegex, configuration.TagPrefix, configuration.SemanticVersionFormat
- );
+ Version = MergedBranch?.TryGetSemanticVersion(out var result, configuration) == true ? result.Value : null;
break;
}
@@ -69,20 +67,6 @@ public MergeMessage(string mergeMessage, IGitVersionConfiguration configuration)
public int? PullRequestNumber { get; }
public SemanticVersion? Version { get; }
- private SemanticVersion? ParseVersion(Regex versionInBranchRegex, string? tagPrefix, SemanticVersionFormat format)
- {
- if (MergedBranch?.TryGetSemanticVersion(out var result, versionInBranchRegex, tagPrefix, format) == true)
- return result.Value;
- return null;
- }
-
- private class MergeMessageFormat(string name, Regex pattern)
- {
- public string Name { get; } = name;
-
- public Regex Pattern { get; } = pattern;
- }
-
private ReferenceName GetMergedBranchName(string mergedBranch)
{
if (FormatName == "RemoteTracking" && !mergedBranch.StartsWith(ReferenceName.RemoteTrackingBranchPrefix))
@@ -106,7 +90,7 @@ public static bool TryParse(
if (isValidMergeCommit)
{
- mergeMessage = new(mergeCommit.Message, configuration);
+ mergeMessage = new MergeMessage(mergeCommit.Message, configuration);
}
return isValidMergeCommit;
diff --git a/src/GitVersion.Core/Polyfills/StringSyntaxAttribute.cs b/src/GitVersion.Core/Polyfills/StringSyntaxAttribute.cs
new file mode 100644
index 0000000000..f3faee9ed6
--- /dev/null
+++ b/src/GitVersion.Core/Polyfills/StringSyntaxAttribute.cs
@@ -0,0 +1,35 @@
+#if !NET7_0_OR_GREATER
+
+// The namespace is important
+namespace System.Diagnostics.CodeAnalysis;
+
+/// Fake version of the StringSyntaxAttribute, which was introduced in .NET 7
+[SuppressMessage("ApiDesign", "RS0016:Add public types and members to the declared API")]
+[SuppressMessage("Style", "IDE0060:Remove unused parameter")]
+[AttributeUsage(AttributeTargets.All)]
+public sealed class StringSyntaxAttribute : Attribute
+{
+ /// The syntax identifier for strings containing composite formats.
+ public const string CompositeFormat = nameof(CompositeFormat);
+
+ /// The syntax identifier for strings containing regular expressions.
+ public const string Regex = nameof(Regex);
+
+ /// The syntax identifier for strings containing date information.
+ public const string DateTimeFormat = nameof(DateTimeFormat);
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public StringSyntaxAttribute(string syntax)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public StringSyntaxAttribute(string syntax, params object?[] arguments)
+ {
+ }
+}
+#endif
diff --git a/src/GitVersion.Core/PublicAPI.Shipped.txt b/src/GitVersion.Core/PublicAPI.Shipped.txt
index e68731b648..143462941c 100644
--- a/src/GitVersion.Core/PublicAPI.Shipped.txt
+++ b/src/GitVersion.Core/PublicAPI.Shipped.txt
@@ -86,7 +86,6 @@ GitVersion.Configuration.EffectiveConfiguration.TrackMergeTarget.get -> bool
GitVersion.Configuration.EffectiveConfiguration.TracksReleaseBranches.get -> bool
GitVersion.Configuration.EffectiveConfiguration.UpdateBuildNumber.get -> bool
GitVersion.Configuration.EffectiveConfiguration.VersionFilters.get -> System.Collections.Generic.IEnumerable!
-GitVersion.Configuration.EffectiveConfiguration.VersionInBranchRegex.get -> System.Text.RegularExpressions.Regex!
GitVersion.Configuration.EffectiveConfiguration.VersionStrategy.get -> GitVersion.VersionCalculation.VersionStrategies
GitVersion.Configuration.IBranchConfiguration
GitVersion.Configuration.IBranchConfiguration.CommitMessageIncrementing.get -> GitVersion.VersionCalculation.CommitMessageIncrementMode?
@@ -132,11 +131,9 @@ GitVersion.Configuration.IGitVersionConfiguration.NextVersion.get -> string?
GitVersion.Configuration.IGitVersionConfiguration.NoBumpMessage.get -> string?
GitVersion.Configuration.IGitVersionConfiguration.PatchVersionBumpMessage.get -> string?
GitVersion.Configuration.IGitVersionConfiguration.SemanticVersionFormat.get -> GitVersion.SemanticVersionFormat
-GitVersion.Configuration.IGitVersionConfiguration.TagPrefix.get -> string?
GitVersion.Configuration.IGitVersionConfiguration.TagPreReleaseWeight.get -> int?
GitVersion.Configuration.IGitVersionConfiguration.UpdateBuildNumber.get -> bool
GitVersion.Configuration.IGitVersionConfiguration.VersionInBranchPattern.get -> string?
-GitVersion.Configuration.IGitVersionConfiguration.VersionInBranchRegex.get -> System.Text.RegularExpressions.Regex!
GitVersion.Configuration.IGitVersionConfiguration.VersionStrategy.get -> GitVersion.VersionCalculation.VersionStrategies
GitVersion.Configuration.IGitVersionConfiguration.Workflow.get -> string?
GitVersion.Configuration.IIgnoreConfiguration
@@ -287,7 +284,6 @@ GitVersion.Git.ReferenceName.IsPullRequest.get -> bool
GitVersion.Git.ReferenceName.IsRemoteBranch.get -> bool
GitVersion.Git.ReferenceName.IsTag.get -> bool
GitVersion.Git.ReferenceName.ReferenceName(string! canonical) -> void
-GitVersion.Git.ReferenceName.TryGetSemanticVersion(out (GitVersion.SemanticVersion! Value, string? Name) result, System.Text.RegularExpressions.Regex! versionPatternRegex, string? tagPrefix, GitVersion.SemanticVersionFormat format) -> bool
GitVersion.Git.ReferenceName.WithoutOrigin.get -> string!
GitVersion.Git.RefSpecDirection
GitVersion.Git.RefSpecDirection.Fetch = 0 -> GitVersion.Git.RefSpecDirection
@@ -675,7 +671,6 @@ GitVersion.VersionCalculation.IEffectiveBranchConfigurationFinder.GetConfigurati
GitVersion.VersionCalculation.IIncrementStrategyFinder
GitVersion.VersionCalculation.IIncrementStrategyFinder.DetermineIncrementedField(GitVersion.Git.ICommit! currentCommit, GitVersion.Git.ICommit? baseVersionSource, bool shouldIncrement, GitVersion.Configuration.EffectiveConfiguration! configuration, string? label) -> GitVersion.VersionField
GitVersion.VersionCalculation.IIncrementStrategyFinder.GetIncrementForcedByCommit(GitVersion.Git.ICommit! commit, GitVersion.Configuration.IGitVersionConfiguration! configuration) -> GitVersion.VersionField
-GitVersion.VersionCalculation.IIncrementStrategyFinder.GetIncrementForCommits(string? majorVersionBumpMessage, string? minorVersionBumpMessage, string? patchVersionBumpMessage, string? noBumpMessage, GitVersion.Git.ICommit![]! commits) -> GitVersion.VersionField?
GitVersion.VersionCalculation.IIncrementStrategyFinder.GetMergedCommits(GitVersion.Git.ICommit! mergeCommit, int index, GitVersion.Configuration.IIgnoreConfiguration! ignore) -> System.Collections.Generic.IEnumerable!
GitVersion.VersionCalculation.INextVersionCalculator
GitVersion.VersionCalculation.INextVersionCalculator.FindVersion() -> GitVersion.SemanticVersion!
@@ -742,13 +737,11 @@ override GitVersion.VersionCalculation.NextVersion.Equals(object? other) -> bool
override GitVersion.VersionCalculation.NextVersion.GetHashCode() -> int
override GitVersion.VersionCalculation.NextVersion.ToString() -> string!
static GitVersion.Configuration.ReferenceNameExtensions.TryGetSemanticVersion(this GitVersion.Git.ReferenceName! source, out (GitVersion.SemanticVersion! Value, string? Name) result, GitVersion.Configuration.EffectiveConfiguration! configuration) -> bool
-static GitVersion.Configuration.ReferenceNameExtensions.TryGetSemanticVersion(this GitVersion.Git.ReferenceName! source, out (GitVersion.SemanticVersion! Value, string? Name) result, GitVersion.Configuration.IGitVersionConfiguration! configuration) -> bool
static GitVersion.Extensions.AssemblyVersionsGeneratorExtensions.GetAssemblyFileVersion(this GitVersion.SemanticVersion! sv, GitVersion.Configuration.AssemblyFileVersioningScheme scheme) -> string?
static GitVersion.Extensions.AssemblyVersionsGeneratorExtensions.GetAssemblyVersion(this GitVersion.SemanticVersion! sv, GitVersion.Configuration.AssemblyVersioningScheme scheme) -> string?
static GitVersion.Extensions.CommonExtensions.NotNull(this T? value, string! name = "") -> T!
static GitVersion.Extensions.CommonExtensions.NotNullOrEmpty(this string? value, string! name = "") -> string!
static GitVersion.Extensions.CommonExtensions.NotNullOrWhitespace(this string? value, string! name = "") -> string!
-static GitVersion.Extensions.DictionaryExtensions.GetOrAdd(this System.Collections.Generic.IDictionary! dict, TKey key, System.Func! getValue) -> TValue
static GitVersion.Extensions.EnumerableExtensions.AddRange(this System.Collections.Generic.ICollection! source, System.Collections.Generic.IEnumerable! items) -> void
static GitVersion.Extensions.EnumerableExtensions.OnlyOrDefault(this System.Collections.Generic.IEnumerable! source) -> T?
static GitVersion.Extensions.EnumerableExtensions.SingleOfType(this System.Collections.IEnumerable! source) -> T
@@ -764,7 +757,6 @@ static GitVersion.Extensions.StringExtensions.IsEmpty(this string? value) -> boo
static GitVersion.Extensions.StringExtensions.IsEquivalentTo(this string! self, string? other) -> bool
static GitVersion.Extensions.StringExtensions.IsNullOrEmpty(this string? value) -> bool
static GitVersion.Extensions.StringExtensions.IsNullOrWhiteSpace(this string? value) -> bool
-static GitVersion.Extensions.StringExtensions.RegexReplace(this string! input, string! pattern, string! replace, System.Text.RegularExpressions.RegexOptions options = System.Text.RegularExpressions.RegexOptions.None) -> string!
static GitVersion.Extensions.StringExtensions.WithPrefixIfNotNullOrEmpty(this string! value, string! prefix) -> string!
static GitVersion.Git.BranchCommit.operator !=(GitVersion.Git.BranchCommit left, GitVersion.Git.BranchCommit right) -> bool
static GitVersion.Git.BranchCommit.operator ==(GitVersion.Git.BranchCommit left, GitVersion.Git.BranchCommit right) -> bool
@@ -773,7 +765,6 @@ static GitVersion.Git.ReferenceName.FromBranchName(string! branchName) -> GitVer
static GitVersion.Git.ReferenceName.operator !=(GitVersion.Git.ReferenceName? left, GitVersion.Git.ReferenceName? right) -> bool
static GitVersion.Git.ReferenceName.operator ==(GitVersion.Git.ReferenceName? left, GitVersion.Git.ReferenceName? right) -> bool
static GitVersion.Git.ReferenceName.Parse(string! canonicalName) -> GitVersion.Git.ReferenceName!
-static GitVersion.Git.ReferenceName.TryParse(out GitVersion.Git.ReferenceName? value, string! canonicalName) -> bool
static GitVersion.Helpers.Disposable.Create(System.Action! disposer) -> System.IDisposable!
static GitVersion.Helpers.Disposable.Create(T value, System.Action! disposer) -> GitVersion.Helpers.IDisposable!
static GitVersion.Helpers.EncodingHelper.DetectEncoding(string? filename) -> System.Text.Encoding?
diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt
index 7dc5c58110..439fac159f 100644
--- a/src/GitVersion.Core/PublicAPI.Unshipped.txt
+++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt
@@ -1 +1,7 @@
#nullable enable
+GitVersion.Configuration.EffectiveConfiguration.VersionInBranchPattern.get -> string?
+GitVersion.Configuration.IGitVersionConfiguration.TagPrefixPattern.get -> string?
+static GitVersion.Configuration.ReferenceNameExtensions.TryGetSemanticVersion(this GitVersion.Git.ReferenceName! source, out (GitVersion.SemanticVersion! Value, string? Name) result, GitVersion.Configuration.IGitVersionConfiguration! configuration) -> bool
+static GitVersion.Extensions.DictionaryExtensions.GetOrAdd(this System.Collections.Concurrent.ConcurrentDictionary! dict, string! pattern) -> System.Text.RegularExpressions.Regex!
+static GitVersion.Extensions.DictionaryExtensions.GetOrAdd(this System.Collections.Generic.Dictionary! dict, TKey key, System.Func! getValue) -> TValue
+static GitVersion.Extensions.StringExtensions.RegexReplace(this string! input, string! pattern, string! replace) -> string!
diff --git a/src/GitVersion.Core/SemVer/SemanticVersion.cs b/src/GitVersion.Core/SemVer/SemanticVersion.cs
index beeb96321c..866bffe6af 100644
--- a/src/GitVersion.Core/SemVer/SemanticVersion.cs
+++ b/src/GitVersion.Core/SemVer/SemanticVersion.cs
@@ -1,6 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
-using System.Text.RegularExpressions;
using GitVersion.Core;
using GitVersion.Extensions;
@@ -76,18 +75,7 @@ public override bool Equals(object? obj)
return obj.GetType() == GetType() && Equals((SemanticVersion)obj);
}
- public override int GetHashCode()
- {
- unchecked
- {
- var hashCode = this.Major.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Minor.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Patch.GetHashCode();
- hashCode = (hashCode * 397) ^ this.PreReleaseTag.GetHashCode();
- hashCode = (hashCode * 397) ^ this.BuildMetaData.GetHashCode();
- return hashCode;
- }
- }
+ public override int GetHashCode() => HashCode.Combine(Major, Minor, Patch, PreReleaseTag, BuildMetaData);
public static bool operator ==(SemanticVersion? v1, SemanticVersion? v2)
{
@@ -102,40 +90,32 @@ public override int GetHashCode()
public static bool operator >(SemanticVersion v1, SemanticVersion v2)
{
- if (v1 == null)
- throw new ArgumentNullException(nameof(v1));
- if (v2 == null)
- throw new ArgumentNullException(nameof(v2));
+ ArgumentNullException.ThrowIfNull(v1);
+ ArgumentNullException.ThrowIfNull(v2);
return v1.CompareTo(v2) > 0;
}
public static bool operator >=(SemanticVersion v1, SemanticVersion v2)
{
- if (v1 == null)
- throw new ArgumentNullException(nameof(v1));
- if (v2 == null)
- throw new ArgumentNullException(nameof(v2));
+ ArgumentNullException.ThrowIfNull(v1);
+ ArgumentNullException.ThrowIfNull(v2);
return v1.CompareTo(v2) >= 0;
}
public static bool operator <=(SemanticVersion v1, SemanticVersion v2)
{
- if (v1 == null)
- throw new ArgumentNullException(nameof(v1));
- if (v2 == null)
- throw new ArgumentNullException(nameof(v2));
+ ArgumentNullException.ThrowIfNull(v1);
+ ArgumentNullException.ThrowIfNull(v2);
return v1.CompareTo(v2) <= 0;
}
public static bool operator <(SemanticVersion v1, SemanticVersion v2)
{
- if (v1 == null)
- throw new ArgumentNullException(nameof(v1));
- if (v2 == null)
- throw new ArgumentNullException(nameof(v2));
+ ArgumentNullException.ThrowIfNull(v1);
+ ArgumentNullException.ThrowIfNull(v2);
return v1.CompareTo(v2) < 0;
}
@@ -152,7 +132,8 @@ public static SemanticVersion Parse(
public static bool TryParse(string version, string? tagPrefixRegex,
[NotNullWhen(true)] out SemanticVersion? semanticVersion, SemanticVersionFormat format = SemanticVersionFormat.Strict)
{
- var match = Regex.Match(version, $"^({tagPrefixRegex})(?.*)$");
+ var regex = RegexPatterns.Cache.GetOrAdd($"^({tagPrefixRegex})(?.*)$");
+ var match = regex.Match(version);
if (!match.Success)
{
diff --git a/src/GitVersion.Core/VersionCalculation/Abstractions/IIncrementStrategyFinder.cs b/src/GitVersion.Core/VersionCalculation/Abstractions/IIncrementStrategyFinder.cs
index 5bd1ce41eb..6331be284d 100644
--- a/src/GitVersion.Core/VersionCalculation/Abstractions/IIncrementStrategyFinder.cs
+++ b/src/GitVersion.Core/VersionCalculation/Abstractions/IIncrementStrategyFinder.cs
@@ -8,11 +8,6 @@ public interface IIncrementStrategyFinder
VersionField DetermineIncrementedField(
ICommit currentCommit, ICommit? baseVersionSource, bool shouldIncrement, EffectiveConfiguration configuration, string? label);
- VersionField? GetIncrementForCommits(
- string? majorVersionBumpMessage, string? minorVersionBumpMessage, string? patchVersionBumpMessage, string? noBumpMessage,
- ICommit[] commits
- );
-
IEnumerable GetMergedCommits(ICommit mergeCommit, int index, IIgnoreConfiguration ignore);
VersionField GetIncrementForcedByCommit(ICommit commit, IGitVersionConfiguration configuration);
diff --git a/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs b/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs
index 957974df4a..26ebccda50 100644
--- a/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs
+++ b/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs
@@ -1,4 +1,3 @@
-using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using GitVersion.Configuration;
using GitVersion.Core;
@@ -10,7 +9,6 @@ namespace GitVersion.VersionCalculation;
internal class IncrementStrategyFinder(IGitRepository repository, ITaggedSemanticVersionRepository taggedSemanticVersionRepository)
: IIncrementStrategyFinder
{
- private static readonly ConcurrentDictionary CompiledRegexCache = new();
private readonly Dictionary commitIncrementCache = [];
private readonly Dictionary> headCommitsMapCache = [];
private readonly Dictionary headCommitsCache = [];
@@ -44,18 +42,17 @@ public VersionField DetermineIncrementedField(
return commitMessageIncrement.Value;
}
- public VersionField? GetIncrementForCommits(string? majorVersionBumpMessage, string? minorVersionBumpMessage,
- string? patchVersionBumpMessage, string? noBumpMessage, ICommit[] commits)
+ private VersionField? GetIncrementForCommits(EffectiveConfiguration configuration, ICommit[] commits)
{
commits.NotNull();
- var majorRegex = TryGetRegexOrDefault(majorVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultMajorPatternRegex);
- var minorRegex = TryGetRegexOrDefault(minorVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultMinorPatternRegex);
- var patchRegex = TryGetRegexOrDefault(patchVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultPatchPatternRegex);
- var none = TryGetRegexOrDefault(noBumpMessage, RegexPatterns.VersionCalculation.DefaultNoBumpPatternRegex);
+ var majorRegex = TryGetRegexOrDefault(configuration.MajorVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultMajorRegex);
+ var minorRegex = TryGetRegexOrDefault(configuration.MinorVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultMinorRegex);
+ var patchRegex = TryGetRegexOrDefault(configuration.PatchVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultPatchRegex);
+ var noBumpRegex = TryGetRegexOrDefault(configuration.NoBumpMessage, RegexPatterns.VersionCalculation.DefaultNoBumpRegex);
var increments = commits
- .Select(c => GetIncrementFromCommit(c, majorRegex, minorRegex, patchRegex, none))
+ .Select(c => GetIncrementFromCommit(c, majorRegex, minorRegex, patchRegex, noBumpRegex))
.Where(v => v != null)
.ToList();
@@ -86,11 +83,7 @@ public VersionField DetermineIncrementedField(
commits = commits.Where(c => c.Parents.Count > 1);
}
- return GetIncrementForCommits(
- majorVersionBumpMessage: configuration.MajorVersionBumpMessage,
- minorVersionBumpMessage: configuration.MinorVersionBumpMessage,
- patchVersionBumpMessage: configuration.PatchVersionBumpMessage,
- noBumpMessage: configuration.NoBumpMessage,
+ return GetIncrementForCommits(configuration,
commits: commits.ToArray()
);
}
@@ -98,7 +91,7 @@ public VersionField DetermineIncrementedField(
private static Regex TryGetRegexOrDefault(string? messageRegex, Regex defaultRegex) =>
messageRegex == null
? defaultRegex
- : CompiledRegexCache.GetOrAdd(messageRegex, pattern => new(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase));
+ : RegexPatterns.Cache.GetOrAdd(messageRegex);
private IReadOnlyCollection GetCommitHistory(string? tagPrefix, SemanticVersionFormat semanticVersionFormat,
ICommit? baseVersionSource, ICommit currentCommit, string? label, IIgnoreConfiguration ignore)
@@ -175,13 +168,13 @@ private ICommit[] GetHeadCommits(ICommit? headCommit, IIgnoreConfiguration ignor
this.headCommitsCache.GetOrAdd(headCommit?.Sha ?? "NULL", () =>
GetCommitsReacheableFromHead(headCommit, ignore).ToArray());
- private VersionField? GetIncrementFromCommit(ICommit commit, Regex majorRegex, Regex minorRegex, Regex patchRegex, Regex none) =>
+ private VersionField? GetIncrementFromCommit(ICommit commit, Regex majorRegex, Regex minorRegex, Regex patchRegex, Regex noBumpRegex) =>
this.commitIncrementCache.GetOrAdd(commit.Sha, () =>
- GetIncrementFromMessage(commit.Message, majorRegex, minorRegex, patchRegex, none));
+ GetIncrementFromMessage(commit.Message, majorRegex, minorRegex, patchRegex, noBumpRegex));
- private static VersionField? GetIncrementFromMessage(string message, Regex majorRegex, Regex minorRegex, Regex patchRegex, Regex none)
+ private static VersionField? GetIncrementFromMessage(string message, Regex majorRegex, Regex minorRegex, Regex patchRegex, Regex noBumpRegex)
{
- if (none.IsMatch(message)) return VersionField.None;
+ if (noBumpRegex.IsMatch(message)) return VersionField.None;
if (majorRegex.IsMatch(message)) return VersionField.Major;
if (minorRegex.IsMatch(message)) return VersionField.Minor;
if (patchRegex.IsMatch(message)) return VersionField.Patch;
@@ -232,10 +225,10 @@ public VersionField GetIncrementForcedByCommit(ICommit commit, IGitVersionConfig
commit.NotNull();
configuration.NotNull();
- var majorRegex = TryGetRegexOrDefault(configuration.MajorVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultMajorPatternRegex);
- var minorRegex = TryGetRegexOrDefault(configuration.MinorVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultMinorPatternRegex);
- var patchRegex = TryGetRegexOrDefault(configuration.PatchVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultPatchPatternRegex);
- var none = TryGetRegexOrDefault(configuration.NoBumpMessage, RegexPatterns.VersionCalculation.DefaultNoBumpPatternRegex);
+ var majorRegex = TryGetRegexOrDefault(configuration.MajorVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultMajorRegex);
+ var minorRegex = TryGetRegexOrDefault(configuration.MinorVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultMinorRegex);
+ var patchRegex = TryGetRegexOrDefault(configuration.PatchVersionBumpMessage, RegexPatterns.VersionCalculation.DefaultPatchRegex);
+ var none = TryGetRegexOrDefault(configuration.NoBumpMessage, RegexPatterns.VersionCalculation.DefaultNoBumpRegex);
return GetIncrementFromCommit(commit, majorRegex, minorRegex, patchRegex, none) ?? VersionField.None;
}
diff --git a/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs b/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs
index 41e16691e5..5111804989 100644
--- a/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs
+++ b/src/GitVersion.Core/VersionCalculation/VersionCalculators/NextVersionCalculator.cs
@@ -79,7 +79,7 @@ public virtual SemanticVersion FindVersion()
var ignore = Context.Configuration.Ignore;
var alternativeSemanticVersion = taggedSemanticVersionService.GetTaggedSemanticVersionsOfBranch(
branch: nextVersion.BranchConfiguration.Branch,
- tagPrefix: Context.Configuration.TagPrefix,
+ tagPrefix: Context.Configuration.TagPrefixPattern,
format: Context.Configuration.SemanticVersionFormat,
ignore: Context.Configuration.Ignore,
notOlderThan: Context.CurrentCommit.When
diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/ConfiguredNextVersionVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/ConfiguredNextVersionVersionStrategy.cs
index 1fa219988c..87645553ca 100644
--- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/ConfiguredNextVersionVersionStrategy.cs
+++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/ConfiguredNextVersionVersionStrategy.cs
@@ -25,7 +25,7 @@ public IEnumerable GetBaseVersions(EffectiveBranchConfiguration con
if (!nextVersion.IsNullOrEmpty())
{
var semanticVersion = SemanticVersion.Parse(
- nextVersion, Context.Configuration.TagPrefix, Context.Configuration.SemanticVersionFormat
+ nextVersion, Context.Configuration.TagPrefixPattern, Context.Configuration.SemanticVersionFormat
);
var label = configuration.Value.GetBranchSpecificLabel(Context.CurrentBranch.Name, null);
diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/VersionInBranchNameVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/VersionInBranchNameVersionStrategy.cs
index 8c6af0f781..cd6880601d 100644
--- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/VersionInBranchNameVersionStrategy.cs
+++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/VersionInBranchNameVersionStrategy.cs
@@ -35,8 +35,7 @@ public bool TryGetBaseVersion(EffectiveBranchConfiguration configuration, [NotNu
foreach (var branch in new[] { Context.CurrentBranch, configuration.Branch })
{
- if (branch.Name.TryGetSemanticVersion(out var result, configuration.Value.VersionInBranchRegex,
- configuration.Value.TagPrefix, configuration.Value.SemanticVersionFormat))
+ if (branch.Name.TryGetSemanticVersion(out var result, configuration.Value))
{
string? branchNameOverride = null;
if (!result.Name.IsNullOrEmpty() && (Context.CurrentBranch.Name.Equals(branch.Name)
diff --git a/src/GitVersion.MsBuild.Tests/InvalidFileCheckerTests.cs b/src/GitVersion.MsBuild.Tests/InvalidFileCheckerTests.cs
index 12b6315a1e..5eb2c3f2f9 100644
--- a/src/GitVersion.MsBuild.Tests/InvalidFileCheckerTests.cs
+++ b/src/GitVersion.MsBuild.Tests/InvalidFileCheckerTests.cs
@@ -1,7 +1,6 @@
using GitVersion.Core.Tests.Helpers;
using GitVersion.Helpers;
using GitVersion.MsBuild.Tests.Mocks;
-using Microsoft.Build.Framework;
namespace GitVersion.MsBuild.Tests;
@@ -30,15 +29,17 @@ public void VerifyIgnoreNonAssemblyInfoFile()
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "SomeOtherFile.cs")))
{
- writer.Write(@"
-using System;
-using System.Reflection;
+ writer.Write("""
-[assembly: AssemblyVersion(""1.0.0.0"")]
-");
+ using System;
+ using System.Reflection;
+
+ [assembly: AssemblyVersion("1.0.0.0")]
+
+ """);
}
- FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "SomeOtherFile.cs" } }, this.projectFile);
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "SomeOtherFile.cs" }], this.projectFile);
}
[Test]
@@ -46,15 +47,17 @@ public void VerifyAttributeFoundCSharp([Values("AssemblyVersion", "AssemblyFileV
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.cs")))
{
- writer.Write(@"
-using System;
-using System.Reflection;
+ writer.Write("""
+
+ using System;
+ using System.Reflection;
-[assembly:{0}(""1.0.0.0"")]
-", attribute);
+ [assembly:{0}("1.0.0.0")]
+
+ """, attribute);
}
- var ex = Assert.Throws(() => FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.cs" } }, this.projectFile), attribute);
+ var ex = Assert.Throws(() => FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.cs" }], this.projectFile), attribute);
ex.ShouldNotBeNull();
Assert.That(ex.Message, Is.EqualTo("File contains assembly version attributes which conflict with the attributes generated by GitVersion AssemblyInfo.cs"));
}
@@ -64,16 +67,18 @@ public void VerifyUnformattedAttributeFoundCSharp([Values("AssemblyVersion", "As
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.cs")))
{
- writer.Write(@"
-using System;
-using System.Reflection;
+ writer.Write("""
+
+ using System;
+ using System.Reflection;
+
+ [ assembly :
+ {0} ( "1.0.0.0")]
-[ assembly :
-{0} ( ""1.0.0.0"")]
-", attribute);
+ """, attribute);
}
- var ex = Assert.Throws(() => FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.cs" } }, this.projectFile), attribute);
+ var ex = Assert.Throws(() => FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.cs" }], this.projectFile), attribute);
ex.ShouldNotBeNull();
Assert.That(ex.Message, Is.EqualTo("File contains assembly version attributes which conflict with the attributes generated by GitVersion AssemblyInfo.cs"));
}
@@ -83,15 +88,17 @@ public void VerifyCommentWorksCSharp([Values("AssemblyVersion", "AssemblyFileVer
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.cs")))
{
- writer.Write(@"
-using System;
-using System.Reflection;
+ writer.Write("""
-//[assembly: {0}(""1.0.0.0"")]
-", attribute);
+ using System;
+ using System.Reflection;
+
+ //[assembly: {0}("1.0.0.0")]
+
+ """, attribute);
}
- FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.cs" } }, this.projectFile);
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.cs" }], this.projectFile);
}
[Test]
@@ -99,14 +106,16 @@ public void VerifyCommentWithNoNewLineAtEndWorksCSharp([Values("AssemblyVersion"
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.cs")))
{
- writer.Write(@"
-using System;
-using System.Reflection;
+ writer.Write("""
+
+ using System;
+ using System.Reflection;
-//[assembly: {0}(""1.0.0.0"")]", attribute);
+ //[assembly: {0}("1.0.0.0")]
+ """, attribute);
}
- FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.cs" } }, this.projectFile);
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.cs" }], this.projectFile);
}
[Test]
@@ -114,18 +123,20 @@ public void VerifyStringWorksCSharp([Values("AssemblyVersion", "AssemblyFileVers
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.cs")))
{
- writer.Write(@"
-using System;
-using System.Reflection;
+ writer.Write("""
+
+ using System;
+ using System.Reflection;
+
+ public class Temp
+ {{
+ static const string Foo = "[assembly: {0}(""1.0.0.0"")]";
+ }}
-public class Temp
-{{
- static const string Foo = ""[assembly: {0}(""""1.0.0.0"""")]"";
-}}
-", attribute);
+ """, attribute);
}
- FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.cs" } }, this.projectFile);
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.cs" }], this.projectFile);
}
[Test]
@@ -133,17 +144,19 @@ public void VerifyIdentifierWorksCSharp([Values("AssemblyVersion", "AssemblyFile
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.cs")))
{
- writer.Write(@"
-using System;
-using System.Reflection;
+ writer.Write("""
-public class {0}
-{{
-}}
-", attribute);
+ using System;
+ using System.Reflection;
+
+ public class {0}
+ {{
+ }}
+
+ """, attribute);
}
- FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.cs" } }, this.projectFile);
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.cs" }], this.projectFile);
}
[Test]
@@ -151,15 +164,17 @@ public void VerifyAttributeFoundVisualBasic([Values("AssemblyVersion", "Assembly
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.vb")))
{
- writer.Write(@"
-Imports System
-Imports System.Reflection
+ writer.Write("""
+
+ Imports System
+ Imports System.Reflection
-
-", attribute);
+
+
+ """, attribute);
}
- var ex = Assert.Throws(() => FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.vb" } }, this.projectFile), attribute);
+ var ex = Assert.Throws(() => FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.vb" }], this.projectFile), attribute);
ex.ShouldNotBeNull();
Assert.That(ex.Message, Is.EqualTo("File contains assembly version attributes which conflict with the attributes generated by GitVersion AssemblyInfo.vb"));
}
@@ -169,16 +184,18 @@ public void VerifyUnformattedAttributeFoundVisualBasic([Values("AssemblyVersion"
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.vb")))
{
- writer.Write(@"
-Imports System
-Imports System.Reflection
+ writer.Write("""
+
+ Imports System
+ Imports System.Reflection
+
+ < Assembly :
+ {0} ( "1.0.0.0")>
-< Assembly :
-{0} ( ""1.0.0.0"")>
-", attribute);
+ """, attribute);
}
- var ex = Assert.Throws(() => FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.vb" } }, this.projectFile), attribute);
+ var ex = Assert.Throws(() => FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.vb" }], this.projectFile), attribute);
ex.ShouldNotBeNull();
Assert.That(ex.Message, Is.EqualTo("File contains assembly version attributes which conflict with the attributes generated by GitVersion AssemblyInfo.vb"));
}
@@ -188,15 +205,17 @@ public void VerifyCommentWorksVisualBasic([Values("AssemblyVersion", "AssemblyFi
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.vb")))
{
- writer.Write(@"
-Imports System
-Imports System.Reflection
+ writer.Write("""
-'
-", attribute);
+ Imports System
+ Imports System.Reflection
+
+ '
+
+ """, attribute);
}
- FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.vb" } }, this.projectFile);
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.vb" }], this.projectFile);
}
[Test]
@@ -204,14 +223,16 @@ public void VerifyCommentWithNoNewLineAtEndWorksVisualBasic([Values("AssemblyVer
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.vb")))
{
- writer.Write(@"
-Imports System
-Imports System.Reflection
+ writer.Write("""
+
+ Imports System
+ Imports System.Reflection
-'", attribute);
+ '
+ """, attribute);
}
- FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.vb" } }, this.projectFile);
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.vb" }], this.projectFile);
}
[Test]
@@ -219,17 +240,19 @@ public void VerifyStringWorksVisualBasic([Values("AssemblyVersion", "AssemblyFil
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.vb")))
{
- writer.Write(@"
-Imports System
-Imports System.Reflection
+ writer.Write("""
+
+ Imports System
+ Imports System.Reflection
+
+ Public Class Temp
+ static const string Foo = "";
+ End Class
-Public Class Temp
- static const string Foo = """";
-End Class
-", attribute);
+ """, attribute);
}
- FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.vb" } }, this.projectFile);
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.vb" }], this.projectFile);
}
[Test]
@@ -237,15 +260,130 @@ public void VerifyIdentifierWorksVisualBasic([Values("AssemblyVersion", "Assembl
{
using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.vb")))
{
- writer.Write(@"
-Imports System
-Imports System.Reflection
+ writer.Write("""
+
+ Imports System
+ Imports System.Reflection
+
+ Public Class {0}
+ End Class
+
+ """, attribute);
+ }
+
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.vb" }], this.projectFile);
+ }
+
+ [Test]
+ public void VerifyAttributeFoundFSharp([Values("AssemblyVersion", "AssemblyFileVersion", "AssemblyInformationalVersion", "System.Reflection.AssemblyVersion")] string attribute)
+ {
+ using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.fs")))
+ {
+ writer.Write("""
+
+ open System
+ open System.Reflection
+
+ []
+
+ """, attribute);
+ }
+
+ var ex = Assert.Throws(() => FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.fs" }], this.projectFile), attribute);
+ ex.ShouldNotBeNull();
+ Assert.That(ex.Message, Is.EqualTo("File contains assembly version attributes which conflict with the attributes generated by GitVersion AssemblyInfo.fs"));
+ }
+
+ [Test]
+ public void VerifyUnformattedAttributeFoundFSharp([Values("AssemblyVersion", "AssemblyFileVersion", "AssemblyInformationalVersion", "System . Reflection . AssemblyVersion")] string attribute)
+ {
+ using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.fs")))
+ {
+ writer.Write("""
+
+ open System
+ open System.Reflection
+
+ [< assembly :
+ {0} ( "1.0.0.0")>]
+
+ """, attribute);
+ }
+
+ var ex = Assert.Throws(() => FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.fs" }], this.projectFile), attribute);
+ ex.ShouldNotBeNull();
+ Assert.That(ex.Message, Is.EqualTo("File contains assembly version attributes which conflict with the attributes generated by GitVersion AssemblyInfo.fs"));
+ }
+
+ [Test]
+ public void VerifyCommentWorksFSharp([Values("AssemblyVersion", "AssemblyFileVersion", "AssemblyInformationalVersion")] string attribute)
+ {
+ using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.fs")))
+ {
+ writer.Write("""
+
+ open System
+ open System.Reflection
+
+ //[]
+
+ """, attribute);
+ }
+
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.fs" }], this.projectFile);
+ }
+
+ [Test]
+ public void VerifyCommentWithNoNewLineAtEndWorksFSharp([Values("AssemblyVersion", "AssemblyFileVersion", "AssemblyInformationalVersion")] string attribute)
+ {
+ using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.fs")))
+ {
+ writer.Write("""
+
+ open System
+ open System.Reflection
+
+ //[]
+ """, attribute);
+ }
+
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.fs" }], this.projectFile);
+ }
+
+ [Test]
+ public void VerifyStringWorksFSharp([Values("AssemblyVersion", "AssemblyFileVersion", "AssemblyInformationalVersion")] string attribute)
+ {
+ using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.fs")))
+ {
+ writer.Write("""
+
+ open System
+ open System.Reflection
+
+ type Temp() =
+ static let Foo = "[]"
+
+ """, attribute);
+ }
+
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.fs" }], this.projectFile);
+ }
+
+ [Test]
+ public void VerifyIdentifierWorksFSharp([Values("AssemblyVersion", "AssemblyFileVersion", "AssemblyInformationalVersion")] string attribute)
+ {
+ using (var writer = File.CreateText(PathHelper.Combine(this.projectDirectory, "AssemblyInfo.fs")))
+ {
+ writer.Write("""
+
+ open System
+ open System.Reflection
+
+ type {0}() = class end
-Public Class {0}
-End Class
-", attribute);
+ """, attribute);
}
- FileHelper.CheckForInvalidFiles(new ITaskItem[] { new MockTaskItem { ItemSpec = "AssemblyInfo.vb" } }, this.projectFile);
+ FileHelper.CheckForInvalidFiles([new MockTaskItem { ItemSpec = "AssemblyInfo.fs" }], this.projectFile);
}
}
diff --git a/src/GitVersion.MsBuild/Helpers/FileHelper.cs b/src/GitVersion.MsBuild/Helpers/FileHelper.cs
index 10618dc116..e8b478ee42 100644
--- a/src/GitVersion.MsBuild/Helpers/FileHelper.cs
+++ b/src/GitVersion.MsBuild/Helpers/FileHelper.cs
@@ -1,4 +1,5 @@
using System.Text.RegularExpressions;
+using GitVersion.Core;
using GitVersion.Helpers;
using Microsoft.Build.Framework;
@@ -6,12 +7,6 @@ namespace GitVersion.MsBuild;
internal static class FileHelper
{
- private static readonly Dictionary> VersionAttributeFinders = new()
- {
- { ".cs", CSharpFileContainsVersionAttribute },
- { ".vb", VisualBasicFileContainsVersionAttribute }
- };
-
public static readonly string TempPath = MakeAndGetTempPath();
private static string MakeAndGetTempPath()
@@ -61,7 +56,8 @@ public static void DeleteTempFiles()
public static void CheckForInvalidFiles(IEnumerable compileFiles, string projectFile)
{
- if (GetInvalidFiles(compileFiles, projectFile).FirstOrDefault() is { } invalidCompileFile)
+ var invalidCompileFile = GetInvalidFiles(compileFiles, projectFile).FirstOrDefault();
+ if (invalidCompileFile != null)
{
throw new WarningException("File contains assembly version attributes which conflict with the attributes generated by GitVersion " + invalidCompileFile);
}
@@ -71,71 +67,31 @@ private static bool FileContainsVersionAttribute(string compileFile, string proj
{
var compileFileExtension = Path.GetExtension(compileFile);
- if (VersionAttributeFinders.TryGetValue(compileFileExtension, out var languageSpecificFileContainsVersionAttribute))
+ var (attributeRegex, triviaRegex) = compileFileExtension switch
{
- return languageSpecificFileContainsVersionAttribute(compileFile, projectFile);
- }
+ ".cs" => (RegexPatterns.AssemblyVersion.CSharp.AttributeRegex, RegexPatterns.AssemblyVersion.CSharp.TriviaRegex),
+ ".fs" => (RegexPatterns.AssemblyVersion.FSharp.AttributeRegex, RegexPatterns.AssemblyVersion.FSharp.TriviaRegex),
+ ".vb" => (RegexPatterns.AssemblyVersion.VisualBasic.AttributeRegex, RegexPatterns.AssemblyVersion.VisualBasic.TriviaRegex),
+ _ => throw new WarningException("File with name containing AssemblyInfo could not be checked for assembly version attributes which conflict with the attributes generated by GitVersion " + compileFile)
+ };
- throw new WarningException("File with name containing AssemblyInfo could not be checked for assembly version attributes which conflict with the attributes generated by GitVersion " + compileFile);
+ return FileContainsVersionAttribute(compileFile, projectFile, attributeRegex, triviaRegex);
}
- private static bool CSharpFileContainsVersionAttribute(string compileFile, string projectFile)
+ private static bool FileContainsVersionAttribute(string compileFile, string projectFile, Regex attributeRegex, Regex triviaRegex)
{
var combine = PathHelper.Combine(Path.GetDirectoryName(projectFile), compileFile);
var allText = File.ReadAllText(combine);
+ allText += PathHelper.NewLine; // Always add a new line, this handles the case for when a file ends with the EOF marker and no new line.
- allText += PathHelper.NewLine; // Always add a new line, this handles the case for when a file ends with the EOF marker and no new line. If you don't have this newline, the regex will match commented out Assembly*Version tags on the last line.
-
- const string blockComments = @"/\*(.*?)\*/";
- const string lineComments = @"//(.*?)\r?\n";
- const string strings = @"""((\\[^\n]|[^""\n])*)""";
- const string verbatimStrings = @"@(""[^""]*"")+";
-
- var noCommentsOrStrings = Regex.Replace(allText,
- blockComments + "|" + lineComments + "|" + strings + "|" + verbatimStrings,
- me => me.Value.StartsWith("//") ? PathHelper.NewLine : string.Empty,
- RegexOptions.Singleline);
-
- return Regex.IsMatch(noCommentsOrStrings, @"(?x) # IgnorePatternWhitespace
-
-\[\s*assembly\s*:\s* # The [assembly: part
-
-(System\s*\.\s*Reflection\s*\.\s*)? # The System.Reflection. part (optional)
-
-Assembly(File|Informational)?Version # The attribute AssemblyVersion, AssemblyFileVersion, or AssemblyInformationalVersion
-
-\s*\(\s*\)\s*\] # End brackets ()]");
+ var noCommentsOrStrings = triviaRegex.Replace(allText, me => me.Value.StartsWith("//") || me.Value.StartsWith("'") ? PathHelper.NewLine : string.Empty);
+ return attributeRegex.IsMatch(noCommentsOrStrings);
}
- private static bool VisualBasicFileContainsVersionAttribute(string compileFile, string projectFile)
- {
- var combine = PathHelper.Combine(Path.GetDirectoryName(projectFile), compileFile);
- var allText = File.ReadAllText(combine);
-
- allText += PathHelper.NewLine; // Always add a new line, this handles the case for when a file ends with the EOF marker and no new line. If you don't have this newline, the regex will match commented out Assembly*Version tags on the last line.
-
- const string lineComments = @"'(.*?)\r?\n";
- const string strings = @"""((\\[^\n]|[^""\n])*)""";
-
- var noCommentsOrStrings = Regex.Replace(allText,
- lineComments + "|" + strings,
- me => me.Value.StartsWith("'") ? PathHelper.NewLine : string.Empty,
- RegexOptions.Singleline);
-
- return Regex.IsMatch(noCommentsOrStrings, @"(?x) # IgnorePatternWhitespace
-
-\<\s*Assembly\s*:\s* # The # End brackets ()>");
- }
-
- private static IEnumerable GetInvalidFiles(IEnumerable compileFiles, string projectFile) => compileFiles.Select(x => x.ItemSpec)
- .Where(compileFile => compileFile.Contains("AssemblyInfo"))
- .Where(s => FileContainsVersionAttribute(s, projectFile));
+ private static IEnumerable GetInvalidFiles(IEnumerable compileFiles, string projectFile)
+ => compileFiles.Select(x => x.ItemSpec)
+ .Where(compileFile => compileFile.Contains("AssemblyInfo"))
+ .Where(s => FileContainsVersionAttribute(s, projectFile));
public static FileWriteInfo GetFileWriteInfo(this string? intermediateOutputPath, string language, string projectFile, string outputFileName)
{
@@ -152,6 +108,7 @@ public static FileWriteInfo GetFileWriteInfo(this string? intermediateOutputPath
fileName = $"{outputFileName}.g.{fileExtension}";
workingDirectory = intermediateOutputPath;
}
+
return new FileWriteInfo(workingDirectory, fileName, fileExtension);
}
}
diff --git a/src/GitVersion.Output.Tests/Output/AssemblyInfoFileUpdaterTests.cs b/src/GitVersion.Output.Tests/Output/AssemblyInfoFileUpdaterTests.cs
index 7082e33020..8ce95285be 100644
--- a/src/GitVersion.Output.Tests/Output/AssemblyInfoFileUpdaterTests.cs
+++ b/src/GitVersion.Output.Tests/Output/AssemblyInfoFileUpdaterTests.cs
@@ -45,7 +45,7 @@ public void ShouldCreateAssemblyInfoFileWhenNotExistsAndEnsureAssemblyInfo(strin
var fullPath = PathHelper.Combine(workingDir, assemblyInfoFile);
var variables = this.variableProvider.GetVariablesFor(
- SemanticVersion.Parse("1.0.0", ConfigurationConstants.DefaultTagPrefix), EmptyConfigurationBuilder.New.Build(), 0);
+ SemanticVersion.Parse("1.0.0", RegexPatterns.Configuration.DefaultTagPrefixPattern), EmptyConfigurationBuilder.New.Build(), 0);
using var assemblyInfoFileUpdater = new AssemblyInfoFileUpdater(this.log, this.fileSystem);
assemblyInfoFileUpdater.Execute(variables, new(workingDir, true, assemblyInfoFile));
@@ -61,7 +61,7 @@ public void ShouldCreateAssemblyInfoFileAtPathWhenNotExistsAndEnsureAssemblyInfo
var assemblyInfoFile = PathHelper.Combine("src", "Project", "Properties", $"VersionAssemblyInfo.{fileExtension}");
var fullPath = PathHelper.Combine(workingDir, assemblyInfoFile);
var variables = this.variableProvider.GetVariablesFor(
- SemanticVersion.Parse("1.0.0", ConfigurationConstants.DefaultTagPrefix), EmptyConfigurationBuilder.New.Build(), 0
+ SemanticVersion.Parse("1.0.0", RegexPatterns.Configuration.DefaultTagPrefixPattern), EmptyConfigurationBuilder.New.Build(), 0
);
using var assemblyInfoFileUpdater = new AssemblyInfoFileUpdater(this.log, this.fileSystem);
@@ -76,7 +76,7 @@ public void ShouldCreateAssemblyInfoFileAtPathWhenNotExistsAndEnsureAssemblyInfo
public void ShouldCreateAssemblyInfoFilesAtPathWhenNotExistsAndEnsureAssemblyInfo(string fileExtension)
{
var assemblyInfoFiles = new HashSet { "AssemblyInfo." + fileExtension, PathHelper.Combine("src", "Project", "Properties", "VersionAssemblyInfo." + fileExtension) };
- var variables = this.variableProvider.GetVariablesFor(SemanticVersion.Parse("1.0.0", ConfigurationConstants.DefaultTagPrefix), EmptyConfigurationBuilder.New.Build(), 0);
+ var variables = this.variableProvider.GetVariablesFor(SemanticVersion.Parse("1.0.0", RegexPatterns.Configuration.DefaultTagPrefixPattern), EmptyConfigurationBuilder.New.Build(), 0);
using var assemblyInfoFileUpdater = new AssemblyInfoFileUpdater(this.log, this.fileSystem);
assemblyInfoFileUpdater.Execute(variables, new(workingDir, true, [.. assemblyInfoFiles]));
@@ -96,7 +96,7 @@ public void ShouldNotCreateAssemblyInfoFileWhenNotExistsAndNotEnsureAssemblyInfo
var assemblyInfoFile = "VersionAssemblyInfo." + fileExtension;
var fullPath = PathHelper.Combine(workingDir, assemblyInfoFile);
var variables = this.variableProvider.GetVariablesFor(
- SemanticVersion.Parse("1.0.0", ConfigurationConstants.DefaultTagPrefix), EmptyConfigurationBuilder.New.Build(), 0
+ SemanticVersion.Parse("1.0.0", RegexPatterns.Configuration.DefaultTagPrefixPattern), EmptyConfigurationBuilder.New.Build(), 0
);
using var assemblyInfoFileUpdater = new AssemblyInfoFileUpdater(this.log, this.fileSystem);
@@ -113,7 +113,7 @@ public void ShouldNotCreateAssemblyInfoFileForUnknownSourceCodeAndEnsureAssembly
const string assemblyInfoFile = "VersionAssemblyInfo.js";
var fullPath = PathHelper.Combine(workingDir, assemblyInfoFile);
var variables = this.variableProvider.GetVariablesFor(
- SemanticVersion.Parse("1.0.0", ConfigurationConstants.DefaultTagPrefix), EmptyConfigurationBuilder.New.Build(), 0
+ SemanticVersion.Parse("1.0.0", RegexPatterns.Configuration.DefaultTagPrefixPattern), EmptyConfigurationBuilder.New.Build(), 0
);
using var assemblyInfoFileUpdater = new AssemblyInfoFileUpdater(this.log, this.fileSystem);
@@ -129,7 +129,7 @@ public void ShouldStartSearchFromWorkingDirectory()
string[] assemblyInfoFiles = [];
var variables = this.variableProvider.GetVariablesFor(
- SemanticVersion.Parse("1.0.0", ConfigurationConstants.DefaultTagPrefix), EmptyConfigurationBuilder.New.Build(), 0
+ SemanticVersion.Parse("1.0.0", RegexPatterns.Configuration.DefaultTagPrefixPattern), EmptyConfigurationBuilder.New.Build(), 0
);
using var assemblyInfoFileUpdater = new AssemblyInfoFileUpdater(this.log, this.fileSystem);
diff --git a/src/GitVersion.Output.Tests/Output/ProjectFileUpdaterTests.cs b/src/GitVersion.Output.Tests/Output/ProjectFileUpdaterTests.cs
index 0eff6f3bb9..4665479e8f 100644
--- a/src/GitVersion.Output.Tests/Output/ProjectFileUpdaterTests.cs
+++ b/src/GitVersion.Output.Tests/Output/ProjectFileUpdaterTests.cs
@@ -145,7 +145,7 @@ public void CannotUpdateProjectFileWithoutAPropertyGroup(string xml)
public void UpdateProjectXmlVersionElementWithStandardXmlInsertsElement(string xml)
{
var variables = this.variableProvider.GetVariablesFor(
- SemanticVersion.Parse("2.0.0", ConfigurationConstants.DefaultTagPrefix), EmptyConfigurationBuilder.New.Build(), 0
+ SemanticVersion.Parse("2.0.0", RegexPatterns.Configuration.DefaultTagPrefixPattern), EmptyConfigurationBuilder.New.Build(), 0
);
var xmlRoot = XElement.Parse(xml);
variables.AssemblySemVer.ShouldNotBeNull();
@@ -176,7 +176,7 @@ public void UpdateProjectXmlVersionElementWithStandardXmlInsertsElement(string x
)]
public void UpdateProjectXmlVersionElementWithStandardXmlModifiesElement(string xml)
{
- var variables = this.variableProvider.GetVariablesFor(SemanticVersion.Parse("2.0.0", ConfigurationConstants.DefaultTagPrefix), EmptyConfigurationBuilder.New.Build(), 0);
+ var variables = this.variableProvider.GetVariablesFor(SemanticVersion.Parse("2.0.0", RegexPatterns.Configuration.DefaultTagPrefixPattern), EmptyConfigurationBuilder.New.Build(), 0);
var xmlRoot = XElement.Parse(xml);
variables.AssemblySemVer.ShouldNotBeNull();
ProjectFileUpdater.UpdateProjectVersionElement(xmlRoot, ProjectFileUpdater.AssemblyVersionElement, variables.AssemblySemVer);
@@ -209,7 +209,7 @@ public void UpdateProjectXmlVersionElementWithStandardXmlModifiesElement(string
)]
public void UpdateProjectXmlVersionElementWithDuplicatePropertyGroupsModifiesLastElement(string xml)
{
- var variables = this.variableProvider.GetVariablesFor(SemanticVersion.Parse("2.0.0", ConfigurationConstants.DefaultTagPrefix), EmptyConfigurationBuilder.New.Build(), 0);
+ var variables = this.variableProvider.GetVariablesFor(SemanticVersion.Parse("2.0.0", RegexPatterns.Configuration.DefaultTagPrefixPattern), EmptyConfigurationBuilder.New.Build(), 0);
var xmlRoot = XElement.Parse(xml);
variables.AssemblySemVer.ShouldNotBeNull();
ProjectFileUpdater.UpdateProjectVersionElement(xmlRoot, ProjectFileUpdater.AssemblyVersionElement, variables.AssemblySemVer);
@@ -243,7 +243,7 @@ public void UpdateProjectXmlVersionElementWithDuplicatePropertyGroupsModifiesLas
)]
public void UpdateProjectXmlVersionElementWithMultipleVersionElementsLastOneIsModified(string xml)
{
- var variables = this.variableProvider.GetVariablesFor(SemanticVersion.Parse("2.0.0", ConfigurationConstants.DefaultTagPrefix), EmptyConfigurationBuilder.New.Build(), 0);
+ var variables = this.variableProvider.GetVariablesFor(SemanticVersion.Parse("2.0.0", RegexPatterns.Configuration.DefaultTagPrefixPattern), EmptyConfigurationBuilder.New.Build(), 0);
var xmlRoot = XElement.Parse(xml);
variables.AssemblySemVer.ShouldNotBeNull();
ProjectFileUpdater.UpdateProjectVersionElement(xmlRoot, ProjectFileUpdater.AssemblyVersionElement, variables.AssemblySemVer);
diff --git a/src/GitVersion.Output/AssemblyInfo/AssemblyInfoFileUpdater.cs b/src/GitVersion.Output/AssemblyInfo/AssemblyInfoFileUpdater.cs
index e731eb72a3..e445500585 100644
--- a/src/GitVersion.Output/AssemblyInfo/AssemblyInfoFileUpdater.cs
+++ b/src/GitVersion.Output/AssemblyInfo/AssemblyInfoFileUpdater.cs
@@ -16,9 +16,9 @@ internal sealed class AssemblyInfoFileUpdater(ILog log, IFileSystem fileSystem)
private readonly Dictionary assemblyAttributeRegexes = new()
{
- {".cs", RegexPatterns.Output.CsharpAssemblyAttributeRegex },
- {".fs", RegexPatterns.Output.FsharpAssemblyAttributeRegex },
- {".vb", RegexPatterns.Output.VisualBasicAssemblyAttributeRegex }
+ [".cs"] = RegexPatterns.Output.CsharpAssemblyAttributeRegex,
+ [".fs"] = RegexPatterns.Output.FsharpAssemblyAttributeRegex,
+ [".vb"] = RegexPatterns.Output.VisualBasicAssemblyAttributeRegex
};
private const string NewLine = "\r\n";