Skip to content

Commit 822fd5e

Browse files
committed
refactors regex patterns for better access
refactors regex patterns to remove the nested `Common` class for easier access and cleaner code.
1 parent aeb6b7e commit 822fd5e

File tree

8 files changed

+84
-87
lines changed

8 files changed

+84
-87
lines changed

src/GitVersion.App/ArgumentParserExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public bool IsValidPath()
4141

4242
public bool IsSwitchArgument()
4343
{
44-
var patternRegex = RegexPatterns.Common.SwitchArgumentRegex;
44+
var patternRegex = RegexPatterns.SwitchArgumentRegex;
4545
return value != null
4646
&& (value.StartsWith('-') || value.StartsWith('/'))
4747
&& !patternRegex.Match(value).Success;

src/GitVersion.Core.Tests/Core/RegexPatternTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class RegexPatternsTests
1010
[TestCase("foo:", false, null)]
1111
public void SwitchArgumentRegex_MatchesExpected(string input, bool expected, string? expectedCapture)
1212
{
13-
var match = RegexPatterns.Common.SwitchArgumentRegex.Match(input);
13+
var match = RegexPatterns.SwitchArgumentRegex.Match(input);
1414
match.Success.ShouldBe(expected);
1515
if (expected)
1616
match.Value.ShouldBe(expectedCapture);
@@ -21,7 +21,7 @@ public void SwitchArgumentRegex_MatchesExpected(string input, bool expected, str
2121
[TestCase("ftp://user:pass@host", false, null)]
2222
public void ObscurePasswordRegex_MatchesExpected(string input, bool expected, string? expectedCapture)
2323
{
24-
var match = RegexPatterns.Common.ObscurePasswordRegex.Match(input);
24+
var match = RegexPatterns.ObscurePasswordRegex.Match(input);
2525
match.Success.ShouldBe(expected);
2626
if (expected)
2727
match.Value.ShouldBe(expectedCapture);
@@ -34,7 +34,7 @@ public void ObscurePasswordRegex_MatchesExpected(string input, bool expected, st
3434
[TestCase("env:FOO", false, null)]
3535
public void ExpandTokensRegex_MatchesExpected(string input, bool expected, string? expectedCapture)
3636
{
37-
var match = RegexPatterns.Common.ExpandTokensRegex.Match(input);
37+
var match = RegexPatterns.ExpandTokensRegex.Match(input);
3838
match.Success.ShouldBe(expected);
3939
if (expected)
4040
match.Value.ShouldBe(expectedCapture);

src/GitVersion.Core/Core/RegexPatterns.cs

Lines changed: 74 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -10,112 +10,109 @@ internal static partial class RegexPatterns
1010
private const RegexOptions Options = RegexOptions.IgnoreCase | RegexOptions.Compiled;
1111
private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(2); // unified timeout for non-GeneratedRegex fallbacks
1212

13-
internal static partial class Common
14-
{
15-
[StringSyntax(StringSyntaxAttribute.Regex)]
16-
internal const string SwitchArgumentRegexPattern = @"/\w+:";
13+
[StringSyntax(StringSyntaxAttribute.Regex)]
14+
private const string SwitchArgumentRegexPattern = @"/\w+:";
1715

18-
[StringSyntax(StringSyntaxAttribute.Regex)]
19-
internal const string ObscurePasswordRegexPattern = "(https?://)(.+)(:.+@)";
16+
[StringSyntax(StringSyntaxAttribute.Regex)]
17+
private const string ObscurePasswordRegexPattern = "(https?://)(.+)(:.+@)";
2018

21-
[StringSyntax(StringSyntaxAttribute.Regex)]
22-
internal const string ExpandTokensRegexPattern =
23-
"""
24-
\{ # Opening brace
25-
(?: # Start of either env or member expression
26-
env:(?!env:)(?<envvar>[A-Za-z_][A-Za-z0-9_]*) # Only a single env: prefix, not followed by another env:
27-
| # OR
28-
(?<member>[A-Za-z_][A-Za-z0-9_]*) # member/property name
29-
(?: # Optional format specifier
30-
:(?<format>[A-Za-z0-9\.\-,]+) # Colon followed by format string (no spaces, ?, or }), format cannot contain colon
31-
)? # Format is optional
32-
) # End group for env or member
33-
(?: # Optional fallback group
34-
\s*\?\?\s+ # '??' operator with optional whitespace: exactly two question marks for fallback
35-
(?: # Fallback value alternatives:
36-
(?<fallback>\w+) # A single word fallback
37-
| # OR
38-
"(?<fallback>[^"]*)" # A quoted string fallback
39-
)
40-
)? # Fallback is optional
41-
\}
42-
""";
19+
[StringSyntax(StringSyntaxAttribute.Regex)]
20+
private const string ExpandTokensRegexPattern =
21+
"""
22+
\{ # Opening brace
23+
(?: # Start of either env or member expression
24+
env:(?!env:)(?<envvar>[A-Za-z_][A-Za-z0-9_]*) # Only a single env: prefix, not followed by another env:
25+
| # OR
26+
(?<member>[A-Za-z_][A-Za-z0-9_]*) # member/property name
27+
(?: # Optional format specifier
28+
:(?<format>[A-Za-z0-9\.\-,]+) # Colon followed by format string (no spaces, ?, or }), format cannot contain colon
29+
)? # Format is optional
30+
) # End group for env or member
31+
(?: # Optional fallback group
32+
\s*\?\?\s+ # '??' operator with optional whitespace: exactly two question marks for fallback
33+
(?: # Fallback value alternatives:
34+
(?<fallback>\w+) # A single word fallback
35+
| # OR
36+
"(?<fallback>[^"]*)" # A quoted string fallback
37+
)
38+
)? # Fallback is optional
39+
\}
40+
""";
4341

44-
/// <summary>
45-
/// Allow alphanumeric, underscore, colon (for custom format specification), hyphen, and dot
46-
/// </summary>
47-
[StringSyntax(StringSyntaxAttribute.Regex, Options)]
48-
internal const string SanitizeEnvVarNameRegexPattern = @"^[A-Za-z0-9_:\-\.]+$";
42+
/// <summary>
43+
/// Allow alphanumeric, underscore, colon (for custom format specification), hyphen, and dot
44+
/// </summary>
45+
[StringSyntax(StringSyntaxAttribute.Regex, Options)]
46+
internal const string SanitizeEnvVarNameRegexPattern = @"^[A-Za-z0-9_:\-\.]+$";
4947

50-
/// <summary>
51-
/// Allow alphanumeric, underscore, and dot for property/field access
52-
/// </summary>
53-
[StringSyntax(StringSyntaxAttribute.Regex, Options)]
54-
internal const string SanitizeMemberNameRegexPattern = @"^[A-Za-z0-9_\.]+$";
48+
/// <summary>
49+
/// Allow alphanumeric, underscore, and dot for property/field access
50+
/// </summary>
51+
[StringSyntax(StringSyntaxAttribute.Regex, Options)]
52+
internal const string SanitizeMemberNameRegexPattern = @"^[A-Za-z0-9_\.]+$";
5553

56-
[StringSyntax(StringSyntaxAttribute.Regex, Options)]
57-
internal const string SanitizeNameRegexPattern = "[^a-zA-Z0-9-]";
54+
[StringSyntax(StringSyntaxAttribute.Regex, Options)]
55+
internal const string SanitizeNameRegexPattern = "[^a-zA-Z0-9-]";
5856

5957
#if NET9_0_OR_GREATER
60-
[GeneratedRegex(SwitchArgumentRegexPattern, Options)]
61-
public static partial Regex SwitchArgumentRegex { get; }
58+
[GeneratedRegex(SwitchArgumentRegexPattern, Options)]
59+
public static partial Regex SwitchArgumentRegex { get; }
6260
#else
63-
[GeneratedRegex(SwitchArgumentRegexPattern, Options)]
64-
private static partial Regex SwitchArgumentRegexImpl();
61+
[GeneratedRegex(SwitchArgumentRegexPattern, Options)]
62+
private static partial Regex SwitchArgumentRegexImpl();
6563

66-
public static Regex SwitchArgumentRegex { get; } = SwitchArgumentRegexImpl();
64+
public static Regex SwitchArgumentRegex { get; } = SwitchArgumentRegexImpl();
6765
#endif
6866

6967
#if NET9_0_OR_GREATER
70-
[GeneratedRegex(ObscurePasswordRegexPattern, Options)]
71-
public static partial Regex ObscurePasswordRegex { get; }
68+
[GeneratedRegex(ObscurePasswordRegexPattern, Options)]
69+
public static partial Regex ObscurePasswordRegex { get; }
7270
#else
73-
[GeneratedRegex(ObscurePasswordRegexPattern, Options)]
74-
private static partial Regex ObscurePasswordRegexImpl();
71+
[GeneratedRegex(ObscurePasswordRegexPattern, Options)]
72+
private static partial Regex ObscurePasswordRegexImpl();
7573

76-
public static Regex ObscurePasswordRegex { get; } = ObscurePasswordRegexImpl();
74+
public static Regex ObscurePasswordRegex { get; } = ObscurePasswordRegexImpl();
7775
#endif
7876

7977
#if NET9_0_OR_GREATER
80-
[GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)]
81-
public static partial Regex ExpandTokensRegex { get; }
78+
[GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)]
79+
public static partial Regex ExpandTokensRegex { get; }
8280
#else
83-
[GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)]
84-
private static partial Regex ExpandTokensRegexImpl();
81+
[GeneratedRegex(ExpandTokensRegexPattern, RegexOptions.IgnorePatternWhitespace | Options)]
82+
private static partial Regex ExpandTokensRegexImpl();
8583

86-
public static Regex ExpandTokensRegex { get; } = ExpandTokensRegexImpl();
84+
public static Regex ExpandTokensRegex { get; } = ExpandTokensRegexImpl();
8785
#endif
8886

8987
#if NET9_0_OR_GREATER
90-
[GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)]
91-
public static partial Regex SanitizeEnvVarNameRegex { get; }
88+
[GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)]
89+
public static partial Regex SanitizeEnvVarNameRegex { get; }
9290
#else
93-
[GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)]
94-
private static partial Regex SanitizeEnvVarNameRegexImpl();
91+
[GeneratedRegex(SanitizeEnvVarNameRegexPattern, Options)]
92+
private static partial Regex SanitizeEnvVarNameRegexImpl();
9593

96-
public static Regex SanitizeEnvVarNameRegex { get; } = SanitizeEnvVarNameRegexImpl();
94+
public static Regex SanitizeEnvVarNameRegex { get; } = SanitizeEnvVarNameRegexImpl();
9795
#endif
9896

9997
#if NET9_0_OR_GREATER
100-
[GeneratedRegex(SanitizeMemberNameRegexPattern, Options)]
101-
public static partial Regex SanitizeMemberNameRegex { get; }
98+
[GeneratedRegex(SanitizeMemberNameRegexPattern, Options)]
99+
public static partial Regex SanitizeMemberNameRegex { get; }
102100
#else
103-
[GeneratedRegex(SanitizeMemberNameRegexPattern, Options)]
104-
private static partial Regex SanitizeMemberNameRegexImpl();
101+
[GeneratedRegex(SanitizeMemberNameRegexPattern, Options)]
102+
private static partial Regex SanitizeMemberNameRegexImpl();
105103

106-
public static Regex SanitizeMemberNameRegex { get; } = SanitizeMemberNameRegexImpl();
104+
public static Regex SanitizeMemberNameRegex { get; } = SanitizeMemberNameRegexImpl();
107105
#endif
108106

109107
#if NET9_0_OR_GREATER
110-
[GeneratedRegex(SanitizeNameRegexPattern, Options)]
111-
public static partial Regex SanitizeNameRegex { get; }
108+
[GeneratedRegex(SanitizeNameRegexPattern, Options)]
109+
public static partial Regex SanitizeNameRegex { get; }
112110
#else
113-
[GeneratedRegex(SanitizeNameRegexPattern, Options)]
114-
private static partial Regex SanitizeNameRegexImpl();
111+
[GeneratedRegex(SanitizeNameRegexPattern, Options)]
112+
private static partial Regex SanitizeNameRegexImpl();
115113

116-
public static Regex SanitizeNameRegex { get; } = SanitizeNameRegexImpl();
114+
public static Regex SanitizeNameRegex { get; } = SanitizeNameRegexImpl();
117115
#endif
118-
}
119116

120117
public static class Cache
121118
{
@@ -137,12 +134,12 @@ public static Regex GetOrAdd([StringSyntax(StringSyntaxAttribute.Regex)] string
137134
// Central descriptor list – single source of truth for known patterns. Order not significant.
138135
private static readonly RegexDescriptor[] Descriptors =
139136
[
140-
new(Common.SwitchArgumentRegexPattern, Common.SwitchArgumentRegex),
141-
new(Common.ObscurePasswordRegexPattern, Common.ObscurePasswordRegex),
142-
new(Common.ExpandTokensRegexPattern, Common.ExpandTokensRegex),
143-
new(Common.SanitizeEnvVarNameRegexPattern, Common.SanitizeEnvVarNameRegex),
144-
new(Common.SanitizeMemberNameRegexPattern, Common.SanitizeMemberNameRegex),
145-
new(Common.SanitizeNameRegexPattern, Common.SanitizeNameRegex),
137+
new(SwitchArgumentRegexPattern, SwitchArgumentRegex),
138+
new(ObscurePasswordRegexPattern, ObscurePasswordRegex),
139+
new(ExpandTokensRegexPattern, ExpandTokensRegex),
140+
new(SanitizeEnvVarNameRegexPattern, SanitizeEnvVarNameRegex),
141+
new(SanitizeMemberNameRegexPattern, SanitizeMemberNameRegex),
142+
new(SanitizeNameRegexPattern, SanitizeNameRegex),
146143
new(Configuration.DefaultTagPrefixRegexPattern, Configuration.DefaultTagPrefixRegex),
147144
new(Configuration.DefaultVersionInBranchRegexPattern, Configuration.DefaultVersionInBranchRegex),
148145
new(Configuration.MainBranchRegexPattern, Configuration.MainBranchRegex),

src/GitVersion.Core/Extensions/ConfigurationExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ private static bool ShouldBeIgnored(ICommit commit, IIgnoreConfiguration ignore)
118118
foreach (var groupName in regex.GetGroupNames())
119119
{
120120
var groupValue = match.Groups[groupName].Value;
121-
Lazy<string> escapedGroupValueLazy = new(() => groupValue.RegexReplace(RegexPatterns.Common.SanitizeNameRegexPattern, "-"));
121+
Lazy<string> escapedGroupValueLazy = new(() => groupValue.RegexReplace(RegexPatterns.SanitizeNameRegexPattern, "-"));
122122
var placeholder = $"{{{groupName}}}";
123123
int index, startIndex = 0;
124124
while ((index = label.IndexOf(placeholder, startIndex, StringComparison.InvariantCulture)) >= 0)

src/GitVersion.Core/Formatting/InputSanitizer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public string SanitizeEnvVarName(string name)
2626
if (name.Length > 200)
2727
throw new ArgumentException($"Environment variable name too long: '{name[..20]}...'");
2828

29-
if (!RegexPatterns.Cache.GetOrAdd(RegexPatterns.Common.SanitizeEnvVarNameRegexPattern).IsMatch(name))
29+
if (!RegexPatterns.Cache.GetOrAdd(RegexPatterns.SanitizeEnvVarNameRegexPattern).IsMatch(name))
3030
throw new ArgumentException($"Environment variable name contains disallowed characters: '{name}'");
3131

3232
return name;
@@ -40,7 +40,7 @@ public string SanitizeMemberName(string memberName)
4040
if (memberName.Length > 100)
4141
throw new ArgumentException($"Member name too long: '{memberName[..20]}...'");
4242

43-
if (!RegexPatterns.Cache.GetOrAdd(RegexPatterns.Common.SanitizeMemberNameRegexPattern).IsMatch(memberName))
43+
if (!RegexPatterns.Cache.GetOrAdd(RegexPatterns.SanitizeMemberNameRegexPattern).IsMatch(memberName))
4444
throw new ArgumentException($"Member name contains disallowed characters: '{memberName}'");
4545

4646
return memberName;

src/GitVersion.Core/Formatting/StringFormatWithExtension.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public string FormatWith<T>(T? source, IEnvironment environment)
4545
var result = new StringBuilder();
4646
var lastIndex = 0;
4747

48-
foreach (var match in RegexPatterns.Common.ExpandTokensRegex.Matches(template).Cast<Match>())
48+
foreach (var match in RegexPatterns.ExpandTokensRegex.Matches(template).Cast<Match>())
4949
{
5050
var replacement = EvaluateMatch(match, source, environment);
5151
result.Append(template, lastIndex, match.Index - lastIndex);

src/GitVersion.Core/Logging/Log.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public IDisposable IndentLog(string operationDescription)
5858

5959
private string FormatMessage(string message, string level)
6060
{
61-
var obscuredMessage = RegexPatterns.Common.ObscurePasswordRegex.Replace(message, "$1$2:*******@");
61+
var obscuredMessage = RegexPatterns.ObscurePasswordRegex.Replace(message, "$1$2:*******@");
6262
var timestamp = $"{DateTime.Now:yy-MM-dd H:mm:ss:ff}";
6363
return string.Format(CultureInfo.InvariantCulture, "{0}{1} [{2}] {3}", this.currentIndentation, level, timestamp, obscuredMessage);
6464
}

src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormatValues.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class SemanticVersionFormatValues(SemanticVersion semver, IGitVersionConf
4242

4343
public string? BranchName => semver.BuildMetaData.Branch;
4444

45-
public string? EscapedBranchName => semver.BuildMetaData.Branch?.RegexReplace(RegexPatterns.Common.SanitizeNameRegexPattern, "-");
45+
public string? EscapedBranchName => semver.BuildMetaData.Branch?.RegexReplace(RegexPatterns.SanitizeNameRegexPattern, "-");
4646

4747
public string? Sha => semver.BuildMetaData.Sha;
4848

0 commit comments

Comments
 (0)