From 5f7738ffa6bb200602420af7cfabc6d64ae4b7c2 Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Sun, 16 Nov 2025 22:35:59 +0100 Subject: [PATCH 1/5] refactors regex patterns for performance Refactors regex patterns to utilize `GeneratedRegexAttribute` caching for improved performance and reduced memory allocation. --- .../ArgumentParserExtensions.cs | 2 +- .../Core/RegexPatternTests.cs | 70 +-- src/GitVersion.Core/Core/RegexPatterns.cs | 431 +++++++++++++++--- .../Formatting/StringFormatWithExtension.cs | 2 +- src/GitVersion.Core/Logging/Log.cs | 2 +- src/GitVersion.Core/MergeMessage.cs | 16 +- src/GitVersion.Core/SemVer/SemanticVersion.cs | 4 +- .../SemVer/SemanticVersionBuildMetaData.cs | 4 +- .../SemVer/SemanticVersionPreReleaseTag.cs | 2 +- .../IncrementStrategyFinder.cs | 16 +- .../Helpers/AssemblyInfoFileHelper.cs | 6 +- .../AssemblyInfo/AssemblyInfoFileUpdater.cs | 12 +- .../Helpers/ParticipantSanitizer.cs | 2 +- 13 files changed, 449 insertions(+), 120 deletions(-) diff --git a/src/GitVersion.App/ArgumentParserExtensions.cs b/src/GitVersion.App/ArgumentParserExtensions.cs index 073983b420..1e134f52cd 100644 --- a/src/GitVersion.App/ArgumentParserExtensions.cs +++ b/src/GitVersion.App/ArgumentParserExtensions.cs @@ -41,7 +41,7 @@ public bool IsValidPath() public bool IsSwitchArgument() { - var patternRegex = RegexPatterns.Common.SwitchArgumentRegex(); + var patternRegex = RegexPatterns.Common.SwitchArgumentRegex; return value != null && (value.StartsWith('-') || value.StartsWith('/')) && !patternRegex.Match(value).Success; diff --git a/src/GitVersion.Core.Tests/Core/RegexPatternTests.cs b/src/GitVersion.Core.Tests/Core/RegexPatternTests.cs index d56739de7f..2cfac644ee 100644 --- a/src/GitVersion.Core.Tests/Core/RegexPatternTests.cs +++ b/src/GitVersion.Core.Tests/Core/RegexPatternTests.cs @@ -10,7 +10,7 @@ public class RegexPatternsTests [TestCase("foo:", false, null)] public void SwitchArgumentRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Common.SwitchArgumentRegex().Match(input); + var match = RegexPatterns.Common.SwitchArgumentRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -21,7 +21,7 @@ public void SwitchArgumentRegex_MatchesExpected(string input, bool expected, str [TestCase("ftp://user:pass@host", false, null)] public void ObscurePasswordRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Common.ObscurePasswordRegex().Match(input); + var match = RegexPatterns.Common.ObscurePasswordRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -34,7 +34,7 @@ public void ObscurePasswordRegex_MatchesExpected(string input, bool expected, st [TestCase("env:FOO", false, null)] public void ExpandTokensRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Common.ExpandTokensRegex().Match(input); + var match = RegexPatterns.Common.ExpandTokensRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -49,7 +49,7 @@ public void ExpandTokensRegex_MatchesExpected(string input, bool expected, strin [TestCase("", true, "")] public void DefaultTagPrefixRegex_MatchesExpected(string input, bool expected, string expectedCapture) { - var match = RegexPatterns.Configuration.DefaultTagPrefixRegex().Match(input); + var match = RegexPatterns.Configuration.DefaultTagPrefixRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -60,7 +60,7 @@ public void DefaultTagPrefixRegex_MatchesExpected(string input, bool expected, s [TestCase("main", false, null)] public void DefaultVersionInBranchRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Configuration.DefaultVersionInBranchRegex().Match(input); + var match = RegexPatterns.Configuration.DefaultVersionInBranchRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -71,7 +71,7 @@ public void DefaultVersionInBranchRegex_MatchesExpected(string input, bool expec [TestCase("develop", false, null)] public void MainBranchRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Configuration.MainBranchRegex().Match(input); + var match = RegexPatterns.Configuration.MainBranchRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -83,7 +83,7 @@ public void MainBranchRegex_MatchesExpected(string input, bool expected, string? [TestCase("main", false, null)] public void DevelopBranchRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Configuration.DevelopBranchRegex().Match(input); + var match = RegexPatterns.Configuration.DevelopBranchRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -94,7 +94,7 @@ public void DevelopBranchRegex_MatchesExpected(string input, bool expected, stri [TestCase("feature/foo", false, null)] public void ReleaseBranchRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Configuration.ReleaseBranchRegex().Match(input); + var match = RegexPatterns.Configuration.ReleaseBranchRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -105,7 +105,7 @@ public void ReleaseBranchRegex_MatchesExpected(string input, bool expected, stri [TestCase("hotfix/1.0", false, null)] public void FeatureBranchRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Configuration.FeatureBranchRegex().Match(input); + var match = RegexPatterns.Configuration.FeatureBranchRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -117,7 +117,7 @@ public void FeatureBranchRegex_MatchesExpected(string input, bool expected, stri [TestCase("main", false, null)] public void PullRequestBranchRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Configuration.PullRequestBranchRegex().Match(input); + var match = RegexPatterns.Configuration.PullRequestBranchRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -128,7 +128,7 @@ public void PullRequestBranchRegex_MatchesExpected(string input, bool expected, [TestCase("support/1.0", false, null)] public void HotfixBranchRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Configuration.HotfixBranchRegex().Match(input); + var match = RegexPatterns.Configuration.HotfixBranchRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -139,7 +139,7 @@ public void HotfixBranchRegex_MatchesExpected(string input, bool expected, strin [TestCase("main", false, null)] public void SupportBranchRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Configuration.SupportBranchRegex().Match(input); + var match = RegexPatterns.Configuration.SupportBranchRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -149,7 +149,7 @@ public void SupportBranchRegex_MatchesExpected(string input, bool expected, stri [TestCase("main", true, "main")] public void UnknownBranchRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Configuration.UnknownBranchRegex().Match(input); + var match = RegexPatterns.Configuration.UnknownBranchRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -160,7 +160,7 @@ public void UnknownBranchRegex_MatchesExpected(string input, bool expected, stri [TestCase("Finish feature/foo", false, null)] public void DefaultMergeMessageRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.MergeMessage.DefaultMergeMessageRegex().Match(input); + var match = RegexPatterns.MergeMessage.DefaultMergeMessageRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -171,7 +171,7 @@ public void DefaultMergeMessageRegex_MatchesExpected(string input, bool expected [TestCase("Merge branch 'feature/foo'", false, null)] public void SmartGitMergeMessageRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.MergeMessage.SmartGitMergeMessageRegex().Match(input); + var match = RegexPatterns.MergeMessage.SmartGitMergeMessageRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -182,7 +182,7 @@ public void SmartGitMergeMessageRegex_MatchesExpected(string input, bool expecte [TestCase("Finish feature/foo", false, null)] public void BitBucketPullMergeMessageRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.MergeMessage.BitBucketPullMergeMessageRegex().Match(input); + var match = RegexPatterns.MergeMessage.BitBucketPullMergeMessageRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -193,7 +193,7 @@ public void BitBucketPullMergeMessageRegex_MatchesExpected(string input, bool ex [TestCase("Merge pull request #123 from repo from feature/foo to develop", false, null)] public void BitBucketPullv7MergeMessageRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.MergeMessage.BitBucketPullv7MergeMessageRegex().Match(input); + var match = RegexPatterns.MergeMessage.BitBucketPullv7MergeMessageRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -204,7 +204,7 @@ public void BitBucketPullv7MergeMessageRegex_MatchesExpected(string input, bool [TestCase("Merge pull request #123 from repo from feature/foo to develop", false, null)] public void BitBucketCloudPullMergeMessageRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.MergeMessage.BitBucketCloudPullMergeMessageRegex().Match(input); + var match = RegexPatterns.MergeMessage.BitBucketCloudPullMergeMessageRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -214,7 +214,7 @@ public void BitBucketCloudPullMergeMessageRegex_MatchesExpected(string input, bo [TestCase("Merge pull request #123 from feature/foo into develop", false, null)] public void AzureDevOpsPullMergeMessageRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.MergeMessage.AzureDevOpsPullMergeMessageRegex().Match(input); + var match = RegexPatterns.MergeMessage.AzureDevOpsPullMergeMessageRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -226,7 +226,7 @@ public void AzureDevOpsPullMergeMessageRegex_MatchesExpected(string input, bool [TestCase("random text", false, null)] public void CsharpAssemblyAttributeRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Output.CsharpAssemblyAttributeRegex().Match(input); + var match = RegexPatterns.Output.CsharpAssemblyAttributeRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -238,7 +238,7 @@ public void CsharpAssemblyAttributeRegex_MatchesExpected(string input, bool expe [TestCase("random text", false, null)] public void FsharpAssemblyAttributeRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Output.FsharpAssemblyAttributeRegex().Match(input); + var match = RegexPatterns.Output.FsharpAssemblyAttributeRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -250,7 +250,7 @@ public void FsharpAssemblyAttributeRegex_MatchesExpected(string input, bool expe [TestCase("random text", false, null)] public void VisualBasicAssemblyAttributeRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Output.VisualBasicAssemblyAttributeRegex().Match(input); + var match = RegexPatterns.Output.VisualBasicAssemblyAttributeRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -261,7 +261,7 @@ public void VisualBasicAssemblyAttributeRegex_MatchesExpected(string input, bool [TestCase("+semver: minor", false, null)] public void DefaultMajorRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.VersionCalculation.DefaultMajorRegex().Match(input); + var match = RegexPatterns.VersionCalculation.DefaultMajorRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -272,7 +272,7 @@ public void DefaultMajorRegex_MatchesExpected(string input, bool expected, strin [TestCase("+semver: patch", false, null)] public void DefaultMinorRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.VersionCalculation.DefaultMinorRegex().Match(input); + var match = RegexPatterns.VersionCalculation.DefaultMinorRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -283,7 +283,7 @@ public void DefaultMinorRegex_MatchesExpected(string input, bool expected, strin [TestCase("+semver: none", false, null)] public void DefaultPatchRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.VersionCalculation.DefaultPatchRegex().Match(input); + var match = RegexPatterns.VersionCalculation.DefaultPatchRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -294,7 +294,7 @@ public void DefaultPatchRegex_MatchesExpected(string input, bool expected, strin [TestCase("+semver: patch", false, null)] public void DefaultNoBumpRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.VersionCalculation.DefaultNoBumpRegex().Match(input); + var match = RegexPatterns.VersionCalculation.DefaultNoBumpRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -305,7 +305,7 @@ public void DefaultNoBumpRegex_MatchesExpected(string input, bool expected, stri [TestCase("1.2", false, null)] public void ParseStrictRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.SemanticVersion.ParseStrictRegex().Match(input); + var match = RegexPatterns.SemanticVersion.ParseStrictRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -317,7 +317,7 @@ public void ParseStrictRegex_MatchesExpected(string input, bool expected, string [TestCase("1.2.3.4", true, "1.2.3.4")] public void ParseLooseRegex_MatchesExpected(string input, bool expected, string expectedCapture) { - var match = RegexPatterns.SemanticVersion.ParseLooseRegex().Match(input); + var match = RegexPatterns.SemanticVersion.ParseLooseRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -328,7 +328,7 @@ public void ParseLooseRegex_MatchesExpected(string input, bool expected, string [TestCase("random", true, "random")] public void ParseBuildMetaDataRegex_MatchesExpected(string input, bool expected, string expectedCapture) { - var match = RegexPatterns.SemanticVersion.ParseBuildMetaDataRegex().Match(input); + var match = RegexPatterns.SemanticVersion.ParseBuildMetaDataRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -341,7 +341,7 @@ public void ParseBuildMetaDataRegex_MatchesExpected(string input, bool expected, [TestCase("m@e#t!a", true, new[] { "@", "#", "!" })] public void FormatBuildMetaDataRegex_CapturesInvalidCharacters(string input, bool shouldMatch, string[] expectedCaptures) { - var matches = RegexPatterns.SemanticVersion.FormatBuildMetaDataRegex().Matches(input); + var matches = RegexPatterns.SemanticVersion.FormatBuildMetaDataRegex.Matches(input); var matched = matches.Count > 0; matched.ShouldBe(shouldMatch, $"Expected match: {shouldMatch}, but found {matches.Count} matches."); @@ -358,7 +358,7 @@ public void FormatBuildMetaDataRegex_CapturesInvalidCharacters(string input, boo [TestCase("rc.2", true, "rc.2")] public void ParsePreReleaseTagRegex_MatchesExpected(string input, bool expected, string expectedCapture) { - var match = RegexPatterns.SemanticVersion.ParsePreReleaseTagRegex().Match(input); + var match = RegexPatterns.SemanticVersion.ParsePreReleaseTagRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -370,7 +370,7 @@ public void ParsePreReleaseTagRegex_MatchesExpected(string input, bool expected, [TestCase("int x = 5;", false, "", "")] public void CSharpTriviaRegex_CapturesExpected(string input, bool expectedMatch, string expectedGroup, string expectedGroupValue) { - var regex = CSharp.TriviaRegex(); + var regex = CSharp.TriviaRegex; var match = regex.Match(input); match.Success.ShouldBe(expectedMatch); @@ -395,7 +395,7 @@ public void CSharpTriviaRegex_CapturesExpected(string input, bool expectedMatch, [TestCase("[assembly: AssemblyTitle(\"App\")]", false)] public void CSharpAttributeRegex_MatchesExpected(string input, bool expectedMatch) { - var regex = CSharp.AttributeRegex(); + var regex = CSharp.AttributeRegex; var match = regex.Match(input); match.Success.ShouldBe(expectedMatch); } @@ -406,7 +406,7 @@ public void CSharpAttributeRegex_MatchesExpected(string input, bool expectedMatc [TestCase("let x = 1", false, "", "")] public void FSharpTriviaRegex_CapturesExpected(string input, bool expectedMatch, string expectedGroup, string expectedGroupValue) { - var regex = FSharp.TriviaRegex(); + var regex = FSharp.TriviaRegex; var match = regex.Match(input); match.Success.ShouldBe(expectedMatch); @@ -431,7 +431,7 @@ public void FSharpTriviaRegex_CapturesExpected(string input, bool expectedMatch, [TestCase("[assembly: AssemblyVersion()]", false)] public void FSharpAttributeRegex_MatchesExpected(string input, bool expectedMatch) { - var regex = FSharp.AttributeRegex(); + var regex = FSharp.AttributeRegex; var match = regex.Match(input); match.Success.ShouldBe(expectedMatch); } diff --git a/src/GitVersion.Core/Core/RegexPatterns.cs b/src/GitVersion.Core/Core/RegexPatterns.cs index a84161731d..5423d60cc5 100644 --- a/src/GitVersion.Core/Core/RegexPatterns.cs +++ b/src/GitVersion.Core/Core/RegexPatterns.cs @@ -18,13 +18,13 @@ public static Regex GetOrAdd([StringSyntax(StringSyntaxAttribute.Regex)] string ArgumentNullException.ThrowIfNull(pattern); return cache.GetOrAdd(pattern, key => - KnownRegexes.TryGetValue(key, out var factory) - ? factory() + KnownRegexes.TryGetValue(key, out var regex) + ? regex : new Regex(key, Options)); } - private static readonly ImmutableDictionary> KnownRegexes = - new Dictionary> + private static readonly ImmutableDictionary KnownRegexes = + new Dictionary { [Common.SwitchArgumentRegexPattern] = Common.SwitchArgumentRegex, [Common.ObscurePasswordRegexPattern] = Common.ObscurePasswordRegex, @@ -122,23 +122,65 @@ internal static partial class Common [StringSyntax(StringSyntaxAttribute.Regex, Options)] internal const string SanitizeNameRegexPattern = "[^a-zA-Z0-9-]"; +#if NET9_0_OR_GREATER [GeneratedRegex(SwitchArgumentRegexPattern, Options)] - public static partial Regex SwitchArgumentRegex(); + public static partial Regex SwitchArgumentRegex { get; } +#else + [GeneratedRegex(SwitchArgumentRegexPattern, Options)] + private static partial Regex SwitchArgumentRegexImpl(); + + public static Regex SwitchArgumentRegex => SwitchArgumentRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(ObscurePasswordRegexPattern, Options)] + public static partial Regex ObscurePasswordRegex { get; } +#else [GeneratedRegex(ObscurePasswordRegexPattern, Options)] - public static partial Regex ObscurePasswordRegex(); + private static partial Regex ObscurePasswordRegexImpl(); + public static Regex ObscurePasswordRegex => ObscurePasswordRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] + public static partial Regex ExpandTokensRegex { get; } +#else [GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] - public static partial Regex ExpandTokensRegex(); + private static partial Regex ExpandTokensRegexImpl(); + + public static Regex ExpandTokensRegex => ExpandTokensRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)] - public static partial Regex SanitizeEnvVarNameRegex(); + public static partial Regex SanitizeEnvVarNameRegex { get; } +#else + [GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)] + private static partial Regex SanitizeEnvVarNameRegexImpl(); + + public static Regex SanitizeEnvVarNameRegex => SanitizeEnvVarNameRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(SanitizeMemberNameRegexPattern, Options)] + public static partial Regex SanitizeMemberNameRegex { get; } +#else [GeneratedRegex(SanitizeMemberNameRegexPattern, Options)] - public static partial Regex SanitizeMemberNameRegex(); + private static partial Regex SanitizeMemberNameRegexImpl(); + public static Regex SanitizeMemberNameRegex => SanitizeMemberNameRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(SanitizeNameRegexPattern, Options)] + public static partial Regex SanitizeNameRegex { get; } +#else [GeneratedRegex(SanitizeNameRegexPattern, Options)] - public static partial Regex SanitizeNameRegex(); + private static partial Regex SanitizeNameRegexImpl(); + + public static Regex SanitizeNameRegex => SanitizeNameRegexImpl(); +#endif } internal static partial class Configuration @@ -173,35 +215,105 @@ internal static partial class Configuration [StringSyntax(StringSyntaxAttribute.Regex)] internal const string UnknownBranchRegexPattern = "(?.+)"; +#if NET9_0_OR_GREATER [GeneratedRegex(DefaultTagPrefixRegexPattern, Options)] - public static partial Regex DefaultTagPrefixRegex(); + public static partial Regex DefaultTagPrefixRegex { get; } +#else + [GeneratedRegex(DefaultTagPrefixRegexPattern, Options)] + private static partial Regex DefaultTagPrefixRegexImpl(); + + public static Regex DefaultTagPrefixRegex => DefaultTagPrefixRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(DefaultVersionInBranchRegexPattern, Options)] + public static partial Regex DefaultVersionInBranchRegex { get; } +#else [GeneratedRegex(DefaultVersionInBranchRegexPattern, Options)] - public static partial Regex DefaultVersionInBranchRegex(); + private static partial Regex DefaultVersionInBranchRegexImpl(); + public static Regex DefaultVersionInBranchRegex => DefaultVersionInBranchRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(MainBranchRegexPattern, Options)] + public static partial Regex MainBranchRegex { get; } +#else [GeneratedRegex(MainBranchRegexPattern, Options)] - public static partial Regex MainBranchRegex(); + private static partial Regex MainBranchRegexImpl(); + + public static Regex MainBranchRegex => MainBranchRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(DevelopBranchRegexPattern, Options)] - public static partial Regex DevelopBranchRegex(); + public static partial Regex DevelopBranchRegex { get; } +#else + [GeneratedRegex(DevelopBranchRegexPattern, Options)] + private static partial Regex DevelopBranchRegexImpl(); + + public static Regex DevelopBranchRegex => DevelopBranchRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(ReleaseBranchRegexPattern, Options)] + public static partial Regex ReleaseBranchRegex { get; } +#else [GeneratedRegex(ReleaseBranchRegexPattern, Options)] - public static partial Regex ReleaseBranchRegex(); + private static partial Regex ReleaseBranchRegexImpl(); + public static Regex ReleaseBranchRegex => ReleaseBranchRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(FeatureBranchRegexPattern, Options)] + public static partial Regex FeatureBranchRegex { get; } +#else [GeneratedRegex(FeatureBranchRegexPattern, Options)] - public static partial Regex FeatureBranchRegex(); + private static partial Regex FeatureBranchRegexImpl(); + + public static Regex FeatureBranchRegex => FeatureBranchRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(PullRequestBranchRegexPattern, Options)] - public static partial Regex PullRequestBranchRegex(); + public static partial Regex PullRequestBranchRegex { get; } +#else + [GeneratedRegex(PullRequestBranchRegexPattern, Options)] + private static partial Regex PullRequestBranchRegexImpl(); + + public static Regex PullRequestBranchRegex => PullRequestBranchRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(HotfixBranchRegexPattern, Options)] + public static partial Regex HotfixBranchRegex { get; } +#else [GeneratedRegex(HotfixBranchRegexPattern, Options)] - public static partial Regex HotfixBranchRegex(); + private static partial Regex HotfixBranchRegexImpl(); + public static Regex HotfixBranchRegex => HotfixBranchRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(SupportBranchRegexPattern, Options)] + public static partial Regex SupportBranchRegex { get; } +#else [GeneratedRegex(SupportBranchRegexPattern, Options)] - public static partial Regex SupportBranchRegex(); + private static partial Regex SupportBranchRegexImpl(); + + public static Regex SupportBranchRegex => SupportBranchRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(UnknownBranchRegexPattern, Options)] - public static partial Regex UnknownBranchRegex(); + public static partial Regex UnknownBranchRegex { get; } +#else + [GeneratedRegex(UnknownBranchRegexPattern, Options)] + private static partial Regex UnknownBranchRegexImpl(); + + public static Regex UnknownBranchRegex => UnknownBranchRegexImpl(); +#endif } internal static partial class MergeMessage @@ -230,29 +342,85 @@ internal static partial class MergeMessage [StringSyntax(StringSyntaxAttribute.Regex)] internal const string AzureDevOpsPullMergeMessageRegexPattern = @"^Merge pull request (?\d+) from (?[^\s]*) into (?[^\s]*)"; +#if NET9_0_OR_GREATER + [GeneratedRegex(DefaultMergeMessageRegexPattern, Options)] + public static partial Regex DefaultMergeMessageRegex { get; } +#else [GeneratedRegex(DefaultMergeMessageRegexPattern, Options)] - public static partial Regex DefaultMergeMessageRegex(); + private static partial Regex DefaultMergeMessageRegexImpl(); + public static Regex DefaultMergeMessageRegex => DefaultMergeMessageRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(SmartGitMergeMessageRegexPattern, Options)] + public static partial Regex SmartGitMergeMessageRegex { get; } +#else [GeneratedRegex(SmartGitMergeMessageRegexPattern, Options)] - public static partial Regex SmartGitMergeMessageRegex(); + private static partial Regex SmartGitMergeMessageRegexImpl(); + + public static Regex SmartGitMergeMessageRegex => SmartGitMergeMessageRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(BitBucketPullMergeMessageRegexPattern, Options)] - public static partial Regex BitBucketPullMergeMessageRegex(); + public static partial Regex BitBucketPullMergeMessageRegex { get; } +#else + [GeneratedRegex(BitBucketPullMergeMessageRegexPattern, Options)] + private static partial Regex BitBucketPullMergeMessageRegexImpl(); + + public static Regex BitBucketPullMergeMessageRegex => BitBucketPullMergeMessageRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(BitBucketPullv7MergeMessageRegexPattern, Options)] + public static partial Regex BitBucketPullv7MergeMessageRegex { get; } +#else [GeneratedRegex(BitBucketPullv7MergeMessageRegexPattern, Options)] - public static partial Regex BitBucketPullv7MergeMessageRegex(); + private static partial Regex BitBucketPullv7MergeMessageRegexImpl(); + public static Regex BitBucketPullv7MergeMessageRegex => BitBucketPullv7MergeMessageRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(BitBucketCloudPullMergeMessageRegexPattern, Options)] + public static partial Regex BitBucketCloudPullMergeMessageRegex { get; } +#else [GeneratedRegex(BitBucketCloudPullMergeMessageRegexPattern, Options)] - public static partial Regex BitBucketCloudPullMergeMessageRegex(); + private static partial Regex BitBucketCloudPullMergeMessageRegexImpl(); + + public static Regex BitBucketCloudPullMergeMessageRegex => BitBucketCloudPullMergeMessageRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(GitHubPullMergeMessageRegexPattern, Options)] - public static partial Regex GitHubPullMergeMessageRegex(); + public static partial Regex GitHubPullMergeMessageRegex { get; } +#else + [GeneratedRegex(GitHubPullMergeMessageRegexPattern, Options)] + private static partial Regex GitHubPullMergeMessageRegexImpl(); + + public static Regex GitHubPullMergeMessageRegex => GitHubPullMergeMessageRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(RemoteTrackingMergeMessageRegexPattern, Options)] + public static partial Regex RemoteTrackingMergeMessageRegex { get; } +#else [GeneratedRegex(RemoteTrackingMergeMessageRegexPattern, Options)] - public static partial Regex RemoteTrackingMergeMessageRegex(); + private static partial Regex RemoteTrackingMergeMessageRegexImpl(); + public static Regex RemoteTrackingMergeMessageRegex => RemoteTrackingMergeMessageRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(AzureDevOpsPullMergeMessageRegexPattern, Options)] + public static partial Regex AzureDevOpsPullMergeMessageRegex { get; } +#else [GeneratedRegex(AzureDevOpsPullMergeMessageRegexPattern, Options)] - public static partial Regex AzureDevOpsPullMergeMessageRegex(); + private static partial Regex AzureDevOpsPullMergeMessageRegexImpl(); + + public static Regex AzureDevOpsPullMergeMessageRegex => AzureDevOpsPullMergeMessageRegexImpl(); +#endif } internal static partial class Output @@ -281,29 +449,85 @@ internal static partial class Output [StringSyntax(StringSyntaxAttribute.Regex)] internal const string SanitizeAssemblyInfoRegexPattern = "[^0-9A-Za-z-.+]"; +#if NET9_0_OR_GREATER + [GeneratedRegex(AssemblyVersionRegexPattern, Options)] + public static partial Regex AssemblyVersionRegex { get; } +#else [GeneratedRegex(AssemblyVersionRegexPattern, Options)] - public static partial Regex AssemblyVersionRegex(); + private static partial Regex AssemblyVersionRegexImpl(); + + public static Regex AssemblyVersionRegex => AssemblyVersionRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(AssemblyInfoVersionRegexPattern, Options)] - public static partial Regex AssemblyInfoVersionRegex(); + public static partial Regex AssemblyInfoVersionRegex { get; } +#else + [GeneratedRegex(AssemblyInfoVersionRegexPattern, Options)] + private static partial Regex AssemblyInfoVersionRegexImpl(); + + public static Regex AssemblyInfoVersionRegex => AssemblyInfoVersionRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(AssemblyFileVersionRegexPattern, Options)] + public static partial Regex AssemblyFileVersionRegex { get; } +#else [GeneratedRegex(AssemblyFileVersionRegexPattern, Options)] - public static partial Regex AssemblyFileVersionRegex(); + private static partial Regex AssemblyFileVersionRegexImpl(); + public static Regex AssemblyFileVersionRegex => AssemblyFileVersionRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(CsharpAssemblyAttributeRegexPattern, Options | RegexOptions.Multiline)] + public static partial Regex CsharpAssemblyAttributeRegex { get; } +#else [GeneratedRegex(CsharpAssemblyAttributeRegexPattern, Options | RegexOptions.Multiline)] - public static partial Regex CsharpAssemblyAttributeRegex(); + private static partial Regex CsharpAssemblyAttributeRegexImpl(); + + public static Regex CsharpAssemblyAttributeRegex => CsharpAssemblyAttributeRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(FsharpAssemblyAttributeRegexPattern, Options | RegexOptions.Multiline)] - public static partial Regex FsharpAssemblyAttributeRegex(); + public static partial Regex FsharpAssemblyAttributeRegex { get; } +#else + [GeneratedRegex(FsharpAssemblyAttributeRegexPattern, Options | RegexOptions.Multiline)] + private static partial Regex FsharpAssemblyAttributeRegexImpl(); + + public static Regex FsharpAssemblyAttributeRegex => FsharpAssemblyAttributeRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(VisualBasicAssemblyAttributeRegexPattern, Options | RegexOptions.Multiline)] + public static partial Regex VisualBasicAssemblyAttributeRegex { get; } +#else [GeneratedRegex(VisualBasicAssemblyAttributeRegexPattern, Options | RegexOptions.Multiline)] - public static partial Regex VisualBasicAssemblyAttributeRegex(); + private static partial Regex VisualBasicAssemblyAttributeRegexImpl(); + public static Regex VisualBasicAssemblyAttributeRegex => VisualBasicAssemblyAttributeRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(SanitizeParticipantRegexPattern, Options)] + public static partial Regex SanitizeParticipantRegex { get; } +#else [GeneratedRegex(SanitizeParticipantRegexPattern, Options)] - public static partial Regex SanitizeParticipantRegex(); + private static partial Regex SanitizeParticipantRegexImpl(); + + public static Regex SanitizeParticipantRegex => SanitizeParticipantRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(SanitizeAssemblyInfoRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] - public static partial Regex SanitizeAssemblyInfoRegex(); + public static partial Regex SanitizeAssemblyInfoRegex { get; } +#else + [GeneratedRegex(SanitizeAssemblyInfoRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] + private static partial Regex SanitizeAssemblyInfoRegexImpl(); + + public static Regex SanitizeAssemblyInfoRegex => SanitizeAssemblyInfoRegexImpl(); +#endif } internal static partial class VersionCalculation @@ -320,17 +544,45 @@ internal static partial class VersionCalculation [StringSyntax(StringSyntaxAttribute.Regex)] internal const string DefaultNoBumpRegexPattern = @"\+semver:\s?(none|skip)"; +#if NET9_0_OR_GREATER + [GeneratedRegex(DefaultMajorRegexPattern, Options)] + public static partial Regex DefaultMajorRegex { get; } +#else [GeneratedRegex(DefaultMajorRegexPattern, Options)] - public static partial Regex DefaultMajorRegex(); + private static partial Regex DefaultMajorRegexImpl(); + public static Regex DefaultMajorRegex => DefaultMajorRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(DefaultMinorRegexPattern, Options)] + public static partial Regex DefaultMinorRegex { get; } +#else [GeneratedRegex(DefaultMinorRegexPattern, Options)] - public static partial Regex DefaultMinorRegex(); + private static partial Regex DefaultMinorRegexImpl(); + + public static Regex DefaultMinorRegex => DefaultMinorRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(DefaultPatchRegexPattern, Options)] - public static partial Regex DefaultPatchRegex(); + public static partial Regex DefaultPatchRegex { get; } +#else + [GeneratedRegex(DefaultPatchRegexPattern, Options)] + private static partial Regex DefaultPatchRegexImpl(); + + public static Regex DefaultPatchRegex => DefaultPatchRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(DefaultNoBumpRegexPattern, Options)] + public static partial Regex DefaultNoBumpRegex { get; } +#else [GeneratedRegex(DefaultNoBumpRegexPattern, Options)] - public static partial Regex DefaultNoBumpRegex(); + private static partial Regex DefaultNoBumpRegexImpl(); + + public static Regex DefaultNoBumpRegex => DefaultNoBumpRegexImpl(); +#endif } internal static partial class SemanticVersion @@ -351,20 +603,55 @@ internal static partial class SemanticVersion internal const string ParsePreReleaseTagRegexPattern = @"(?.*?)\.?(?\d+)?$"; // uses the git-semver spec https://github.com/semver/semver/blob/master/semver.md +#if NET9_0_OR_GREATER + [GeneratedRegex(ParseStrictRegexPattern, Options)] + public static partial Regex ParseStrictRegex { get; } +#else [GeneratedRegex(ParseStrictRegexPattern, Options)] - public static partial Regex ParseStrictRegex(); + private static partial Regex ParseStrictRegexImpl(); + + public static Regex ParseStrictRegex => ParseStrictRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(ParseLooseRegexPattern, Options)] - public static partial Regex ParseLooseRegex(); + public static partial Regex ParseLooseRegex { get; } +#else + [GeneratedRegex(ParseLooseRegexPattern, Options)] + private static partial Regex ParseLooseRegexImpl(); + + public static Regex ParseLooseRegex => ParseLooseRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(ParseBuildMetaDataRegexPattern, Options)] + public static partial Regex ParseBuildMetaDataRegex { get; } +#else [GeneratedRegex(ParseBuildMetaDataRegexPattern, Options)] - public static partial Regex ParseBuildMetaDataRegex(); + private static partial Regex ParseBuildMetaDataRegexImpl(); + public static Regex ParseBuildMetaDataRegex => ParseBuildMetaDataRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(FormatBuildMetaDataRegexPattern, Options)] + public static partial Regex FormatBuildMetaDataRegex { get; } +#else [GeneratedRegex(FormatBuildMetaDataRegexPattern, Options)] - public static partial Regex FormatBuildMetaDataRegex(); + private static partial Regex FormatBuildMetaDataRegexImpl(); + + public static Regex FormatBuildMetaDataRegex => FormatBuildMetaDataRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(ParsePreReleaseTagRegexPattern, Options)] - public static partial Regex ParsePreReleaseTagRegex(); + public static partial Regex ParsePreReleaseTagRegex { get; } +#else + [GeneratedRegex(ParsePreReleaseTagRegexPattern, Options)] + private static partial Regex ParsePreReleaseTagRegexImpl(); + + public static Regex ParsePreReleaseTagRegex => ParsePreReleaseTagRegexImpl(); +#endif } internal static partial class AssemblyVersion @@ -389,11 +676,25 @@ internal static partial class CSharp \s*\(\s*\)\s*\] # End brackets ()] """; +#if NET9_0_OR_GREATER + [GeneratedRegex(TriviaRegexPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options)] + public static partial Regex TriviaRegex { get; } +#else [GeneratedRegex(TriviaRegexPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options)] - public static partial Regex TriviaRegex(); + private static partial Regex TriviaRegexImpl(); + public static Regex TriviaRegex => TriviaRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(AttributeRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] + public static partial Regex AttributeRegex { get; } +#else [GeneratedRegex(AttributeRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] - public static partial Regex AttributeRegex(); + private static partial Regex AttributeRegexImpl(); + + public static Regex AttributeRegex => AttributeRegexImpl(); +#endif } internal static partial class FSharp @@ -420,11 +721,25 @@ internal static partial class FSharp /// Note that while available to call direct, as the C# TriviaRegex is the same it will handle any calls through the cache for F# too. /// /// +#if NET9_0_OR_GREATER [GeneratedRegex(TriviaRegexPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options)] - public static partial Regex TriviaRegex(); + public static partial Regex TriviaRegex { get; } +#else + [GeneratedRegex(TriviaRegexPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options)] + private static partial Regex TriviaRegexImpl(); + + public static Regex TriviaRegex => TriviaRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(AttributeRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] + public static partial Regex AttributeRegex { get; } +#else [GeneratedRegex(AttributeRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] - public static partial Regex AttributeRegex(); + private static partial Regex AttributeRegexImpl(); + + public static Regex AttributeRegex => AttributeRegexImpl(); +#endif } internal static partial class VisualBasic @@ -446,11 +761,25 @@ internal static partial class VisualBasic \s*\(\s*\)\s*\> # End brackets ()> """; +#if NET9_0_OR_GREATER + [GeneratedRegex(TriviaRegexPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options)] + public static partial Regex TriviaRegex { get; } +#else [GeneratedRegex(TriviaRegexPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options)] - public static partial Regex TriviaRegex(); + private static partial Regex TriviaRegexImpl(); + + public static Regex TriviaRegex => TriviaRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(AttributeRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] - public static partial Regex AttributeRegex(); + public static partial Regex AttributeRegex { get; } +#else + [GeneratedRegex(AttributeRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] + private static partial Regex AttributeRegexImpl(); + + public static Regex AttributeRegex => AttributeRegexImpl(); +#endif } } } diff --git a/src/GitVersion.Core/Formatting/StringFormatWithExtension.cs b/src/GitVersion.Core/Formatting/StringFormatWithExtension.cs index a055b7b53b..382b8dfedc 100644 --- a/src/GitVersion.Core/Formatting/StringFormatWithExtension.cs +++ b/src/GitVersion.Core/Formatting/StringFormatWithExtension.cs @@ -45,7 +45,7 @@ public string FormatWith(T? source, IEnvironment environment) var result = new StringBuilder(); var lastIndex = 0; - foreach (var match in RegexPatterns.Common.ExpandTokensRegex().Matches(template).Cast()) + foreach (var match in RegexPatterns.Common.ExpandTokensRegex.Matches(template).Cast()) { var replacement = EvaluateMatch(match, source, environment); result.Append(template, lastIndex, match.Index - lastIndex); diff --git a/src/GitVersion.Core/Logging/Log.cs b/src/GitVersion.Core/Logging/Log.cs index 05de5b44c9..af82183a0e 100644 --- a/src/GitVersion.Core/Logging/Log.cs +++ b/src/GitVersion.Core/Logging/Log.cs @@ -58,7 +58,7 @@ public IDisposable IndentLog(string operationDescription) private string FormatMessage(string message, string level) { - var obscuredMessage = RegexPatterns.Common.ObscurePasswordRegex().Replace(message, "$1$2:*******@"); + var obscuredMessage = RegexPatterns.Common.ObscurePasswordRegex.Replace(message, "$1$2:*******@"); var timestamp = $"{DateTime.Now:yy-MM-dd H:mm:ss:ff}"; return string.Format(CultureInfo.InvariantCulture, "{0}{1} [{2}] {3}", this.currentIndentation, level, timestamp, obscuredMessage); } diff --git a/src/GitVersion.Core/MergeMessage.cs b/src/GitVersion.Core/MergeMessage.cs index 243aa2e758..7a0ffda7e2 100644 --- a/src/GitVersion.Core/MergeMessage.cs +++ b/src/GitVersion.Core/MergeMessage.cs @@ -11,14 +11,14 @@ public class MergeMessage { private static readonly IList<(string Name, Regex Pattern)> DefaultFormats = [ - new("Default", RegexPatterns.MergeMessage.DefaultMergeMessageRegex()), - new("SmartGit", RegexPatterns.MergeMessage.SmartGitMergeMessageRegex()), - new("BitBucketPull", RegexPatterns.MergeMessage.BitBucketPullMergeMessageRegex()), - new("BitBucketPullv7", RegexPatterns.MergeMessage.BitBucketPullv7MergeMessageRegex()), - new("BitBucketCloudPull", RegexPatterns.MergeMessage.BitBucketCloudPullMergeMessageRegex()), - new("GitHubPull", RegexPatterns.MergeMessage.GitHubPullMergeMessageRegex()), - new("RemoteTracking", RegexPatterns.MergeMessage.RemoteTrackingMergeMessageRegex()), - new("AzureDevOpsPull", RegexPatterns.MergeMessage.AzureDevOpsPullMergeMessageRegex()) + new("Default", RegexPatterns.MergeMessage.DefaultMergeMessageRegex), + new("SmartGit", RegexPatterns.MergeMessage.SmartGitMergeMessageRegex), + new("BitBucketPull", RegexPatterns.MergeMessage.BitBucketPullMergeMessageRegex), + new("BitBucketPullv7", RegexPatterns.MergeMessage.BitBucketPullv7MergeMessageRegex), + new("BitBucketCloudPull", RegexPatterns.MergeMessage.BitBucketCloudPullMergeMessageRegex), + new("GitHubPull", RegexPatterns.MergeMessage.GitHubPullMergeMessageRegex), + new("RemoteTracking", RegexPatterns.MergeMessage.RemoteTrackingMergeMessageRegex), + new("AzureDevOpsPull", RegexPatterns.MergeMessage.AzureDevOpsPullMergeMessageRegex) ]; public MergeMessage(string mergeMessage, IGitVersionConfiguration configuration) diff --git a/src/GitVersion.Core/SemVer/SemanticVersion.cs b/src/GitVersion.Core/SemVer/SemanticVersion.cs index eb421e36c7..cab2f2cb3b 100644 --- a/src/GitVersion.Core/SemVer/SemanticVersion.cs +++ b/src/GitVersion.Core/SemVer/SemanticVersion.cs @@ -149,7 +149,7 @@ public static bool TryParse(string version, string? tagPrefixRegex, private static bool TryParseStrict(string version, [NotNullWhen(true)] out SemanticVersion? semanticVersion) { - var parsed = RegexPatterns.SemanticVersion.ParseStrictRegex().Match(version); + var parsed = RegexPatterns.SemanticVersion.ParseStrictRegex.Match(version); if (!parsed.Success) { @@ -171,7 +171,7 @@ private static bool TryParseStrict(string version, [NotNullWhen(true)] out Seman private static bool TryParseLoose(string version, [NotNullWhen(true)] out SemanticVersion? semanticVersion) { - var parsed = RegexPatterns.SemanticVersion.ParseLooseRegex().Match(version); + var parsed = RegexPatterns.SemanticVersion.ParseLooseRegex.Match(version); if (!parsed.Success) { diff --git a/src/GitVersion.Core/SemVer/SemanticVersionBuildMetaData.cs b/src/GitVersion.Core/SemVer/SemanticVersionBuildMetaData.cs index 88f2fc658a..5ae4086543 100644 --- a/src/GitVersion.Core/SemVer/SemanticVersionBuildMetaData.cs +++ b/src/GitVersion.Core/SemVer/SemanticVersionBuildMetaData.cs @@ -111,7 +111,7 @@ public static SemanticVersionBuildMetaData Parse(string? buildMetaData) if (buildMetaData.IsNullOrEmpty()) return Empty; - var parsed = RegexPatterns.SemanticVersion.ParseBuildMetaDataRegex().Match(buildMetaData); + var parsed = RegexPatterns.SemanticVersion.ParseBuildMetaDataRegex.Match(buildMetaData); long? buildMetaDataCommitsSinceTag = null; long? buildMetaDataCommitsSinceVersionSource = null; @@ -147,7 +147,7 @@ public static SemanticVersionBuildMetaData Parse(string? buildMetaData) private static string FormatMetaDataPart(string value) { if (!value.IsNullOrEmpty()) - value = RegexPatterns.SemanticVersion.FormatBuildMetaDataRegex().Replace(value, "-"); + value = RegexPatterns.SemanticVersion.FormatBuildMetaDataRegex.Replace(value, "-"); return value; } } diff --git a/src/GitVersion.Core/SemVer/SemanticVersionPreReleaseTag.cs b/src/GitVersion.Core/SemVer/SemanticVersionPreReleaseTag.cs index 30dc819449..5244c32240 100644 --- a/src/GitVersion.Core/SemVer/SemanticVersionPreReleaseTag.cs +++ b/src/GitVersion.Core/SemVer/SemanticVersionPreReleaseTag.cs @@ -70,7 +70,7 @@ public static SemanticVersionPreReleaseTag Parse(string? preReleaseTag) { if (preReleaseTag.IsNullOrEmpty()) return Empty; - var match = RegexPatterns.SemanticVersion.ParsePreReleaseTagRegex().Match(preReleaseTag); + var match = RegexPatterns.SemanticVersion.ParsePreReleaseTagRegex.Match(preReleaseTag); if (!match.Success) { // TODO check how to log this diff --git a/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs b/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs index ef529381fc..1a2b0bf32b 100644 --- a/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs +++ b/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs @@ -49,10 +49,10 @@ public VersionField DetermineIncrementedField( { commits.NotNull(); - 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 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, noBumpRegex)) @@ -209,10 +209,10 @@ public VersionField GetIncrementForcedByCommit(ICommit commit, IGitVersionConfig commit.NotNull(); configuration.NotNull(); - 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()); + 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.MsBuild/Helpers/AssemblyInfoFileHelper.cs b/src/GitVersion.MsBuild/Helpers/AssemblyInfoFileHelper.cs index d177c6fee0..ae53770b68 100644 --- a/src/GitVersion.MsBuild/Helpers/AssemblyInfoFileHelper.cs +++ b/src/GitVersion.MsBuild/Helpers/AssemblyInfoFileHelper.cs @@ -44,9 +44,9 @@ private static bool FileContainsVersionAttribute(IFileSystem fileSystem, string var (attributeRegex, triviaRegex) = compileFileExtension switch { - ".cs" => (CSharp.AttributeRegex(), CSharp.TriviaRegex()), - ".fs" => (FSharp.AttributeRegex(), FSharp.TriviaRegex()), - ".vb" => (VisualBasic.AttributeRegex(), VisualBasic.TriviaRegex()), + ".cs" => (CSharp.AttributeRegex, CSharp.TriviaRegex), + ".fs" => (FSharp.AttributeRegex, FSharp.TriviaRegex), + ".vb" => (VisualBasic.AttributeRegex, 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) }; diff --git a/src/GitVersion.Output/AssemblyInfo/AssemblyInfoFileUpdater.cs b/src/GitVersion.Output/AssemblyInfo/AssemblyInfoFileUpdater.cs index 3b531597ee..bfb0166d5d 100644 --- a/src/GitVersion.Output/AssemblyInfo/AssemblyInfoFileUpdater.cs +++ b/src/GitVersion.Output/AssemblyInfo/AssemblyInfoFileUpdater.cs @@ -17,9 +17,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"; @@ -65,17 +65,17 @@ public void Execute(GitVersionVariables variables, AssemblyInfoContext context) if (!assemblyVersion.IsNullOrWhiteSpace()) { - fileContents = ReplaceOrInsertAfterLastAssemblyAttributeOrAppend(RegexPatterns.Output.AssemblyVersionRegex(), fileContents, assemblyVersionString, assemblyInfoFile.Extension, ref appendedAttributes); + fileContents = ReplaceOrInsertAfterLastAssemblyAttributeOrAppend(RegexPatterns.Output.AssemblyVersionRegex, fileContents, assemblyVersionString, assemblyInfoFile.Extension, ref appendedAttributes); } if (!assemblyFileVersion.IsNullOrWhiteSpace()) { - fileContents = ReplaceOrInsertAfterLastAssemblyAttributeOrAppend(RegexPatterns.Output.AssemblyFileVersionRegex(), fileContents, assemblyFileVersionString, assemblyInfoFile.Extension, ref appendedAttributes); + fileContents = ReplaceOrInsertAfterLastAssemblyAttributeOrAppend(RegexPatterns.Output.AssemblyFileVersionRegex, fileContents, assemblyFileVersionString, assemblyInfoFile.Extension, ref appendedAttributes); } if (!assemblyInfoVersion.IsNullOrWhiteSpace()) { - fileContents = ReplaceOrInsertAfterLastAssemblyAttributeOrAppend(RegexPatterns.Output.AssemblyInfoVersionRegex(), fileContents, assemblyInfoVersionString, assemblyInfoFile.Extension, ref appendedAttributes); + fileContents = ReplaceOrInsertAfterLastAssemblyAttributeOrAppend(RegexPatterns.Output.AssemblyInfoVersionRegex, fileContents, assemblyInfoVersionString, assemblyInfoFile.Extension, ref appendedAttributes); } if (appendedAttributes) diff --git a/src/GitVersion.Testing/Helpers/ParticipantSanitizer.cs b/src/GitVersion.Testing/Helpers/ParticipantSanitizer.cs index 826728b19b..d22f2f9d73 100644 --- a/src/GitVersion.Testing/Helpers/ParticipantSanitizer.cs +++ b/src/GitVersion.Testing/Helpers/ParticipantSanitizer.cs @@ -12,7 +12,7 @@ public static string SanitizeParticipant(string participant) { GuardAgainstInvalidParticipants(participant); - return RegexPatterns.Output.SanitizeParticipantRegex().Replace(participant, "_"); + return RegexPatterns.Output.SanitizeParticipantRegex.Replace(participant, "_"); } private static void GuardAgainstInvalidParticipants(string participant) From d2e5063b718cf3e0e74eb7c89170582725efb81d Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Mon, 17 Nov 2025 09:31:30 +0100 Subject: [PATCH 2/5] centralize regex patterns and add timeout unifies regex definitions into a central descriptor list. adds a default timeout to regex construction for safety. --- src/GitVersion.Core/Core/RegexPatterns.cs | 118 +++++++++++----------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/src/GitVersion.Core/Core/RegexPatterns.cs b/src/GitVersion.Core/Core/RegexPatterns.cs index 5423d60cc5..f4effd89ee 100644 --- a/src/GitVersion.Core/Core/RegexPatterns.cs +++ b/src/GitVersion.Core/Core/RegexPatterns.cs @@ -8,6 +8,7 @@ namespace GitVersion.Core; internal static partial class RegexPatterns { private const RegexOptions Options = RegexOptions.IgnoreCase | RegexOptions.Compiled; + private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(2); // unified timeout for non-GeneratedRegex fallbacks public static class Cache { @@ -20,61 +21,67 @@ public static Regex GetOrAdd([StringSyntax(StringSyntaxAttribute.Regex)] string return cache.GetOrAdd(pattern, key => KnownRegexes.TryGetValue(key, out var regex) ? regex - : new Regex(key, Options)); + : new Regex(key, Options, DefaultTimeout)); // now uses timeout for safety } + // Descriptor used to centralize pattern + compiled regex instance. Extendable with options/timeout metadata later. + private readonly record struct RegexDescriptor(string Pattern, Regex Regex); + + // Central descriptor list – single source of truth for known patterns. Order not significant. + private static readonly RegexDescriptor[] Descriptors = + [ + new(Common.SwitchArgumentRegexPattern, Common.SwitchArgumentRegex), + new(Common.ObscurePasswordRegexPattern, Common.ObscurePasswordRegex), + new(Common.ExpandTokensRegexPattern, Common.ExpandTokensRegex), + new(Common.SanitizeEnvVarNameRegexPattern, Common.SanitizeEnvVarNameRegex), + new(Common.SanitizeMemberNameRegexPattern, Common.SanitizeMemberNameRegex), + new(Common.SanitizeNameRegexPattern, Common.SanitizeNameRegex), + new(Configuration.DefaultTagPrefixRegexPattern, Configuration.DefaultTagPrefixRegex), + new(Configuration.DefaultVersionInBranchRegexPattern, Configuration.DefaultVersionInBranchRegex), + new(Configuration.MainBranchRegexPattern, Configuration.MainBranchRegex), + new(Configuration.DevelopBranchRegexPattern, Configuration.DevelopBranchRegex), + new(Configuration.ReleaseBranchRegexPattern, Configuration.ReleaseBranchRegex), + new(Configuration.FeatureBranchRegexPattern, Configuration.FeatureBranchRegex), + new(Configuration.PullRequestBranchRegexPattern, Configuration.PullRequestBranchRegex), + new(Configuration.HotfixBranchRegexPattern, Configuration.HotfixBranchRegex), + new(Configuration.SupportBranchRegexPattern, Configuration.SupportBranchRegex), + new(Configuration.UnknownBranchRegexPattern, Configuration.UnknownBranchRegex), + new(MergeMessage.DefaultMergeMessageRegexPattern, MergeMessage.DefaultMergeMessageRegex), + new(MergeMessage.SmartGitMergeMessageRegexPattern, MergeMessage.SmartGitMergeMessageRegex), + new(MergeMessage.BitBucketPullMergeMessageRegexPattern, MergeMessage.BitBucketPullMergeMessageRegex), + new(MergeMessage.BitBucketPullv7MergeMessageRegexPattern, MergeMessage.BitBucketPullv7MergeMessageRegex), + new(MergeMessage.BitBucketCloudPullMergeMessageRegexPattern, MergeMessage.BitBucketCloudPullMergeMessageRegex), + new(MergeMessage.GitHubPullMergeMessageRegexPattern, MergeMessage.GitHubPullMergeMessageRegex), + new(MergeMessage.RemoteTrackingMergeMessageRegexPattern, MergeMessage.RemoteTrackingMergeMessageRegex), + new(MergeMessage.AzureDevOpsPullMergeMessageRegexPattern, MergeMessage.AzureDevOpsPullMergeMessageRegex), + new(Output.AssemblyVersionRegexPattern, Output.AssemblyVersionRegex), + new(Output.AssemblyInfoVersionRegexPattern, Output.AssemblyInfoVersionRegex), + new(Output.AssemblyFileVersionRegexPattern, Output.AssemblyFileVersionRegex), + new(Output.SanitizeAssemblyInfoRegexPattern, Output.SanitizeAssemblyInfoRegex), + new(Output.CsharpAssemblyAttributeRegexPattern, Output.CsharpAssemblyAttributeRegex), + new(Output.FsharpAssemblyAttributeRegexPattern, Output.FsharpAssemblyAttributeRegex), + new(Output.VisualBasicAssemblyAttributeRegexPattern, Output.VisualBasicAssemblyAttributeRegex), + new(Output.SanitizeParticipantRegexPattern, Output.SanitizeParticipantRegex), + new(VersionCalculation.DefaultMajorRegexPattern, VersionCalculation.DefaultMajorRegex), + new(VersionCalculation.DefaultMinorRegexPattern, VersionCalculation.DefaultMinorRegex), + new(VersionCalculation.DefaultPatchRegexPattern, VersionCalculation.DefaultPatchRegex), + new(VersionCalculation.DefaultNoBumpRegexPattern, VersionCalculation.DefaultNoBumpRegex), + new(SemanticVersion.ParseStrictRegexPattern, SemanticVersion.ParseStrictRegex), + new(SemanticVersion.ParseLooseRegexPattern, SemanticVersion.ParseLooseRegex), + new(SemanticVersion.ParseBuildMetaDataRegexPattern, SemanticVersion.ParseBuildMetaDataRegex), + new(SemanticVersion.FormatBuildMetaDataRegexPattern, SemanticVersion.FormatBuildMetaDataRegex), + new(SemanticVersion.ParsePreReleaseTagRegexPattern, SemanticVersion.ParsePreReleaseTagRegex), + // Trivia pattern unified: C# & F# share same underlying pattern; only map once under C# constant. + new(AssemblyVersion.CSharp.TriviaRegexPattern, AssemblyVersion.CSharp.TriviaRegex), + new(AssemblyVersion.CSharp.AttributeRegexPattern, AssemblyVersion.CSharp.AttributeRegex), + // F# Trivia pattern identical – Attribute differs, so include attribute pattern only. + new(AssemblyVersion.FSharp.AttributeRegexPattern, AssemblyVersion.FSharp.AttributeRegex), + new(AssemblyVersion.VisualBasic.TriviaRegexPattern, AssemblyVersion.VisualBasic.TriviaRegex), + new(AssemblyVersion.VisualBasic.AttributeRegexPattern, AssemblyVersion.VisualBasic.AttributeRegex) + ]; + private static readonly ImmutableDictionary KnownRegexes = - new Dictionary - { - [Common.SwitchArgumentRegexPattern] = Common.SwitchArgumentRegex, - [Common.ObscurePasswordRegexPattern] = Common.ObscurePasswordRegex, - [Common.ExpandTokensRegexPattern] = Common.ExpandTokensRegex, - [Common.SanitizeEnvVarNameRegexPattern] = Common.SanitizeEnvVarNameRegex, - [Common.SanitizeMemberNameRegexPattern] = Common.SanitizeMemberNameRegex, - [Common.SanitizeNameRegexPattern] = Common.SanitizeNameRegex, - [Configuration.DefaultTagPrefixRegexPattern] = Configuration.DefaultTagPrefixRegex, - [Configuration.DefaultVersionInBranchRegexPattern] = Configuration.DefaultVersionInBranchRegex, - [Configuration.MainBranchRegexPattern] = Configuration.MainBranchRegex, - [Configuration.DevelopBranchRegexPattern] = Configuration.DevelopBranchRegex, - [Configuration.ReleaseBranchRegexPattern] = Configuration.ReleaseBranchRegex, - [Configuration.FeatureBranchRegexPattern] = Configuration.FeatureBranchRegex, - [Configuration.PullRequestBranchRegexPattern] = Configuration.PullRequestBranchRegex, - [Configuration.HotfixBranchRegexPattern] = Configuration.HotfixBranchRegex, - [Configuration.SupportBranchRegexPattern] = Configuration.SupportBranchRegex, - [Configuration.UnknownBranchRegexPattern] = Configuration.UnknownBranchRegex, - [MergeMessage.DefaultMergeMessageRegexPattern] = MergeMessage.DefaultMergeMessageRegex, - [MergeMessage.SmartGitMergeMessageRegexPattern] = MergeMessage.SmartGitMergeMessageRegex, - [MergeMessage.BitBucketPullMergeMessageRegexPattern] = MergeMessage.BitBucketPullMergeMessageRegex, - [MergeMessage.BitBucketPullv7MergeMessageRegexPattern] = MergeMessage.BitBucketPullv7MergeMessageRegex, - [MergeMessage.BitBucketCloudPullMergeMessageRegexPattern] = MergeMessage.BitBucketCloudPullMergeMessageRegex, - [MergeMessage.GitHubPullMergeMessageRegexPattern] = MergeMessage.GitHubPullMergeMessageRegex, - [MergeMessage.RemoteTrackingMergeMessageRegexPattern] = MergeMessage.RemoteTrackingMergeMessageRegex, - [MergeMessage.AzureDevOpsPullMergeMessageRegexPattern] = MergeMessage.AzureDevOpsPullMergeMessageRegex, - [Output.AssemblyVersionRegexPattern] = Output.AssemblyVersionRegex, - [Output.AssemblyInfoVersionRegexPattern] = Output.AssemblyInfoVersionRegex, - [Output.AssemblyFileVersionRegexPattern] = Output.AssemblyFileVersionRegex, - [Output.SanitizeAssemblyInfoRegexPattern] = Output.SanitizeAssemblyInfoRegex, - [Output.CsharpAssemblyAttributeRegexPattern] = Output.CsharpAssemblyAttributeRegex, - [Output.FsharpAssemblyAttributeRegexPattern] = Output.FsharpAssemblyAttributeRegex, - [Output.VisualBasicAssemblyAttributeRegexPattern] = Output.VisualBasicAssemblyAttributeRegex, - [Output.SanitizeParticipantRegexPattern] = Output.SanitizeParticipantRegex, - [VersionCalculation.DefaultMajorRegexPattern] = VersionCalculation.DefaultMajorRegex, - [VersionCalculation.DefaultMinorRegexPattern] = VersionCalculation.DefaultMinorRegex, - [VersionCalculation.DefaultPatchRegexPattern] = VersionCalculation.DefaultPatchRegex, - [VersionCalculation.DefaultNoBumpRegexPattern] = VersionCalculation.DefaultNoBumpRegex, - [SemanticVersion.ParseStrictRegexPattern] = SemanticVersion.ParseStrictRegex, - [SemanticVersion.ParseLooseRegexPattern] = SemanticVersion.ParseLooseRegex, - [SemanticVersion.ParseBuildMetaDataRegexPattern] = SemanticVersion.ParseBuildMetaDataRegex, - [SemanticVersion.FormatBuildMetaDataRegexPattern] = SemanticVersion.FormatBuildMetaDataRegex, - [SemanticVersion.ParsePreReleaseTagRegexPattern] = SemanticVersion.ParsePreReleaseTagRegex, - [AssemblyVersion.CSharp.TriviaRegexPattern] = AssemblyVersion.CSharp.TriviaRegex, - [AssemblyVersion.CSharp.AttributeRegexPattern] = AssemblyVersion.CSharp.AttributeRegex, - [AssemblyVersion.FSharp.TriviaRegexPattern] = AssemblyVersion.FSharp.TriviaRegex, - // AssemblyVersion.FSharp.TriviaRegexPattern is same as C# so can't be added to the cache so C# TriviaRegex is used for F# as well. - [AssemblyVersion.FSharp.AttributeRegexPattern] = AssemblyVersion.FSharp.AttributeRegex, - [AssemblyVersion.VisualBasic.TriviaRegexPattern] = AssemblyVersion.VisualBasic.TriviaRegex, - [AssemblyVersion.VisualBasic.AttributeRegexPattern] = AssemblyVersion.VisualBasic.AttributeRegex - }.ToImmutableDictionary(); + Descriptors.ToImmutableDictionary(d => d.Pattern, d => d.Regex); } internal static partial class Common @@ -700,12 +707,7 @@ internal static partial class CSharp internal static partial class FSharp { [StringSyntax(StringSyntaxAttribute.Regex)] - internal const string TriviaRegexPattern = - """ - /\*(.*?)\*/ # Block comments: matches /* ... */ - |//(.*?)\r?\n # Line comments: matches // ... followed by a newline - |"((\\[^\n]|[^"\n])*)" # Strings: matches " ... " including escaped quotes - """; + internal const string TriviaRegexPattern = CSharp.TriviaRegexPattern; // unified [StringSyntax(StringSyntaxAttribute.Regex)] internal const string AttributeRegexPattern = From 826d8a62a09172339fab68220dcf167ce6798b39 Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Mon, 17 Nov 2025 12:01:34 +0100 Subject: [PATCH 3/5] Use property-backed fields for regex initialization Replaces expression-bodied properties with property-backed fields for Regex initialization to ensure a consistent approach and avoid potential re-evaluations. Affects multiple regex patterns across the project. --- src/GitVersion.Core/Core/RegexPatterns.cs | 94 +++++++++++------------ 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/GitVersion.Core/Core/RegexPatterns.cs b/src/GitVersion.Core/Core/RegexPatterns.cs index f4effd89ee..74548e723c 100644 --- a/src/GitVersion.Core/Core/RegexPatterns.cs +++ b/src/GitVersion.Core/Core/RegexPatterns.cs @@ -136,7 +136,7 @@ internal static partial class Common [GeneratedRegex(SwitchArgumentRegexPattern, Options)] private static partial Regex SwitchArgumentRegexImpl(); - public static Regex SwitchArgumentRegex => SwitchArgumentRegexImpl(); + public static Regex SwitchArgumentRegex { get; } = SwitchArgumentRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -146,7 +146,7 @@ internal static partial class Common [GeneratedRegex(ObscurePasswordRegexPattern, Options)] private static partial Regex ObscurePasswordRegexImpl(); - public static Regex ObscurePasswordRegex => ObscurePasswordRegexImpl(); + public static Regex ObscurePasswordRegex { get; } = ObscurePasswordRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -156,7 +156,7 @@ internal static partial class Common [GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] private static partial Regex ExpandTokensRegexImpl(); - public static Regex ExpandTokensRegex => ExpandTokensRegexImpl(); + public static Regex ExpandTokensRegex { get; } = ExpandTokensRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -166,7 +166,7 @@ internal static partial class Common [GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)] private static partial Regex SanitizeEnvVarNameRegexImpl(); - public static Regex SanitizeEnvVarNameRegex => SanitizeEnvVarNameRegexImpl(); + public static Regex SanitizeEnvVarNameRegex { get; } = SanitizeEnvVarNameRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -176,7 +176,7 @@ internal static partial class Common [GeneratedRegex(SanitizeMemberNameRegexPattern, Options)] private static partial Regex SanitizeMemberNameRegexImpl(); - public static Regex SanitizeMemberNameRegex => SanitizeMemberNameRegexImpl(); + public static Regex SanitizeMemberNameRegex { get; } = SanitizeMemberNameRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -186,7 +186,7 @@ internal static partial class Common [GeneratedRegex(SanitizeNameRegexPattern, Options)] private static partial Regex SanitizeNameRegexImpl(); - public static Regex SanitizeNameRegex => SanitizeNameRegexImpl(); + public static Regex SanitizeNameRegex { get; } = SanitizeNameRegexImpl(); #endif } @@ -229,7 +229,7 @@ internal static partial class Configuration [GeneratedRegex(DefaultTagPrefixRegexPattern, Options)] private static partial Regex DefaultTagPrefixRegexImpl(); - public static Regex DefaultTagPrefixRegex => DefaultTagPrefixRegexImpl(); + public static Regex DefaultTagPrefixRegex { get; } = DefaultTagPrefixRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -239,7 +239,7 @@ internal static partial class Configuration [GeneratedRegex(DefaultVersionInBranchRegexPattern, Options)] private static partial Regex DefaultVersionInBranchRegexImpl(); - public static Regex DefaultVersionInBranchRegex => DefaultVersionInBranchRegexImpl(); + public static Regex DefaultVersionInBranchRegex { get; } = DefaultVersionInBranchRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -249,7 +249,7 @@ internal static partial class Configuration [GeneratedRegex(MainBranchRegexPattern, Options)] private static partial Regex MainBranchRegexImpl(); - public static Regex MainBranchRegex => MainBranchRegexImpl(); + public static Regex MainBranchRegex { get; } = MainBranchRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -259,7 +259,7 @@ internal static partial class Configuration [GeneratedRegex(DevelopBranchRegexPattern, Options)] private static partial Regex DevelopBranchRegexImpl(); - public static Regex DevelopBranchRegex => DevelopBranchRegexImpl(); + public static Regex DevelopBranchRegex { get; } = DevelopBranchRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -269,7 +269,7 @@ internal static partial class Configuration [GeneratedRegex(ReleaseBranchRegexPattern, Options)] private static partial Regex ReleaseBranchRegexImpl(); - public static Regex ReleaseBranchRegex => ReleaseBranchRegexImpl(); + public static Regex ReleaseBranchRegex { get; } = ReleaseBranchRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -279,7 +279,7 @@ internal static partial class Configuration [GeneratedRegex(FeatureBranchRegexPattern, Options)] private static partial Regex FeatureBranchRegexImpl(); - public static Regex FeatureBranchRegex => FeatureBranchRegexImpl(); + public static Regex FeatureBranchRegex { get; } = FeatureBranchRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -289,7 +289,7 @@ internal static partial class Configuration [GeneratedRegex(PullRequestBranchRegexPattern, Options)] private static partial Regex PullRequestBranchRegexImpl(); - public static Regex PullRequestBranchRegex => PullRequestBranchRegexImpl(); + public static Regex PullRequestBranchRegex { get; } = PullRequestBranchRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -299,7 +299,7 @@ internal static partial class Configuration [GeneratedRegex(HotfixBranchRegexPattern, Options)] private static partial Regex HotfixBranchRegexImpl(); - public static Regex HotfixBranchRegex => HotfixBranchRegexImpl(); + public static Regex HotfixBranchRegex { get; } = HotfixBranchRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -309,7 +309,7 @@ internal static partial class Configuration [GeneratedRegex(SupportBranchRegexPattern, Options)] private static partial Regex SupportBranchRegexImpl(); - public static Regex SupportBranchRegex => SupportBranchRegexImpl(); + public static Regex SupportBranchRegex { get; } = SupportBranchRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -319,7 +319,7 @@ internal static partial class Configuration [GeneratedRegex(UnknownBranchRegexPattern, Options)] private static partial Regex UnknownBranchRegexImpl(); - public static Regex UnknownBranchRegex => UnknownBranchRegexImpl(); + public static Regex UnknownBranchRegex { get; } = UnknownBranchRegexImpl(); #endif } @@ -356,7 +356,7 @@ internal static partial class MergeMessage [GeneratedRegex(DefaultMergeMessageRegexPattern, Options)] private static partial Regex DefaultMergeMessageRegexImpl(); - public static Regex DefaultMergeMessageRegex => DefaultMergeMessageRegexImpl(); + public static Regex DefaultMergeMessageRegex { get; } = DefaultMergeMessageRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -366,7 +366,7 @@ internal static partial class MergeMessage [GeneratedRegex(SmartGitMergeMessageRegexPattern, Options)] private static partial Regex SmartGitMergeMessageRegexImpl(); - public static Regex SmartGitMergeMessageRegex => SmartGitMergeMessageRegexImpl(); + public static Regex SmartGitMergeMessageRegex { get; } = SmartGitMergeMessageRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -376,7 +376,7 @@ internal static partial class MergeMessage [GeneratedRegex(BitBucketPullMergeMessageRegexPattern, Options)] private static partial Regex BitBucketPullMergeMessageRegexImpl(); - public static Regex BitBucketPullMergeMessageRegex => BitBucketPullMergeMessageRegexImpl(); + public static Regex BitBucketPullMergeMessageRegex { get; } = BitBucketPullMergeMessageRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -386,7 +386,7 @@ internal static partial class MergeMessage [GeneratedRegex(BitBucketPullv7MergeMessageRegexPattern, Options)] private static partial Regex BitBucketPullv7MergeMessageRegexImpl(); - public static Regex BitBucketPullv7MergeMessageRegex => BitBucketPullv7MergeMessageRegexImpl(); + public static Regex BitBucketPullv7MergeMessageRegex { get; } = BitBucketPullv7MergeMessageRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -396,7 +396,7 @@ internal static partial class MergeMessage [GeneratedRegex(BitBucketCloudPullMergeMessageRegexPattern, Options)] private static partial Regex BitBucketCloudPullMergeMessageRegexImpl(); - public static Regex BitBucketCloudPullMergeMessageRegex => BitBucketCloudPullMergeMessageRegexImpl(); + public static Regex BitBucketCloudPullMergeMessageRegex { get; } = BitBucketCloudPullMergeMessageRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -406,7 +406,7 @@ internal static partial class MergeMessage [GeneratedRegex(GitHubPullMergeMessageRegexPattern, Options)] private static partial Regex GitHubPullMergeMessageRegexImpl(); - public static Regex GitHubPullMergeMessageRegex => GitHubPullMergeMessageRegexImpl(); + public static Regex GitHubPullMergeMessageRegex { get; } = GitHubPullMergeMessageRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -416,7 +416,7 @@ internal static partial class MergeMessage [GeneratedRegex(RemoteTrackingMergeMessageRegexPattern, Options)] private static partial Regex RemoteTrackingMergeMessageRegexImpl(); - public static Regex RemoteTrackingMergeMessageRegex => RemoteTrackingMergeMessageRegexImpl(); + public static Regex RemoteTrackingMergeMessageRegex { get; } = RemoteTrackingMergeMessageRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -426,7 +426,7 @@ internal static partial class MergeMessage [GeneratedRegex(AzureDevOpsPullMergeMessageRegexPattern, Options)] private static partial Regex AzureDevOpsPullMergeMessageRegexImpl(); - public static Regex AzureDevOpsPullMergeMessageRegex => AzureDevOpsPullMergeMessageRegexImpl(); + public static Regex AzureDevOpsPullMergeMessageRegex { get; } = AzureDevOpsPullMergeMessageRegexImpl(); #endif } @@ -463,7 +463,7 @@ internal static partial class Output [GeneratedRegex(AssemblyVersionRegexPattern, Options)] private static partial Regex AssemblyVersionRegexImpl(); - public static Regex AssemblyVersionRegex => AssemblyVersionRegexImpl(); + public static Regex AssemblyVersionRegex { get; } = AssemblyVersionRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -473,7 +473,7 @@ internal static partial class Output [GeneratedRegex(AssemblyInfoVersionRegexPattern, Options)] private static partial Regex AssemblyInfoVersionRegexImpl(); - public static Regex AssemblyInfoVersionRegex => AssemblyInfoVersionRegexImpl(); + public static Regex AssemblyInfoVersionRegex { get; } = AssemblyInfoVersionRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -483,7 +483,7 @@ internal static partial class Output [GeneratedRegex(AssemblyFileVersionRegexPattern, Options)] private static partial Regex AssemblyFileVersionRegexImpl(); - public static Regex AssemblyFileVersionRegex => AssemblyFileVersionRegexImpl(); + public static Regex AssemblyFileVersionRegex { get; } = AssemblyFileVersionRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -493,7 +493,7 @@ internal static partial class Output [GeneratedRegex(CsharpAssemblyAttributeRegexPattern, Options | RegexOptions.Multiline)] private static partial Regex CsharpAssemblyAttributeRegexImpl(); - public static Regex CsharpAssemblyAttributeRegex => CsharpAssemblyAttributeRegexImpl(); + public static Regex CsharpAssemblyAttributeRegex { get; } = CsharpAssemblyAttributeRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -503,7 +503,7 @@ internal static partial class Output [GeneratedRegex(FsharpAssemblyAttributeRegexPattern, Options | RegexOptions.Multiline)] private static partial Regex FsharpAssemblyAttributeRegexImpl(); - public static Regex FsharpAssemblyAttributeRegex => FsharpAssemblyAttributeRegexImpl(); + public static Regex FsharpAssemblyAttributeRegex { get; } = FsharpAssemblyAttributeRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -513,7 +513,7 @@ internal static partial class Output [GeneratedRegex(VisualBasicAssemblyAttributeRegexPattern, Options | RegexOptions.Multiline)] private static partial Regex VisualBasicAssemblyAttributeRegexImpl(); - public static Regex VisualBasicAssemblyAttributeRegex => VisualBasicAssemblyAttributeRegexImpl(); + public static Regex VisualBasicAssemblyAttributeRegex { get; } = VisualBasicAssemblyAttributeRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -523,7 +523,7 @@ internal static partial class Output [GeneratedRegex(SanitizeParticipantRegexPattern, Options)] private static partial Regex SanitizeParticipantRegexImpl(); - public static Regex SanitizeParticipantRegex => SanitizeParticipantRegexImpl(); + public static Regex SanitizeParticipantRegex { get; } = SanitizeParticipantRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -533,7 +533,7 @@ internal static partial class Output [GeneratedRegex(SanitizeAssemblyInfoRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] private static partial Regex SanitizeAssemblyInfoRegexImpl(); - public static Regex SanitizeAssemblyInfoRegex => SanitizeAssemblyInfoRegexImpl(); + public static Regex SanitizeAssemblyInfoRegex { get; } = SanitizeAssemblyInfoRegexImpl(); #endif } @@ -558,7 +558,7 @@ internal static partial class VersionCalculation [GeneratedRegex(DefaultMajorRegexPattern, Options)] private static partial Regex DefaultMajorRegexImpl(); - public static Regex DefaultMajorRegex => DefaultMajorRegexImpl(); + public static Regex DefaultMajorRegex { get; } = DefaultMajorRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -568,7 +568,7 @@ internal static partial class VersionCalculation [GeneratedRegex(DefaultMinorRegexPattern, Options)] private static partial Regex DefaultMinorRegexImpl(); - public static Regex DefaultMinorRegex => DefaultMinorRegexImpl(); + public static Regex DefaultMinorRegex { get; } = DefaultMinorRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -578,7 +578,7 @@ internal static partial class VersionCalculation [GeneratedRegex(DefaultPatchRegexPattern, Options)] private static partial Regex DefaultPatchRegexImpl(); - public static Regex DefaultPatchRegex => DefaultPatchRegexImpl(); + public static Regex DefaultPatchRegex { get; } = DefaultPatchRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -588,7 +588,7 @@ internal static partial class VersionCalculation [GeneratedRegex(DefaultNoBumpRegexPattern, Options)] private static partial Regex DefaultNoBumpRegexImpl(); - public static Regex DefaultNoBumpRegex => DefaultNoBumpRegexImpl(); + public static Regex DefaultNoBumpRegex { get; } = DefaultNoBumpRegexImpl(); #endif } @@ -617,7 +617,7 @@ internal static partial class SemanticVersion [GeneratedRegex(ParseStrictRegexPattern, Options)] private static partial Regex ParseStrictRegexImpl(); - public static Regex ParseStrictRegex => ParseStrictRegexImpl(); + public static Regex ParseStrictRegex { get; } = ParseStrictRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -627,7 +627,7 @@ internal static partial class SemanticVersion [GeneratedRegex(ParseLooseRegexPattern, Options)] private static partial Regex ParseLooseRegexImpl(); - public static Regex ParseLooseRegex => ParseLooseRegexImpl(); + public static Regex ParseLooseRegex { get; } = ParseLooseRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -637,7 +637,7 @@ internal static partial class SemanticVersion [GeneratedRegex(ParseBuildMetaDataRegexPattern, Options)] private static partial Regex ParseBuildMetaDataRegexImpl(); - public static Regex ParseBuildMetaDataRegex => ParseBuildMetaDataRegexImpl(); + public static Regex ParseBuildMetaDataRegex { get; } = ParseBuildMetaDataRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -647,7 +647,7 @@ internal static partial class SemanticVersion [GeneratedRegex(FormatBuildMetaDataRegexPattern, Options)] private static partial Regex FormatBuildMetaDataRegexImpl(); - public static Regex FormatBuildMetaDataRegex => FormatBuildMetaDataRegexImpl(); + public static Regex FormatBuildMetaDataRegex { get; } = FormatBuildMetaDataRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -657,7 +657,7 @@ internal static partial class SemanticVersion [GeneratedRegex(ParsePreReleaseTagRegexPattern, Options)] private static partial Regex ParsePreReleaseTagRegexImpl(); - public static Regex ParsePreReleaseTagRegex => ParsePreReleaseTagRegexImpl(); + public static Regex ParsePreReleaseTagRegex { get; } = ParsePreReleaseTagRegexImpl(); #endif } @@ -690,7 +690,7 @@ internal static partial class CSharp [GeneratedRegex(TriviaRegexPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options)] private static partial Regex TriviaRegexImpl(); - public static Regex TriviaRegex => TriviaRegexImpl(); + public static Regex TriviaRegex { get; } = TriviaRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -700,7 +700,7 @@ internal static partial class CSharp [GeneratedRegex(AttributeRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] private static partial Regex AttributeRegexImpl(); - public static Regex AttributeRegex => AttributeRegexImpl(); + public static Regex AttributeRegex { get; } = AttributeRegexImpl(); #endif } @@ -730,7 +730,7 @@ internal static partial class FSharp [GeneratedRegex(TriviaRegexPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options)] private static partial Regex TriviaRegexImpl(); - public static Regex TriviaRegex => TriviaRegexImpl(); + public static Regex TriviaRegex { get; } = TriviaRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -740,7 +740,7 @@ internal static partial class FSharp [GeneratedRegex(AttributeRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] private static partial Regex AttributeRegexImpl(); - public static Regex AttributeRegex => AttributeRegexImpl(); + public static Regex AttributeRegex { get; } = AttributeRegexImpl(); #endif } @@ -770,7 +770,7 @@ internal static partial class VisualBasic [GeneratedRegex(TriviaRegexPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options)] private static partial Regex TriviaRegexImpl(); - public static Regex TriviaRegex => TriviaRegexImpl(); + public static Regex TriviaRegex { get; } = TriviaRegexImpl(); #endif #if NET9_0_OR_GREATER @@ -780,7 +780,7 @@ internal static partial class VisualBasic [GeneratedRegex(AttributeRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] private static partial Regex AttributeRegexImpl(); - public static Regex AttributeRegex => AttributeRegexImpl(); + public static Regex AttributeRegex { get; } = AttributeRegexImpl(); #endif } } From aeb6b7ea1aa7fa13d328b6b0369ec891930eb3bc Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Mon, 17 Nov 2025 13:23:50 +0100 Subject: [PATCH 4/5] moves regex cache to bottom of class moves regex cache to bottom of the class, for better organization. --- src/GitVersion.Core/Core/RegexPatterns.cs | 151 +++++++++++----------- 1 file changed, 76 insertions(+), 75 deletions(-) diff --git a/src/GitVersion.Core/Core/RegexPatterns.cs b/src/GitVersion.Core/Core/RegexPatterns.cs index 74548e723c..add4489e4f 100644 --- a/src/GitVersion.Core/Core/RegexPatterns.cs +++ b/src/GitVersion.Core/Core/RegexPatterns.cs @@ -10,80 +10,6 @@ internal static partial class RegexPatterns private const RegexOptions Options = RegexOptions.IgnoreCase | RegexOptions.Compiled; private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(2); // unified timeout for non-GeneratedRegex fallbacks - public static class Cache - { - private static readonly ConcurrentDictionary cache = new(); - - public static Regex GetOrAdd([StringSyntax(StringSyntaxAttribute.Regex)] string pattern) - { - ArgumentNullException.ThrowIfNull(pattern); - - return cache.GetOrAdd(pattern, key => - KnownRegexes.TryGetValue(key, out var regex) - ? regex - : new Regex(key, Options, DefaultTimeout)); // now uses timeout for safety - } - - // Descriptor used to centralize pattern + compiled regex instance. Extendable with options/timeout metadata later. - private readonly record struct RegexDescriptor(string Pattern, Regex Regex); - - // Central descriptor list – single source of truth for known patterns. Order not significant. - private static readonly RegexDescriptor[] Descriptors = - [ - new(Common.SwitchArgumentRegexPattern, Common.SwitchArgumentRegex), - new(Common.ObscurePasswordRegexPattern, Common.ObscurePasswordRegex), - new(Common.ExpandTokensRegexPattern, Common.ExpandTokensRegex), - new(Common.SanitizeEnvVarNameRegexPattern, Common.SanitizeEnvVarNameRegex), - new(Common.SanitizeMemberNameRegexPattern, Common.SanitizeMemberNameRegex), - new(Common.SanitizeNameRegexPattern, Common.SanitizeNameRegex), - new(Configuration.DefaultTagPrefixRegexPattern, Configuration.DefaultTagPrefixRegex), - new(Configuration.DefaultVersionInBranchRegexPattern, Configuration.DefaultVersionInBranchRegex), - new(Configuration.MainBranchRegexPattern, Configuration.MainBranchRegex), - new(Configuration.DevelopBranchRegexPattern, Configuration.DevelopBranchRegex), - new(Configuration.ReleaseBranchRegexPattern, Configuration.ReleaseBranchRegex), - new(Configuration.FeatureBranchRegexPattern, Configuration.FeatureBranchRegex), - new(Configuration.PullRequestBranchRegexPattern, Configuration.PullRequestBranchRegex), - new(Configuration.HotfixBranchRegexPattern, Configuration.HotfixBranchRegex), - new(Configuration.SupportBranchRegexPattern, Configuration.SupportBranchRegex), - new(Configuration.UnknownBranchRegexPattern, Configuration.UnknownBranchRegex), - new(MergeMessage.DefaultMergeMessageRegexPattern, MergeMessage.DefaultMergeMessageRegex), - new(MergeMessage.SmartGitMergeMessageRegexPattern, MergeMessage.SmartGitMergeMessageRegex), - new(MergeMessage.BitBucketPullMergeMessageRegexPattern, MergeMessage.BitBucketPullMergeMessageRegex), - new(MergeMessage.BitBucketPullv7MergeMessageRegexPattern, MergeMessage.BitBucketPullv7MergeMessageRegex), - new(MergeMessage.BitBucketCloudPullMergeMessageRegexPattern, MergeMessage.BitBucketCloudPullMergeMessageRegex), - new(MergeMessage.GitHubPullMergeMessageRegexPattern, MergeMessage.GitHubPullMergeMessageRegex), - new(MergeMessage.RemoteTrackingMergeMessageRegexPattern, MergeMessage.RemoteTrackingMergeMessageRegex), - new(MergeMessage.AzureDevOpsPullMergeMessageRegexPattern, MergeMessage.AzureDevOpsPullMergeMessageRegex), - new(Output.AssemblyVersionRegexPattern, Output.AssemblyVersionRegex), - new(Output.AssemblyInfoVersionRegexPattern, Output.AssemblyInfoVersionRegex), - new(Output.AssemblyFileVersionRegexPattern, Output.AssemblyFileVersionRegex), - new(Output.SanitizeAssemblyInfoRegexPattern, Output.SanitizeAssemblyInfoRegex), - new(Output.CsharpAssemblyAttributeRegexPattern, Output.CsharpAssemblyAttributeRegex), - new(Output.FsharpAssemblyAttributeRegexPattern, Output.FsharpAssemblyAttributeRegex), - new(Output.VisualBasicAssemblyAttributeRegexPattern, Output.VisualBasicAssemblyAttributeRegex), - new(Output.SanitizeParticipantRegexPattern, Output.SanitizeParticipantRegex), - new(VersionCalculation.DefaultMajorRegexPattern, VersionCalculation.DefaultMajorRegex), - new(VersionCalculation.DefaultMinorRegexPattern, VersionCalculation.DefaultMinorRegex), - new(VersionCalculation.DefaultPatchRegexPattern, VersionCalculation.DefaultPatchRegex), - new(VersionCalculation.DefaultNoBumpRegexPattern, VersionCalculation.DefaultNoBumpRegex), - new(SemanticVersion.ParseStrictRegexPattern, SemanticVersion.ParseStrictRegex), - new(SemanticVersion.ParseLooseRegexPattern, SemanticVersion.ParseLooseRegex), - new(SemanticVersion.ParseBuildMetaDataRegexPattern, SemanticVersion.ParseBuildMetaDataRegex), - new(SemanticVersion.FormatBuildMetaDataRegexPattern, SemanticVersion.FormatBuildMetaDataRegex), - new(SemanticVersion.ParsePreReleaseTagRegexPattern, SemanticVersion.ParsePreReleaseTagRegex), - // Trivia pattern unified: C# & F# share same underlying pattern; only map once under C# constant. - new(AssemblyVersion.CSharp.TriviaRegexPattern, AssemblyVersion.CSharp.TriviaRegex), - new(AssemblyVersion.CSharp.AttributeRegexPattern, AssemblyVersion.CSharp.AttributeRegex), - // F# Trivia pattern identical – Attribute differs, so include attribute pattern only. - new(AssemblyVersion.FSharp.AttributeRegexPattern, AssemblyVersion.FSharp.AttributeRegex), - new(AssemblyVersion.VisualBasic.TriviaRegexPattern, AssemblyVersion.VisualBasic.TriviaRegex), - new(AssemblyVersion.VisualBasic.AttributeRegexPattern, AssemblyVersion.VisualBasic.AttributeRegex) - ]; - - private static readonly ImmutableDictionary KnownRegexes = - Descriptors.ToImmutableDictionary(d => d.Pattern, d => d.Regex); - } - internal static partial class Common { [StringSyntax(StringSyntaxAttribute.Regex)] @@ -93,7 +19,8 @@ internal static partial class Common internal const string ObscurePasswordRegexPattern = "(https?://)(.+)(:.+@)"; [StringSyntax(StringSyntaxAttribute.Regex)] - internal const string ExpandTokensRegexPattern = """ + internal const string ExpandTokensRegexPattern = + """ \{ # Opening brace (?: # Start of either env or member expression env:(?!env:)(?[A-Za-z_][A-Za-z0-9_]*) # Only a single env: prefix, not followed by another env: @@ -190,6 +117,80 @@ internal static partial class Common #endif } + public static class Cache + { + private static readonly ConcurrentDictionary cache = new(); + + public static Regex GetOrAdd([StringSyntax(StringSyntaxAttribute.Regex)] string pattern) + { + ArgumentNullException.ThrowIfNull(pattern); + + return cache.GetOrAdd(pattern, key => + KnownRegexes.TryGetValue(key, out var regex) + ? regex + : new Regex(key, Options, DefaultTimeout)); // now uses timeout for safety + } + + // Descriptor used to centralize pattern + compiled regex instance. Extendable with options/timeout metadata later. + private readonly record struct RegexDescriptor(string Pattern, Regex Regex); + + // Central descriptor list – single source of truth for known patterns. Order not significant. + private static readonly RegexDescriptor[] Descriptors = + [ + new(Common.SwitchArgumentRegexPattern, Common.SwitchArgumentRegex), + new(Common.ObscurePasswordRegexPattern, Common.ObscurePasswordRegex), + new(Common.ExpandTokensRegexPattern, Common.ExpandTokensRegex), + new(Common.SanitizeEnvVarNameRegexPattern, Common.SanitizeEnvVarNameRegex), + new(Common.SanitizeMemberNameRegexPattern, Common.SanitizeMemberNameRegex), + new(Common.SanitizeNameRegexPattern, Common.SanitizeNameRegex), + new(Configuration.DefaultTagPrefixRegexPattern, Configuration.DefaultTagPrefixRegex), + new(Configuration.DefaultVersionInBranchRegexPattern, Configuration.DefaultVersionInBranchRegex), + new(Configuration.MainBranchRegexPattern, Configuration.MainBranchRegex), + new(Configuration.DevelopBranchRegexPattern, Configuration.DevelopBranchRegex), + new(Configuration.ReleaseBranchRegexPattern, Configuration.ReleaseBranchRegex), + new(Configuration.FeatureBranchRegexPattern, Configuration.FeatureBranchRegex), + new(Configuration.PullRequestBranchRegexPattern, Configuration.PullRequestBranchRegex), + new(Configuration.HotfixBranchRegexPattern, Configuration.HotfixBranchRegex), + new(Configuration.SupportBranchRegexPattern, Configuration.SupportBranchRegex), + new(Configuration.UnknownBranchRegexPattern, Configuration.UnknownBranchRegex), + new(MergeMessage.DefaultMergeMessageRegexPattern, MergeMessage.DefaultMergeMessageRegex), + new(MergeMessage.SmartGitMergeMessageRegexPattern, MergeMessage.SmartGitMergeMessageRegex), + new(MergeMessage.BitBucketPullMergeMessageRegexPattern, MergeMessage.BitBucketPullMergeMessageRegex), + new(MergeMessage.BitBucketPullv7MergeMessageRegexPattern, MergeMessage.BitBucketPullv7MergeMessageRegex), + new(MergeMessage.BitBucketCloudPullMergeMessageRegexPattern, MergeMessage.BitBucketCloudPullMergeMessageRegex), + new(MergeMessage.GitHubPullMergeMessageRegexPattern, MergeMessage.GitHubPullMergeMessageRegex), + new(MergeMessage.RemoteTrackingMergeMessageRegexPattern, MergeMessage.RemoteTrackingMergeMessageRegex), + new(MergeMessage.AzureDevOpsPullMergeMessageRegexPattern, MergeMessage.AzureDevOpsPullMergeMessageRegex), + new(Output.AssemblyVersionRegexPattern, Output.AssemblyVersionRegex), + new(Output.AssemblyInfoVersionRegexPattern, Output.AssemblyInfoVersionRegex), + new(Output.AssemblyFileVersionRegexPattern, Output.AssemblyFileVersionRegex), + new(Output.SanitizeAssemblyInfoRegexPattern, Output.SanitizeAssemblyInfoRegex), + new(Output.CsharpAssemblyAttributeRegexPattern, Output.CsharpAssemblyAttributeRegex), + new(Output.FsharpAssemblyAttributeRegexPattern, Output.FsharpAssemblyAttributeRegex), + new(Output.VisualBasicAssemblyAttributeRegexPattern, Output.VisualBasicAssemblyAttributeRegex), + new(Output.SanitizeParticipantRegexPattern, Output.SanitizeParticipantRegex), + new(VersionCalculation.DefaultMajorRegexPattern, VersionCalculation.DefaultMajorRegex), + new(VersionCalculation.DefaultMinorRegexPattern, VersionCalculation.DefaultMinorRegex), + new(VersionCalculation.DefaultPatchRegexPattern, VersionCalculation.DefaultPatchRegex), + new(VersionCalculation.DefaultNoBumpRegexPattern, VersionCalculation.DefaultNoBumpRegex), + new(SemanticVersion.ParseStrictRegexPattern, SemanticVersion.ParseStrictRegex), + new(SemanticVersion.ParseLooseRegexPattern, SemanticVersion.ParseLooseRegex), + new(SemanticVersion.ParseBuildMetaDataRegexPattern, SemanticVersion.ParseBuildMetaDataRegex), + new(SemanticVersion.FormatBuildMetaDataRegexPattern, SemanticVersion.FormatBuildMetaDataRegex), + new(SemanticVersion.ParsePreReleaseTagRegexPattern, SemanticVersion.ParsePreReleaseTagRegex), + // Trivia pattern unified: C# & F# share same underlying pattern; only map once under C# constant. + new(AssemblyVersion.CSharp.TriviaRegexPattern, AssemblyVersion.CSharp.TriviaRegex), + new(AssemblyVersion.CSharp.AttributeRegexPattern, AssemblyVersion.CSharp.AttributeRegex), + // F# Trivia pattern identical – Attribute differs, so include attribute pattern only. + new(AssemblyVersion.FSharp.AttributeRegexPattern, AssemblyVersion.FSharp.AttributeRegex), + new(AssemblyVersion.VisualBasic.TriviaRegexPattern, AssemblyVersion.VisualBasic.TriviaRegex), + new(AssemblyVersion.VisualBasic.AttributeRegexPattern, AssemblyVersion.VisualBasic.AttributeRegex) + ]; + + private static readonly ImmutableDictionary KnownRegexes = + Descriptors.ToImmutableDictionary(d => d.Pattern, d => d.Regex); + } + internal static partial class Configuration { [StringSyntax(StringSyntaxAttribute.Regex)] From 822fd5ea2ddf3c1950432ec2e409dc63dc98e3ef Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Mon, 17 Nov 2025 13:28:31 +0100 Subject: [PATCH 5/5] refactors regex patterns for better access refactors regex patterns to remove the nested `Common` class for easier access and cleaner code. --- .../ArgumentParserExtensions.cs | 2 +- .../Core/RegexPatternTests.cs | 6 +- src/GitVersion.Core/Core/RegexPatterns.cs | 151 +++++++++--------- .../Extensions/ConfigurationExtensions.cs | 2 +- .../Formatting/InputSanitizer.cs | 4 +- .../Formatting/StringFormatWithExtension.cs | 2 +- src/GitVersion.Core/Logging/Log.cs | 2 +- .../SemanticVersionFormatValues.cs | 2 +- 8 files changed, 84 insertions(+), 87 deletions(-) diff --git a/src/GitVersion.App/ArgumentParserExtensions.cs b/src/GitVersion.App/ArgumentParserExtensions.cs index 1e134f52cd..7d0dade040 100644 --- a/src/GitVersion.App/ArgumentParserExtensions.cs +++ b/src/GitVersion.App/ArgumentParserExtensions.cs @@ -41,7 +41,7 @@ public bool IsValidPath() public bool IsSwitchArgument() { - var patternRegex = RegexPatterns.Common.SwitchArgumentRegex; + var patternRegex = RegexPatterns.SwitchArgumentRegex; return value != null && (value.StartsWith('-') || value.StartsWith('/')) && !patternRegex.Match(value).Success; diff --git a/src/GitVersion.Core.Tests/Core/RegexPatternTests.cs b/src/GitVersion.Core.Tests/Core/RegexPatternTests.cs index 2cfac644ee..9ab32dd3a3 100644 --- a/src/GitVersion.Core.Tests/Core/RegexPatternTests.cs +++ b/src/GitVersion.Core.Tests/Core/RegexPatternTests.cs @@ -10,7 +10,7 @@ public class RegexPatternsTests [TestCase("foo:", false, null)] public void SwitchArgumentRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Common.SwitchArgumentRegex.Match(input); + var match = RegexPatterns.SwitchArgumentRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -21,7 +21,7 @@ public void SwitchArgumentRegex_MatchesExpected(string input, bool expected, str [TestCase("ftp://user:pass@host", false, null)] public void ObscurePasswordRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Common.ObscurePasswordRegex.Match(input); + var match = RegexPatterns.ObscurePasswordRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); @@ -34,7 +34,7 @@ public void ObscurePasswordRegex_MatchesExpected(string input, bool expected, st [TestCase("env:FOO", false, null)] public void ExpandTokensRegex_MatchesExpected(string input, bool expected, string? expectedCapture) { - var match = RegexPatterns.Common.ExpandTokensRegex.Match(input); + var match = RegexPatterns.ExpandTokensRegex.Match(input); match.Success.ShouldBe(expected); if (expected) match.Value.ShouldBe(expectedCapture); diff --git a/src/GitVersion.Core/Core/RegexPatterns.cs b/src/GitVersion.Core/Core/RegexPatterns.cs index add4489e4f..3b6ae834dd 100644 --- a/src/GitVersion.Core/Core/RegexPatterns.cs +++ b/src/GitVersion.Core/Core/RegexPatterns.cs @@ -10,112 +10,109 @@ internal static partial class RegexPatterns private const RegexOptions Options = RegexOptions.IgnoreCase | RegexOptions.Compiled; private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(2); // unified timeout for non-GeneratedRegex fallbacks - internal static partial class Common - { - [StringSyntax(StringSyntaxAttribute.Regex)] - internal const string SwitchArgumentRegexPattern = @"/\w+:"; + [StringSyntax(StringSyntaxAttribute.Regex)] + private const string SwitchArgumentRegexPattern = @"/\w+:"; - [StringSyntax(StringSyntaxAttribute.Regex)] - internal const string ObscurePasswordRegexPattern = "(https?://)(.+)(:.+@)"; + [StringSyntax(StringSyntaxAttribute.Regex)] + private const string ObscurePasswordRegexPattern = "(https?://)(.+)(:.+@)"; - [StringSyntax(StringSyntaxAttribute.Regex)] - internal const string ExpandTokensRegexPattern = - """ - \{ # Opening brace - (?: # Start of either env or member expression - env:(?!env:)(?[A-Za-z_][A-Za-z0-9_]*) # Only a single env: prefix, not followed by another env: - | # OR - (?[A-Za-z_][A-Za-z0-9_]*) # member/property name - (?: # Optional format specifier - :(?[A-Za-z0-9\.\-,]+) # Colon followed by format string (no spaces, ?, or }), format cannot contain colon - )? # Format is optional - ) # End group for env or member - (?: # Optional fallback group - \s*\?\?\s+ # '??' operator with optional whitespace: exactly two question marks for fallback - (?: # Fallback value alternatives: - (?\w+) # A single word fallback - | # OR - "(?[^"]*)" # A quoted string fallback - ) - )? # Fallback is optional - \} - """; + [StringSyntax(StringSyntaxAttribute.Regex)] + private const string ExpandTokensRegexPattern = + """ + \{ # Opening brace + (?: # Start of either env or member expression + env:(?!env:)(?[A-Za-z_][A-Za-z0-9_]*) # Only a single env: prefix, not followed by another env: + | # OR + (?[A-Za-z_][A-Za-z0-9_]*) # member/property name + (?: # Optional format specifier + :(?[A-Za-z0-9\.\-,]+) # Colon followed by format string (no spaces, ?, or }), format cannot contain colon + )? # Format is optional + ) # End group for env or member + (?: # Optional fallback group + \s*\?\?\s+ # '??' operator with optional whitespace: exactly two question marks for fallback + (?: # Fallback value alternatives: + (?\w+) # A single word fallback + | # OR + "(?[^"]*)" # A quoted string fallback + ) + )? # Fallback is optional + \} + """; - /// - /// Allow alphanumeric, underscore, colon (for custom format specification), hyphen, and dot - /// - [StringSyntax(StringSyntaxAttribute.Regex, Options)] - internal const string SanitizeEnvVarNameRegexPattern = @"^[A-Za-z0-9_:\-\.]+$"; + /// + /// Allow alphanumeric, underscore, colon (for custom format specification), hyphen, and dot + /// + [StringSyntax(StringSyntaxAttribute.Regex, Options)] + internal const string SanitizeEnvVarNameRegexPattern = @"^[A-Za-z0-9_:\-\.]+$"; - /// - /// Allow alphanumeric, underscore, and dot for property/field access - /// - [StringSyntax(StringSyntaxAttribute.Regex, Options)] - internal const string SanitizeMemberNameRegexPattern = @"^[A-Za-z0-9_\.]+$"; + /// + /// Allow alphanumeric, underscore, and dot for property/field access + /// + [StringSyntax(StringSyntaxAttribute.Regex, Options)] + internal const string SanitizeMemberNameRegexPattern = @"^[A-Za-z0-9_\.]+$"; - [StringSyntax(StringSyntaxAttribute.Regex, Options)] - internal const string SanitizeNameRegexPattern = "[^a-zA-Z0-9-]"; + [StringSyntax(StringSyntaxAttribute.Regex, Options)] + internal const string SanitizeNameRegexPattern = "[^a-zA-Z0-9-]"; #if NET9_0_OR_GREATER - [GeneratedRegex(SwitchArgumentRegexPattern, Options)] - public static partial Regex SwitchArgumentRegex { get; } + [GeneratedRegex(SwitchArgumentRegexPattern, Options)] + public static partial Regex SwitchArgumentRegex { get; } #else - [GeneratedRegex(SwitchArgumentRegexPattern, Options)] - private static partial Regex SwitchArgumentRegexImpl(); + [GeneratedRegex(SwitchArgumentRegexPattern, Options)] + private static partial Regex SwitchArgumentRegexImpl(); - public static Regex SwitchArgumentRegex { get; } = SwitchArgumentRegexImpl(); + public static Regex SwitchArgumentRegex { get; } = SwitchArgumentRegexImpl(); #endif #if NET9_0_OR_GREATER - [GeneratedRegex(ObscurePasswordRegexPattern, Options)] - public static partial Regex ObscurePasswordRegex { get; } + [GeneratedRegex(ObscurePasswordRegexPattern, Options)] + public static partial Regex ObscurePasswordRegex { get; } #else - [GeneratedRegex(ObscurePasswordRegexPattern, Options)] - private static partial Regex ObscurePasswordRegexImpl(); + [GeneratedRegex(ObscurePasswordRegexPattern, Options)] + private static partial Regex ObscurePasswordRegexImpl(); - public static Regex ObscurePasswordRegex { get; } = ObscurePasswordRegexImpl(); + public static Regex ObscurePasswordRegex { get; } = ObscurePasswordRegexImpl(); #endif #if NET9_0_OR_GREATER - [GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] - public static partial Regex ExpandTokensRegex { get; } + [GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] + public static partial Regex ExpandTokensRegex { get; } #else - [GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] - private static partial Regex ExpandTokensRegexImpl(); + [GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] + private static partial Regex ExpandTokensRegexImpl(); - public static Regex ExpandTokensRegex { get; } = ExpandTokensRegexImpl(); + public static Regex ExpandTokensRegex { get; } = ExpandTokensRegexImpl(); #endif #if NET9_0_OR_GREATER - [GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)] - public static partial Regex SanitizeEnvVarNameRegex { get; } + [GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)] + public static partial Regex SanitizeEnvVarNameRegex { get; } #else - [GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)] - private static partial Regex SanitizeEnvVarNameRegexImpl(); + [GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)] + private static partial Regex SanitizeEnvVarNameRegexImpl(); - public static Regex SanitizeEnvVarNameRegex { get; } = SanitizeEnvVarNameRegexImpl(); + public static Regex SanitizeEnvVarNameRegex { get; } = SanitizeEnvVarNameRegexImpl(); #endif #if NET9_0_OR_GREATER - [GeneratedRegex(SanitizeMemberNameRegexPattern, Options)] - public static partial Regex SanitizeMemberNameRegex { get; } + [GeneratedRegex(SanitizeMemberNameRegexPattern, Options)] + public static partial Regex SanitizeMemberNameRegex { get; } #else - [GeneratedRegex(SanitizeMemberNameRegexPattern, Options)] - private static partial Regex SanitizeMemberNameRegexImpl(); + [GeneratedRegex(SanitizeMemberNameRegexPattern, Options)] + private static partial Regex SanitizeMemberNameRegexImpl(); - public static Regex SanitizeMemberNameRegex { get; } = SanitizeMemberNameRegexImpl(); + public static Regex SanitizeMemberNameRegex { get; } = SanitizeMemberNameRegexImpl(); #endif #if NET9_0_OR_GREATER - [GeneratedRegex(SanitizeNameRegexPattern, Options)] - public static partial Regex SanitizeNameRegex { get; } + [GeneratedRegex(SanitizeNameRegexPattern, Options)] + public static partial Regex SanitizeNameRegex { get; } #else - [GeneratedRegex(SanitizeNameRegexPattern, Options)] - private static partial Regex SanitizeNameRegexImpl(); + [GeneratedRegex(SanitizeNameRegexPattern, Options)] + private static partial Regex SanitizeNameRegexImpl(); - public static Regex SanitizeNameRegex { get; } = SanitizeNameRegexImpl(); + public static Regex SanitizeNameRegex { get; } = SanitizeNameRegexImpl(); #endif - } public static class Cache { @@ -137,12 +134,12 @@ public static Regex GetOrAdd([StringSyntax(StringSyntaxAttribute.Regex)] string // Central descriptor list – single source of truth for known patterns. Order not significant. private static readonly RegexDescriptor[] Descriptors = [ - new(Common.SwitchArgumentRegexPattern, Common.SwitchArgumentRegex), - new(Common.ObscurePasswordRegexPattern, Common.ObscurePasswordRegex), - new(Common.ExpandTokensRegexPattern, Common.ExpandTokensRegex), - new(Common.SanitizeEnvVarNameRegexPattern, Common.SanitizeEnvVarNameRegex), - new(Common.SanitizeMemberNameRegexPattern, Common.SanitizeMemberNameRegex), - new(Common.SanitizeNameRegexPattern, Common.SanitizeNameRegex), + new(SwitchArgumentRegexPattern, SwitchArgumentRegex), + new(ObscurePasswordRegexPattern, ObscurePasswordRegex), + new(ExpandTokensRegexPattern, ExpandTokensRegex), + new(SanitizeEnvVarNameRegexPattern, SanitizeEnvVarNameRegex), + new(SanitizeMemberNameRegexPattern, SanitizeMemberNameRegex), + new(SanitizeNameRegexPattern, SanitizeNameRegex), new(Configuration.DefaultTagPrefixRegexPattern, Configuration.DefaultTagPrefixRegex), new(Configuration.DefaultVersionInBranchRegexPattern, Configuration.DefaultVersionInBranchRegex), new(Configuration.MainBranchRegexPattern, Configuration.MainBranchRegex), diff --git a/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs b/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs index 3830bf8962..68e77ee4fd 100644 --- a/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs +++ b/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs @@ -118,7 +118,7 @@ private static bool ShouldBeIgnored(ICommit commit, IIgnoreConfiguration ignore) foreach (var groupName in regex.GetGroupNames()) { var groupValue = match.Groups[groupName].Value; - Lazy escapedGroupValueLazy = new(() => groupValue.RegexReplace(RegexPatterns.Common.SanitizeNameRegexPattern, "-")); + Lazy escapedGroupValueLazy = new(() => groupValue.RegexReplace(RegexPatterns.SanitizeNameRegexPattern, "-")); var placeholder = $"{{{groupName}}}"; int index, startIndex = 0; while ((index = label.IndexOf(placeholder, startIndex, StringComparison.InvariantCulture)) >= 0) diff --git a/src/GitVersion.Core/Formatting/InputSanitizer.cs b/src/GitVersion.Core/Formatting/InputSanitizer.cs index a676ec5540..f0f043c05b 100644 --- a/src/GitVersion.Core/Formatting/InputSanitizer.cs +++ b/src/GitVersion.Core/Formatting/InputSanitizer.cs @@ -26,7 +26,7 @@ public string SanitizeEnvVarName(string name) if (name.Length > 200) throw new ArgumentException($"Environment variable name too long: '{name[..20]}...'"); - if (!RegexPatterns.Cache.GetOrAdd(RegexPatterns.Common.SanitizeEnvVarNameRegexPattern).IsMatch(name)) + if (!RegexPatterns.Cache.GetOrAdd(RegexPatterns.SanitizeEnvVarNameRegexPattern).IsMatch(name)) throw new ArgumentException($"Environment variable name contains disallowed characters: '{name}'"); return name; @@ -40,7 +40,7 @@ public string SanitizeMemberName(string memberName) if (memberName.Length > 100) throw new ArgumentException($"Member name too long: '{memberName[..20]}...'"); - if (!RegexPatterns.Cache.GetOrAdd(RegexPatterns.Common.SanitizeMemberNameRegexPattern).IsMatch(memberName)) + if (!RegexPatterns.Cache.GetOrAdd(RegexPatterns.SanitizeMemberNameRegexPattern).IsMatch(memberName)) throw new ArgumentException($"Member name contains disallowed characters: '{memberName}'"); return memberName; diff --git a/src/GitVersion.Core/Formatting/StringFormatWithExtension.cs b/src/GitVersion.Core/Formatting/StringFormatWithExtension.cs index 382b8dfedc..06154aefe5 100644 --- a/src/GitVersion.Core/Formatting/StringFormatWithExtension.cs +++ b/src/GitVersion.Core/Formatting/StringFormatWithExtension.cs @@ -45,7 +45,7 @@ public string FormatWith(T? source, IEnvironment environment) var result = new StringBuilder(); var lastIndex = 0; - foreach (var match in RegexPatterns.Common.ExpandTokensRegex.Matches(template).Cast()) + foreach (var match in RegexPatterns.ExpandTokensRegex.Matches(template).Cast()) { var replacement = EvaluateMatch(match, source, environment); result.Append(template, lastIndex, match.Index - lastIndex); diff --git a/src/GitVersion.Core/Logging/Log.cs b/src/GitVersion.Core/Logging/Log.cs index af82183a0e..e18eef1453 100644 --- a/src/GitVersion.Core/Logging/Log.cs +++ b/src/GitVersion.Core/Logging/Log.cs @@ -58,7 +58,7 @@ public IDisposable IndentLog(string operationDescription) private string FormatMessage(string message, string level) { - var obscuredMessage = RegexPatterns.Common.ObscurePasswordRegex.Replace(message, "$1$2:*******@"); + var obscuredMessage = RegexPatterns.ObscurePasswordRegex.Replace(message, "$1$2:*******@"); var timestamp = $"{DateTime.Now:yy-MM-dd H:mm:ss:ff}"; return string.Format(CultureInfo.InvariantCulture, "{0}{1} [{2}] {3}", this.currentIndentation, level, timestamp, obscuredMessage); } diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormatValues.cs b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormatValues.cs index 64913a061c..981a45aa8a 100644 --- a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormatValues.cs +++ b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormatValues.cs @@ -42,7 +42,7 @@ public class SemanticVersionFormatValues(SemanticVersion semver, IGitVersionConf public string? BranchName => semver.BuildMetaData.Branch; - public string? EscapedBranchName => semver.BuildMetaData.Branch?.RegexReplace(RegexPatterns.Common.SanitizeNameRegexPattern, "-"); + public string? EscapedBranchName => semver.BuildMetaData.Branch?.RegexReplace(RegexPatterns.SanitizeNameRegexPattern, "-"); public string? Sha => semver.BuildMetaData.Sha;