diff --git a/src/GitVersion.App/ArgumentParserExtensions.cs b/src/GitVersion.App/ArgumentParserExtensions.cs index 073983b420..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 d56739de7f..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); @@ -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..3b6ae834dd 100644 --- a/src/GitVersion.Core/Core/RegexPatterns.cs +++ b/src/GitVersion.Core/Core/RegexPatterns.cs @@ -8,6 +8,111 @@ 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 + + [StringSyntax(StringSyntaxAttribute.Regex)] + private const string SwitchArgumentRegexPattern = @"/\w+:"; + + [StringSyntax(StringSyntaxAttribute.Regex)] + private const string ObscurePasswordRegexPattern = "(https?://)(.+)(:.+@)"; + + [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, 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-]"; + +#if NET9_0_OR_GREATER + [GeneratedRegex(SwitchArgumentRegexPattern, Options)] + public static partial Regex SwitchArgumentRegex { get; } +#else + [GeneratedRegex(SwitchArgumentRegexPattern, Options)] + private static partial Regex SwitchArgumentRegexImpl(); + + public static Regex SwitchArgumentRegex { get; } = SwitchArgumentRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(ObscurePasswordRegexPattern, Options)] + public static partial Regex ObscurePasswordRegex { get; } +#else + [GeneratedRegex(ObscurePasswordRegexPattern, Options)] + private static partial Regex ObscurePasswordRegexImpl(); + + public static Regex ObscurePasswordRegex { get; } = ObscurePasswordRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] + public static partial Regex ExpandTokensRegex { get; } +#else + [GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] + private static partial Regex ExpandTokensRegexImpl(); + + public static Regex ExpandTokensRegex { get; } = ExpandTokensRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)] + public static partial Regex SanitizeEnvVarNameRegex { get; } +#else + [GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)] + private static partial Regex SanitizeEnvVarNameRegexImpl(); + + public static Regex SanitizeEnvVarNameRegex { get; } = SanitizeEnvVarNameRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(SanitizeMemberNameRegexPattern, Options)] + public static partial Regex SanitizeMemberNameRegex { get; } +#else + [GeneratedRegex(SanitizeMemberNameRegexPattern, Options)] + private static partial Regex SanitizeMemberNameRegexImpl(); + + public static Regex SanitizeMemberNameRegex { get; } = SanitizeMemberNameRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(SanitizeNameRegexPattern, Options)] + public static partial Regex SanitizeNameRegex { get; } +#else + [GeneratedRegex(SanitizeNameRegexPattern, Options)] + private static partial Regex SanitizeNameRegexImpl(); + + public static Regex SanitizeNameRegex { get; } = SanitizeNameRegexImpl(); +#endif public static class Cache { @@ -18,127 +123,69 @@ public static Regex GetOrAdd([StringSyntax(StringSyntaxAttribute.Regex)] string ArgumentNullException.ThrowIfNull(pattern); return cache.GetOrAdd(pattern, key => - KnownRegexes.TryGetValue(key, out var factory) - ? factory() - : new Regex(key, Options)); + KnownRegexes.TryGetValue(key, out var regex) + ? regex + : new Regex(key, Options, DefaultTimeout)); // now uses timeout for safety } - 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(); - } - - internal static partial class Common - { - [StringSyntax(StringSyntaxAttribute.Regex)] - internal const string SwitchArgumentRegexPattern = @"/\w+:"; - - [StringSyntax(StringSyntaxAttribute.Regex)] - internal 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 - \} - """; - - /// - /// 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_\.]+$"; - - [StringSyntax(StringSyntaxAttribute.Regex, Options)] - internal const string SanitizeNameRegexPattern = "[^a-zA-Z0-9-]"; - - [GeneratedRegex(SwitchArgumentRegexPattern, Options)] - public static partial Regex SwitchArgumentRegex(); - - [GeneratedRegex(ObscurePasswordRegexPattern, Options)] - public static partial Regex ObscurePasswordRegex(); - - [GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)] - public static partial Regex ExpandTokensRegex(); - - [GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)] - public static partial Regex SanitizeEnvVarNameRegex(); - - [GeneratedRegex(SanitizeMemberNameRegexPattern, Options)] - public static partial Regex SanitizeMemberNameRegex(); - - [GeneratedRegex(SanitizeNameRegexPattern, Options)] - public static partial Regex SanitizeNameRegex(); + // 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(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), + 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 @@ -173,35 +220,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 { get; } +#else [GeneratedRegex(DefaultTagPrefixRegexPattern, Options)] - public static partial Regex DefaultTagPrefixRegex(); + private static partial Regex DefaultTagPrefixRegexImpl(); + + public static Regex DefaultTagPrefixRegex { get; } = DefaultTagPrefixRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(DefaultVersionInBranchRegexPattern, Options)] - public static partial Regex DefaultVersionInBranchRegex(); + public static partial Regex DefaultVersionInBranchRegex { get; } +#else + [GeneratedRegex(DefaultVersionInBranchRegexPattern, Options)] + private static partial Regex DefaultVersionInBranchRegexImpl(); + + public static Regex DefaultVersionInBranchRegex { get; } = 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 { get; } = MainBranchRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(DevelopBranchRegexPattern, Options)] + public static partial Regex DevelopBranchRegex { get; } +#else [GeneratedRegex(DevelopBranchRegexPattern, Options)] - public static partial Regex DevelopBranchRegex(); + private static partial Regex DevelopBranchRegexImpl(); + + public static Regex DevelopBranchRegex { get; } = DevelopBranchRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(ReleaseBranchRegexPattern, Options)] - public static partial Regex ReleaseBranchRegex(); + public static partial Regex ReleaseBranchRegex { get; } +#else + [GeneratedRegex(ReleaseBranchRegexPattern, Options)] + private static partial Regex ReleaseBranchRegexImpl(); + + public static Regex ReleaseBranchRegex { get; } = 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 { get; } = FeatureBranchRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(PullRequestBranchRegexPattern, Options)] + public static partial Regex PullRequestBranchRegex { get; } +#else [GeneratedRegex(PullRequestBranchRegexPattern, Options)] - public static partial Regex PullRequestBranchRegex(); + private static partial Regex PullRequestBranchRegexImpl(); + + public static Regex PullRequestBranchRegex { get; } = PullRequestBranchRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(HotfixBranchRegexPattern, Options)] - public static partial Regex HotfixBranchRegex(); + public static partial Regex HotfixBranchRegex { get; } +#else + [GeneratedRegex(HotfixBranchRegexPattern, Options)] + private static partial Regex HotfixBranchRegexImpl(); + + public static Regex HotfixBranchRegex { get; } = 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 { get; } = SupportBranchRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(UnknownBranchRegexPattern, Options)] + public static partial Regex UnknownBranchRegex { get; } +#else [GeneratedRegex(UnknownBranchRegexPattern, Options)] - public static partial Regex UnknownBranchRegex(); + private static partial Regex UnknownBranchRegexImpl(); + + public static Regex UnknownBranchRegex { get; } = UnknownBranchRegexImpl(); +#endif } internal static partial class MergeMessage @@ -230,29 +347,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 { get; } = DefaultMergeMessageRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(SmartGitMergeMessageRegexPattern, Options)] - public static partial Regex SmartGitMergeMessageRegex(); + public static partial Regex SmartGitMergeMessageRegex { get; } +#else + [GeneratedRegex(SmartGitMergeMessageRegexPattern, Options)] + private static partial Regex SmartGitMergeMessageRegexImpl(); + + public static Regex SmartGitMergeMessageRegex { get; } = SmartGitMergeMessageRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(BitBucketPullMergeMessageRegexPattern, Options)] + public static partial Regex BitBucketPullMergeMessageRegex { get; } +#else [GeneratedRegex(BitBucketPullMergeMessageRegexPattern, Options)] - public static partial Regex BitBucketPullMergeMessageRegex(); + private static partial Regex BitBucketPullMergeMessageRegexImpl(); + public static Regex BitBucketPullMergeMessageRegex { get; } = 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 { get; } = BitBucketPullv7MergeMessageRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(BitBucketCloudPullMergeMessageRegexPattern, Options)] - public static partial Regex BitBucketCloudPullMergeMessageRegex(); + public static partial Regex BitBucketCloudPullMergeMessageRegex { get; } +#else + [GeneratedRegex(BitBucketCloudPullMergeMessageRegexPattern, Options)] + private static partial Regex BitBucketCloudPullMergeMessageRegexImpl(); + + public static Regex BitBucketCloudPullMergeMessageRegex { get; } = 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 { get; } = 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 { get; } = 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 { get; } = AzureDevOpsPullMergeMessageRegexImpl(); +#endif } internal static partial class Output @@ -281,29 +454,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(); + public static partial Regex AssemblyVersionRegex { get; } +#else + [GeneratedRegex(AssemblyVersionRegexPattern, Options)] + private static partial Regex AssemblyVersionRegexImpl(); + + public static Regex AssemblyVersionRegex { get; } = AssemblyVersionRegexImpl(); +#endif +#if NET9_0_OR_GREATER + [GeneratedRegex(AssemblyInfoVersionRegexPattern, Options)] + public static partial Regex AssemblyInfoVersionRegex { get; } +#else [GeneratedRegex(AssemblyInfoVersionRegexPattern, Options)] - public static partial Regex AssemblyInfoVersionRegex(); + private static partial Regex AssemblyInfoVersionRegexImpl(); + public static Regex AssemblyInfoVersionRegex { get; } = 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 { get; } = 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 { get; } = 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 { get; } = 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 { get; } = 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 { get; } = 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 { get; } = SanitizeAssemblyInfoRegexImpl(); +#endif } internal static partial class VersionCalculation @@ -320,17 +549,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 { get; } = 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 { get; } = 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 { get; } = 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 { get; } = DefaultNoBumpRegexImpl(); +#endif } internal static partial class SemanticVersion @@ -351,20 +608,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 { get; } = 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 { get; } = ParseLooseRegexImpl(); +#endif +#if NET9_0_OR_GREATER [GeneratedRegex(ParseBuildMetaDataRegexPattern, Options)] - public static partial Regex ParseBuildMetaDataRegex(); + public static partial Regex ParseBuildMetaDataRegex { get; } +#else + [GeneratedRegex(ParseBuildMetaDataRegexPattern, Options)] + private static partial Regex ParseBuildMetaDataRegexImpl(); + + public static Regex ParseBuildMetaDataRegex { get; } = 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 { get; } = FormatBuildMetaDataRegexImpl(); +#endif + +#if NET9_0_OR_GREATER + [GeneratedRegex(ParsePreReleaseTagRegexPattern, Options)] + public static partial Regex ParsePreReleaseTagRegex { get; } +#else [GeneratedRegex(ParsePreReleaseTagRegexPattern, Options)] - public static partial Regex ParsePreReleaseTagRegex(); + private static partial Regex ParsePreReleaseTagRegexImpl(); + + public static Regex ParsePreReleaseTagRegex { get; } = ParsePreReleaseTagRegexImpl(); +#endif } internal static partial class AssemblyVersion @@ -389,22 +681,31 @@ 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(); + public static partial Regex TriviaRegex { get; } +#else + [GeneratedRegex(TriviaRegexPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | Options)] + private static partial Regex TriviaRegexImpl(); + + public static Regex TriviaRegex { get; } = 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 { get; } = AttributeRegexImpl(); +#endif } 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 = @@ -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 { get; } = 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 { get; } = 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 { get; } = 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 { get; } = AttributeRegexImpl(); +#endif } } } 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 a055b7b53b..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 05de5b44c9..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/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.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; 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)