From 4531e3cb8be6c025cca2267a830f261533895bab Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Fri, 31 Mar 2023 17:44:51 +0200 Subject: [PATCH 01/14] Fix bug: VersionInBranchNameVersionStrategy only considers the release branch --- docs/input/docs/reference/configuration.md | 10 ++++-- ...riteOutEffectiveConfiguration.approved.txt | 2 ++ .../IntegrationTests/OtherBranchScenarios.cs | 11 ++++-- .../MergeMessageTests.cs | 8 ++--- .../MergeMessageBaseVersionStrategyTests.cs | 7 ---- ...ionInBranchNameBaseVersionStrategyTests.cs | 7 ++-- .../Configuration/ConfigurationBuilderBase.cs | 9 +++++ .../Configuration/ConfigurationConstants.cs | 1 + .../Configuration/EffectiveConfiguration.cs | 4 +++ .../GitFlowConfigurationBuilder.cs | 2 ++ .../GitHubFlowConfigurationBuilder.cs | 1 + .../Configuration/GitVersionConfiguration.cs | 16 +++++++++ .../Configuration/IGitVersionConfiguration.cs | 5 +++ src/GitVersion.Core/Git/ReferenceName.cs | 34 +++++++++++++++++++ src/GitVersion.Core/MergeMessage.cs | 23 ++++--------- .../VersionInBranchNameVersionStrategy.cs | 28 ++++++--------- 16 files changed, 114 insertions(+), 54 deletions(-) diff --git a/docs/input/docs/reference/configuration.md b/docs/input/docs/reference/configuration.md index eecfcfbf06..c7c34b1244 100644 --- a/docs/input/docs/reference/configuration.md +++ b/docs/input/docs/reference/configuration.md @@ -43,6 +43,7 @@ The global configuration looks like this: assembly-versioning-scheme: MajorMinorPatch assembly-file-versioning-scheme: MajorMinorPatch label-prefix: '[vV]?' +version-in-branch-pattern: '(?[vV]?\d+(\.\d+)?(\.\d+)?).*' major-version-bump-message: '\+semver:\s?(breaking|major)' minor-version-bump-message: '\+semver:\s?(feature|minor)' patch-version-bump-message: '\+semver:\s?(fix|patch)' @@ -258,9 +259,12 @@ and [tracks-release-branches](#tracks-release-branches). ### label-prefix -A regex which is used to trim Git tags before processing (e.g., v1.0.0). Default -is `[vV]`, although this is just for illustrative purposes as we do a IgnoreCase -match and could be `v`. +A regular expression which is used to trim Git tags before processing (e.g., v1.0.0). The default value is `[vV]`. + +### version-in-branch-pattern + +A regular expression which is used to determine the version number in the branch name or commit message (e.g., v1.0.0-LTS). +The default value is `(?[vV]?\d+(\.\d+)?(\.\d+)?).*`. ### major-version-bump-message diff --git a/src/GitVersion.Core.Tests/Configuration/ConfigurationProviderTests.CanWriteOutEffectiveConfiguration.approved.txt b/src/GitVersion.Core.Tests/Configuration/ConfigurationProviderTests.CanWriteOutEffectiveConfiguration.approved.txt index 24ef92139a..a04994326f 100644 --- a/src/GitVersion.Core.Tests/Configuration/ConfigurationProviderTests.CanWriteOutEffectiveConfiguration.approved.txt +++ b/src/GitVersion.Core.Tests/Configuration/ConfigurationProviderTests.CanWriteOutEffectiveConfiguration.approved.txt @@ -1,6 +1,7 @@ assembly-versioning-scheme: MajorMinorPatch assembly-file-versioning-scheme: MajorMinorPatch label-prefix: '[vV]?' +version-in-branch-pattern: (?[vV]?\d+(\.\d+)?(\.\d+)?).* major-version-bump-message: '\+semver:\s?(breaking|major)' minor-version-bump-message: '\+semver:\s?(feature|minor)' patch-version-bump-message: '\+semver:\s?(fix|patch)' @@ -94,6 +95,7 @@ branches: - support - hotfix is-source-branch-for: [] + is-release-branch: true pre-release-weight: 30000 support: label: '' diff --git a/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs index 6344f1828a..43a4ae0549 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs @@ -33,14 +33,19 @@ public void ShouldOnlyConsiderTagsMatchingOfCurrentBranch() [Test] public void CanTakeVersionFromReleaseBranch() { + var configuration = GitFlowConfigurationBuilder.New + .WithBranch("release", _ => _.WithLabel("{BranchName}")) + .Build(); + using var fixture = new EmptyRepositoryFixture(); + const string taggedVersion = "1.0.3"; fixture.Repository.MakeATaggedCommit(taggedVersion); fixture.Repository.MakeCommits(5); - fixture.Repository.CreateBranch("release/beta-2.0.0"); - Commands.Checkout(fixture.Repository, "release/beta-2.0.0"); + fixture.Repository.CreateBranch("release/2.0.0-LTS"); + Commands.Checkout(fixture.Repository, "release/2.0.0-LTS"); - fixture.AssertFullSemver("2.0.0-beta.1+0"); + fixture.AssertFullSemver("2.0.0-LTS.1+0", configuration); } [Test] diff --git a/src/GitVersion.Core.Tests/MergeMessageTests.cs b/src/GitVersion.Core.Tests/MergeMessageTests.cs index 2468ade21e..0e93c7f16d 100644 --- a/src/GitVersion.Core.Tests/MergeMessageTests.cs +++ b/src/GitVersion.Core.Tests/MergeMessageTests.cs @@ -111,11 +111,11 @@ public void ParsesGitHubPullMergeMessage( private static readonly object?[] BitBucketPullMergeMessages = { - new object?[] { "Merge pull request #1234 from feature/one from feature/two to dev", "feature/two", "dev", null, 1234 }, + new object?[] { "Merge pull request #1234 from feature/one from feature/two to dev", "feature/two", "dev", null, 1234 }, new object?[] { "Merge pull request #1234 in feature/one from feature/two to dev", "feature/two", "dev", null, 1234 }, - new object?[] { "Merge pull request #1234 in v4.0.0 from v4.1.0 to dev", "v4.1.0", "dev", new SemanticVersion(4,1), 1234 }, - new object?[] { "Merge pull request #1234 from origin/feature/one from origin/feature/4.2.0/two to dev", "origin/feature/4.2.0/two", "dev", new SemanticVersion(4,2), 1234 }, - new object?[] { "Merge pull request #1234 in feature/4.1.0/one from feature/4.2.0/two to dev", "feature/4.2.0/two", "dev", new SemanticVersion(4,2), 1234 }, + new object?[] { "Merge pull request #1234 in v4.0.0 from v4.1.0 to dev", "v4.1.0", "dev", new SemanticVersion(4,1), 1234 }, + new object?[] { "Merge pull request #1234 from origin/feature/one from origin/feature/4.2.0/two to dev", "origin/feature/4.2.0/two", "dev", new SemanticVersion(4,2), 1234 }, + new object?[] { "Merge pull request #1234 in feature/4.1.0/one from feature/4.2.0/two to dev", "feature/4.2.0/two", "dev", new SemanticVersion(4,2), 1234 }, new object?[] { $"Merge pull request #1234 from feature/one from feature/two to {MainBranch}" , "feature/two", MainBranch, null, 1234 }, new object?[] { "Merge pull request #1234 in V4.1.0 from V://10.10.10.10 to dev", "V://10.10.10.10", "dev", null, 1234 }, //TODO: Investigate successful bitbucket merge messages that may be invalid diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs index 3daeee88c6..bc7cf4e150 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs @@ -75,14 +75,7 @@ public void TakesVersionFromMergeOfReleaseBranch(string message, bool isMergeCom [TestCase("Merge branch '4.0.3'", true)] [TestCase("Merge branch 's'", true)] [TestCase("Merge tag '10.10.50'", true)] - [TestCase("Merge branch 'hotfix-4.6.6' into support-4.6", true)] - [TestCase("Merge branch 'hotfix-10.10.50'", true)] - [TestCase("Merge branch 'Hotfix-10.10.50'", true)] - [TestCase("Merge branch 'Hotfix/10.10.50'", true)] - [TestCase("Merge branch 'hotfix-0.1.5'", true)] - [TestCase("Merge branch 'hotfix-4.2.2' into support-4.2", true)] [TestCase("Merge branch 'somebranch' into release-3.0.0", true)] - [TestCase("Merge branch 'hotfix-0.1.5'\n\nRelates to: TicketId", true)] [TestCase("Merge branch 'alpha-0.1.5'", true)] [TestCase("Merge pull request #95 from Particular/issue-94", false)] [TestCase("Merge pull request #95 in Particular/issue-94", true)] diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs index f0f2d9db30..4f28c60463 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs @@ -33,10 +33,10 @@ public void CanTakeVersionFromNameOfReleaseBranch(string branchName, string expe baseVersion.SemanticVersion.ToString().ShouldBe(expectedBaseVersion); } - [TestCase("hotfix-2.0.0")] + //[TestCase("hotfix-2.0.0")] [TestCase("origin/hotfix-2.0.0")] [TestCase("remotes/origin/hotfix-2.0.0")] - [TestCase("hotfix/2.0.0")] + //[TestCase("hotfix/2.0.0")] [TestCase("origin/hotfix/2.0.0")] [TestCase("remotes/origin/hotfix/2.0.0")] [TestCase("custom/JIRA-123")] @@ -68,7 +68,7 @@ public void ShouldNotTakeVersionFromNameOfNonReleaseBranch(string branchName) [TestCase("release-2.0.0", "2.0.0")] [TestCase("release/3.0.0", "3.0.0")] - [TestCase("support/lts-2.0.0", "2.0.0")] + [TestCase("support/2.0.0-lts", "2.0.0")] [TestCase("support-3.0.0-lts", "3.0.0")] public void CanTakeVersionFromNameOfConfiguredReleaseBranch(string branchName, string expectedBaseVersion) { @@ -80,6 +80,7 @@ public void CanTakeVersionFromNameOfConfiguredReleaseBranch(string branchName, s var repository = fixture.Repository.ToGitRepository(); var configuration = GitFlowConfigurationBuilder.New + .WithLabelPrefix("([vV]|lts-)?") .WithBranch("support", builder => builder.WithIsReleaseBranch(true)) .Build(); ConfigurationHelper configurationHelper = new(configuration); diff --git a/src/GitVersion.Core/Configuration/ConfigurationBuilderBase.cs b/src/GitVersion.Core/Configuration/ConfigurationBuilderBase.cs index 85d31138f7..994c8bf080 100644 --- a/src/GitVersion.Core/Configuration/ConfigurationBuilderBase.cs +++ b/src/GitVersion.Core/Configuration/ConfigurationBuilderBase.cs @@ -12,6 +12,7 @@ internal abstract class ConfigurationBuilderBase : IConfi private string? assemblyVersioningFormat; private string? assemblyFileVersioningFormat; private string? labelPrefix; + private string? versionInBranchPattern; private string? nextVersion; private string? majorVersionBumpMessage; private string? minorVersionBumpMessage; @@ -131,6 +132,12 @@ public virtual TConfigurationBuilder WithLabelPrefix(string? value) return (TConfigurationBuilder)this; } + public virtual TConfigurationBuilder WithVersionInBranchPattern(string? value) + { + this.versionInBranchPattern = value; + return (TConfigurationBuilder)this; + } + public virtual TConfigurationBuilder WithNextVersion(string? value) { this.nextVersion = value; @@ -302,6 +309,7 @@ public virtual TConfigurationBuilder WithConfiguration(IGitVersionConfiguration WithAssemblyVersioningFormat(value.AssemblyVersioningFormat); WithAssemblyFileVersioningFormat(value.AssemblyFileVersioningFormat); WithLabelPrefix(value.LabelPrefix); + WithVersionInBranchPattern(value.VersionInBranchPattern); WithNextVersion(value.NextVersion); WithMajorVersionBumpMessage(value.MajorVersionBumpMessage); WithMinorVersionBumpMessage(value.MinorVersionBumpMessage); @@ -357,6 +365,7 @@ public virtual IGitVersionConfiguration Build() AssemblyVersioningFormat = this.assemblyVersioningFormat, AssemblyFileVersioningFormat = this.assemblyFileVersioningFormat, LabelPrefix = this.labelPrefix, + VersionInBranchPattern = this.versionInBranchPattern, NextVersion = this.nextVersion, MajorVersionBumpMessage = this.majorVersionBumpMessage, MinorVersionBumpMessage = this.minorVersionBumpMessage, diff --git a/src/GitVersion.Core/Configuration/ConfigurationConstants.cs b/src/GitVersion.Core/Configuration/ConfigurationConstants.cs index 85966d7759..7e862ab4e7 100644 --- a/src/GitVersion.Core/Configuration/ConfigurationConstants.cs +++ b/src/GitVersion.Core/Configuration/ConfigurationConstants.cs @@ -3,6 +3,7 @@ namespace GitVersion.Configuration; internal static class ConfigurationConstants { public const string DefaultLabelPrefix = "[vV]?"; + public const string DefaultVersionInBranchPattern = @"(?[vV]?\d+(\.\d+)?(\.\d+)?).*"; public const string BranchNamePlaceholder = "{BranchName}"; public const string MainBranchKey = "main"; diff --git a/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs b/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs index 20962004bc..eef699cb3e 100644 --- a/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs +++ b/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs @@ -1,3 +1,4 @@ +using System.Text.RegularExpressions; using GitVersion.Extensions; using GitVersion.VersionCalculation; @@ -39,6 +40,7 @@ public EffectiveConfiguration(IGitVersionConfiguration configuration, IBranchCon AssemblyFileVersioningFormat = configuration.AssemblyFileVersioningFormat; VersioningMode = branchConfiguration.VersioningMode.Value; LabelPrefix = configuration.LabelPrefix; + VersionInBranchRegex = configuration.VersionInBranchRegex; Label = branchConfiguration.Label; NextVersion = configuration.NextVersion; Increment = branchConfiguration.Increment; @@ -137,6 +139,8 @@ protected EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningSche /// public string? LabelPrefix { get; } + public Regex VersionInBranchRegex { get; } + /// /// Label to use when calculating SemVer /// diff --git a/src/GitVersion.Core/Configuration/GitFlowConfigurationBuilder.cs b/src/GitVersion.Core/Configuration/GitFlowConfigurationBuilder.cs index aa9635910d..5d332dcc32 100644 --- a/src/GitVersion.Core/Configuration/GitFlowConfigurationBuilder.cs +++ b/src/GitVersion.Core/Configuration/GitFlowConfigurationBuilder.cs @@ -20,6 +20,7 @@ private GitFlowConfigurationBuilder() PatchVersionBumpMessage = IncrementStrategyFinder.DefaultPatchPattern, SemanticVersionFormat = SemanticVersionFormat.Strict, LabelPrefix = ConfigurationConstants.DefaultLabelPrefix, + VersionInBranchPattern = ConfigurationConstants.DefaultVersionInBranchPattern, LabelPreReleaseWeight = 60000, UpdateBuildNumber = true, VersioningMode = VersioningMode.ContinuousDelivery, @@ -133,6 +134,7 @@ private GitFlowConfigurationBuilder() HotfixBranch.Name }, Label = "beta", + IsReleaseBranch = true, PreReleaseWeight = 30000 }); diff --git a/src/GitVersion.Core/Configuration/GitHubFlowConfigurationBuilder.cs b/src/GitVersion.Core/Configuration/GitHubFlowConfigurationBuilder.cs index 236c652968..fbcc27b90a 100644 --- a/src/GitVersion.Core/Configuration/GitHubFlowConfigurationBuilder.cs +++ b/src/GitVersion.Core/Configuration/GitHubFlowConfigurationBuilder.cs @@ -20,6 +20,7 @@ private GitHubFlowConfigurationBuilder() PatchVersionBumpMessage = IncrementStrategyFinder.DefaultPatchPattern, SemanticVersionFormat = SemanticVersionFormat.Strict, LabelPrefix = ConfigurationConstants.DefaultLabelPrefix, + VersionInBranchPattern = ConfigurationConstants.DefaultVersionInBranchPattern, LabelPreReleaseWeight = 60000, UpdateBuildNumber = true, VersioningMode = VersioningMode.ContinuousDelivery, diff --git a/src/GitVersion.Core/Configuration/GitVersionConfiguration.cs b/src/GitVersion.Core/Configuration/GitVersionConfiguration.cs index ebb11723c3..a21cdc76ed 100644 --- a/src/GitVersion.Core/Configuration/GitVersionConfiguration.cs +++ b/src/GitVersion.Core/Configuration/GitVersionConfiguration.cs @@ -1,4 +1,5 @@ using System.Globalization; +using System.Text.RegularExpressions; using GitVersion.Attributes; using GitVersion.Extensions; @@ -34,6 +35,21 @@ internal sealed record GitVersionConfiguration : BranchConfiguration, IGitVersio [JsonPropertyDescription($"A regular expression which is used to trim Git tags before processing. Defaults to {ConfigurationConstants.DefaultLabelPrefix}")] public string? LabelPrefix { get; internal set; } + [JsonPropertyName("version-in-branch-pattern")] + [JsonPropertyDescription($"A regular expression which is used to determine the version number in the branch name or commit message (e.g., v1.0.0-LTS). The default value is '{ConfigurationConstants.DefaultVersionInBranchPattern}'.")] + public string? VersionInBranchPattern { get; internal set; } + + [JsonIgnore] + public Regex VersionInBranchRegex => versionInBranchRegex ??= new Regex(GetVersionInBranchPattern(), RegexOptions.Compiled); + private Regex? versionInBranchRegex; + + private string GetVersionInBranchPattern() + { + var versionInBranchPattern = VersionInBranchPattern; + if (versionInBranchPattern.IsNullOrEmpty()) versionInBranchPattern = ConfigurationConstants.DefaultVersionInBranchPattern; + return $"^{versionInBranchPattern.TrimStart('^')}"; + } + [JsonPropertyName("next-version")] [JsonPropertyDescription("Allows you to bump the next version explicitly. Useful for bumping main or a feature branch with breaking changes")] public string? NextVersion diff --git a/src/GitVersion.Core/Configuration/IGitVersionConfiguration.cs b/src/GitVersion.Core/Configuration/IGitVersionConfiguration.cs index 272430587c..5998585d36 100644 --- a/src/GitVersion.Core/Configuration/IGitVersionConfiguration.cs +++ b/src/GitVersion.Core/Configuration/IGitVersionConfiguration.cs @@ -1,3 +1,4 @@ +using System.Text.RegularExpressions; using GitVersion.Extensions; namespace GitVersion.Configuration; @@ -18,6 +19,10 @@ public interface IGitVersionConfiguration : IBranchConfiguration string? LabelPrefix { get; } + string? VersionInBranchPattern { get; } + + Regex VersionInBranchRegex { get; } + string? NextVersion { get; } string? MajorVersionBumpMessage { get; } diff --git a/src/GitVersion.Core/Git/ReferenceName.cs b/src/GitVersion.Core/Git/ReferenceName.cs index 3f600f6b43..fa975c2d53 100644 --- a/src/GitVersion.Core/Git/ReferenceName.cs +++ b/src/GitVersion.Core/Git/ReferenceName.cs @@ -1,4 +1,6 @@ using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Text.RegularExpressions; using GitVersion.Extensions; using GitVersion.Helpers; @@ -104,7 +106,39 @@ private string RemoveOrigin() return Friendly; } + private char GetBranchSeparator() => WithoutOrigin.Contains('/') || !WithoutOrigin.Contains('-') ? '/' : '-'; + private static bool IsPrefixedBy(string input, string prefix) => input.StartsWith(prefix, StringComparison.Ordinal); private static bool IsPrefixedBy(string input, string[] prefixes) => prefixes.Any(prefix => IsPrefixedBy(input, prefix)); + + public bool TryGetSemanticVersion([NotNullWhen(true)] out (SemanticVersion Value, string? Name) result, + Regex versionPatternRegex, string? labelPrefix, SemanticVersionFormat format) + { + result = default; + + Contract.Assume(versionPatternRegex.ToString().StartsWith("^")); + + int length = 0; + foreach (var branchPart in WithoutOrigin.Split(GetBranchSeparator())) + { + if (branchPart.IsNullOrEmpty()) return false; + + var match = versionPatternRegex.NotNull().Match(branchPart); + if (match.Success) + { + var versionPart = match.Groups["version"].Value; + if (SemanticVersion.TryParse(versionPart, labelPrefix, out var semanticVersion, format)) + { + length += versionPart.Length; + var name = WithoutOrigin[length..].Trim('-'); + result = new(semanticVersion, name.IsEmpty() ? null : name); + return true; + } + } + length += branchPart.Length + 1; + } + + return false; + } } diff --git a/src/GitVersion.Core/MergeMessage.cs b/src/GitVersion.Core/MergeMessage.cs index 5f13789565..d1ae4149c5 100644 --- a/src/GitVersion.Core/MergeMessage.cs +++ b/src/GitVersion.Core/MergeMessage.cs @@ -48,7 +48,9 @@ public MergeMessage(string mergeMessage, IGitVersionConfiguration configuration) PullRequestNumber = pullNumber; } - Version = ParseVersion(configuration.LabelPrefix, configuration.SemanticVersionFormat); + Version = ParseVersion( + configuration.VersionInBranchRegex, configuration.LabelPrefix, configuration.SemanticVersionFormat + )?.Value; break; } @@ -62,22 +64,11 @@ public MergeMessage(string mergeMessage, IGitVersionConfiguration configuration) public int? PullRequestNumber { get; } public SemanticVersion? Version { get; } - private SemanticVersion? ParseVersion(string? tagPrefix, SemanticVersionFormat versionFormat) + private (SemanticVersion Value, string? Name)? ParseVersion( + Regex versionPatternRegex, string? labelPrefix, SemanticVersionFormat format) { - if (tagPrefix is null || MergedBranch is null) - return null; - // Remove remotes and branch prefixes like release/ feature/ hotfix/ etc - var toMatch = Regex.Replace(MergedBranch.WithoutOrigin, @"^(\w+[-/])*", "", RegexOptions.IgnoreCase); - toMatch = Regex.Replace(toMatch, $"^{tagPrefix}", ""); - // We don't match if the version is likely an ip (i.e starts with http://) - var versionMatch = new Regex(@"^(? GetBaseVersions(EffectiveBranchConfigur { if (!configuration.Value.IsReleaseBranch) yield break; - var versionInBranch = GetVersionInBranch( - configuration.Branch.Name, configuration.Value.LabelPrefix, configuration.Value.SemanticVersionFormat - ); - if (versionInBranch != null) + if (configuration.Branch.Name.TryGetSemanticVersion(out var result, configuration.Value.VersionInBranchRegex, + configuration.Value.LabelPrefix, configuration.Value.SemanticVersionFormat)) { var commitBranchWasBranchedFrom = this.repositoryStore.FindCommitBranchWasBranchedFrom( configuration.Branch, Context.Configuration ); - var branchNameOverride = Context.CurrentBranch.Name.Friendly.RegexReplace("[-/]" + versionInBranch.Item1, string.Empty); - yield return new BaseVersion("Version in branch name", false, versionInBranch.Item2, commitBranchWasBranchedFrom.Commit, branchNameOverride); - } - } - private static Tuple? GetVersionInBranch( - ReferenceName branchName, string? tagPrefixRegex, SemanticVersionFormat versionFormat) - { - var branchParts = branchName.WithoutOrigin.Split('/', '-'); - foreach (var part in branchParts) - { - if (SemanticVersion.TryParse(part, tagPrefixRegex, out var semanticVersion, versionFormat)) + string? branchNameOverride = null; + if (Context.CurrentBranch.Name.Equals(configuration.Branch.Name) + || Context.Configuration.GetBranchConfiguration(Context.CurrentBranch.Name).Label is null) { - return Tuple.Create(part, semanticVersion); + branchNameOverride = result.Name; } - } - return null; + yield return new BaseVersion( + "Version in branch name", false, result.Value, commitBranchWasBranchedFrom.Commit, branchNameOverride + ); + } } } From 9faa790c8c3887d6f1396e9829cd2560796e1539 Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Fri, 31 Mar 2023 19:32:02 +0200 Subject: [PATCH 02/14] Fix VersionInBranchNameVersionStrategy only considers the releae branch --- .../IntegrationTests/OtherBranchScenarios.cs | 25 +++++++++++--- src/GitVersion.Core/PublicAPI.Unshipped.txt | 4 +++ .../VersionInBranchNameVersionStrategy.cs | 33 +++++++++++-------- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs index 43a4ae0549..7580804108 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/OtherBranchScenarios.cs @@ -40,12 +40,29 @@ public void CanTakeVersionFromReleaseBranch() using var fixture = new EmptyRepositoryFixture(); const string taggedVersion = "1.0.3"; - fixture.Repository.MakeATaggedCommit(taggedVersion); + fixture.MakeATaggedCommit(taggedVersion); fixture.Repository.MakeCommits(5); - fixture.Repository.CreateBranch("release/2.0.0-LTS"); - Commands.Checkout(fixture.Repository, "release/2.0.0-LTS"); + fixture.BranchTo("release/2.0.0-LTS"); + fixture.MakeACommit(); + + fixture.AssertFullSemver("2.0.0-LTS.1+1", configuration); + } + + [Test] + public void CanTakeVersionFromHotfixBranch() + { + var configuration = GitFlowConfigurationBuilder.New + .WithBranch("hotfix", _ => _.WithLabel("{BranchName}")) + .Build(); + + using var fixture = new EmptyRepositoryFixture(); + + const string taggedVersion = "1.0.3"; + fixture.MakeATaggedCommit(taggedVersion); + fixture.BranchTo("hotfix/1.0.5-LTS"); + fixture.MakeACommit(); - fixture.AssertFullSemver("2.0.0-LTS.1+0", configuration); + fixture.AssertFullSemver("1.0.5-LTS.1+1", configuration); } [Test] diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt index 6e3b993774..1286de50e6 100644 --- a/src/GitVersion.Core/PublicAPI.Unshipped.txt +++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt @@ -134,6 +134,7 @@ GitVersion.Configuration.EffectiveConfiguration.TrackMergeTarget.get -> bool GitVersion.Configuration.EffectiveConfiguration.TracksReleaseBranches.get -> bool GitVersion.Configuration.EffectiveConfiguration.UpdateBuildNumber.get -> bool GitVersion.Configuration.EffectiveConfiguration.VersionFilters.get -> System.Collections.Generic.IEnumerable! +GitVersion.Configuration.EffectiveConfiguration.VersionInBranchRegex.get -> System.Text.RegularExpressions.Regex! GitVersion.Configuration.EffectiveConfiguration.VersioningMode.get -> GitVersion.VersionCalculation.VersioningMode GitVersion.Configuration.IBranchConfiguration GitVersion.Configuration.IBranchConfiguration.CommitMessageIncrementing.get -> GitVersion.VersionCalculation.CommitMessageIncrementMode? @@ -180,6 +181,8 @@ GitVersion.Configuration.IGitVersionConfiguration.NoBumpMessage.get -> string? GitVersion.Configuration.IGitVersionConfiguration.PatchVersionBumpMessage.get -> string? GitVersion.Configuration.IGitVersionConfiguration.SemanticVersionFormat.get -> GitVersion.SemanticVersionFormat GitVersion.Configuration.IGitVersionConfiguration.UpdateBuildNumber.get -> bool +GitVersion.Configuration.IGitVersionConfiguration.VersionInBranchPattern.get -> string? +GitVersion.Configuration.IGitVersionConfiguration.VersionInBranchRegex.get -> System.Text.RegularExpressions.Regex! GitVersion.Configuration.IGitVersionConfiguration.Workflow.get -> string? GitVersion.Configuration.IIgnoreConfiguration GitVersion.Configuration.IIgnoreConfiguration.Before.get -> System.DateTimeOffset? @@ -554,6 +557,7 @@ GitVersion.OutputVariables.VersionVariablesJsonModel.WeightedPreReleaseNumber.ge GitVersion.OutputVariables.VersionVariablesJsonModel.WeightedPreReleaseNumber.set -> void GitVersion.OutputVariables.VersionVariablesJsonStringConverter GitVersion.OutputVariables.VersionVariablesJsonStringConverter.VersionVariablesJsonStringConverter() -> void +GitVersion.ReferenceName.TryGetSemanticVersion(out (GitVersion.SemanticVersion! Value, string? Name) result, System.Text.RegularExpressions.Regex! versionPatternRegex, string? labelPrefix, GitVersion.SemanticVersionFormat format) -> bool GitVersion.RefSpecDirection GitVersion.RefSpecDirection.Fetch = 0 -> GitVersion.RefSpecDirection GitVersion.RefSpecDirection.Push = 1 -> GitVersion.RefSpecDirection diff --git a/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/VersionInBranchNameVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/VersionInBranchNameVersionStrategy.cs index f7984e1f67..ff4fceccc0 100644 --- a/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/VersionInBranchNameVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/VersionInBranchNameVersionStrategy.cs @@ -20,23 +20,28 @@ public override IEnumerable GetBaseVersions(EffectiveBranchConfigur { if (!configuration.Value.IsReleaseBranch) yield break; - if (configuration.Branch.Name.TryGetSemanticVersion(out var result, configuration.Value.VersionInBranchRegex, - configuration.Value.LabelPrefix, configuration.Value.SemanticVersionFormat)) + foreach (var branch in new[] { Context.CurrentBranch, configuration.Branch }) { - var commitBranchWasBranchedFrom = this.repositoryStore.FindCommitBranchWasBranchedFrom( - configuration.Branch, Context.Configuration - ); - - string? branchNameOverride = null; - if (Context.CurrentBranch.Name.Equals(configuration.Branch.Name) - || Context.Configuration.GetBranchConfiguration(Context.CurrentBranch.Name).Label is null) + if (branch.Name.TryGetSemanticVersion(out var result, configuration.Value.VersionInBranchRegex, + configuration.Value.LabelPrefix, configuration.Value.SemanticVersionFormat)) { - branchNameOverride = result.Name; - } + var commitBranchWasBranchedFrom = this.repositoryStore.FindCommitBranchWasBranchedFrom( + configuration.Branch, Context.Configuration + ); + + string? branchNameOverride = null; + if (Context.CurrentBranch.Name.Equals(branch.Name) + || Context.Configuration.GetBranchConfiguration(Context.CurrentBranch.Name).Label is null) + { + branchNameOverride = result.Name; + } - yield return new BaseVersion( - "Version in branch name", false, result.Value, commitBranchWasBranchedFrom.Commit, branchNameOverride - ); + yield return new BaseVersion( + "Version in branch name", false, result.Value, commitBranchWasBranchedFrom.Commit, branchNameOverride + ); + yield break; + } } + } } From 1992f424685323ada80eae060e45eafdd7b965b9 Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Sat, 1 Apr 2023 08:45:33 +0200 Subject: [PATCH 03/14] Fix some unit tests --- .../IntegrationTests/HotfixBranchScenarios.cs | 39 ++++++++++--------- .../SupportBranchScenarios.cs | 36 ++++++++--------- .../VersionInBranchNameVersionStrategy.cs | 29 +++++++++----- 3 files changed, 57 insertions(+), 47 deletions(-) diff --git a/src/GitVersion.Core.Tests/IntegrationTests/HotfixBranchScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/HotfixBranchScenarios.cs index ab7217bf6b..d8ce805c34 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/HotfixBranchScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/HotfixBranchScenarios.cs @@ -60,7 +60,7 @@ public void CanTakeVersionFromHotfixesBranch() // create hotfix branch Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("hotfixes/1.1.1")); - fixture.AssertFullSemver("1.1.0"); // We are still on a tagged commit + fixture.AssertFullSemver("1.1.1+0"); fixture.Repository.MakeACommit(); fixture.AssertFullSemver("1.1.1-beta.1+1"); @@ -78,44 +78,44 @@ public void PatchOlderReleaseExample() r.MakeATaggedCommit("2.0.0"); }); // Merge hotfix branch to support - Commands.Checkout(fixture.Repository, MainBranch); + fixture.Checkout(MainBranch); var tag = fixture.Repository.Tags.Single(t => t.FriendlyName == "1.1.0"); - var supportBranch = fixture.Repository.CreateBranch("support-1.1", (LibGit2Sharp.Commit)tag.Target); - Commands.Checkout(fixture.Repository, supportBranch); + fixture.Repository.CreateBranch("support-1.1", (LibGit2Sharp.Commit)tag.Target); + fixture.Checkout("support-1.1"); fixture.AssertFullSemver("1.1.0"); // create hotfix branch - Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("hotfix-1.1.1")); - fixture.AssertFullSemver("1.1.0"); // We are still on a tagged commit - fixture.Repository.MakeACommit(); + fixture.BranchTo("hotfix-1.1.1"); + fixture.AssertFullSemver("1.1.1+0"); + fixture.MakeACommit(); fixture.AssertFullSemver("1.1.1-beta.1+1"); - fixture.Repository.MakeACommit(); + fixture.MakeACommit(); fixture.AssertFullSemver("1.1.1-beta.1+2"); // Create feature branch off hotfix branch and complete - Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("feature/fix")); + fixture.BranchTo("feature/fix"); fixture.AssertFullSemver("1.1.1-fix.1+2"); - fixture.Repository.MakeACommit(); + fixture.MakeACommit(); fixture.AssertFullSemver("1.1.1-fix.1+3"); fixture.Repository.CreatePullRequestRef("feature/fix", "hotfix-1.1.1", prNumber: 8, normalise: true); fixture.AssertFullSemver("1.1.1-PullRequest8.4"); - Commands.Checkout(fixture.Repository, "hotfix-1.1.1"); - fixture.Repository.MergeNoFF("feature/fix", Generate.SignatureNow()); + fixture.Checkout("hotfix-1.1.1"); + fixture.MergeNoFF("feature/fix"); fixture.AssertFullSemver("1.1.1-beta.1+4"); // Merge hotfix into support branch to complete hotfix - Commands.Checkout(fixture.Repository, "support-1.1"); - fixture.Repository.MergeNoFF("hotfix-1.1.1", Generate.SignatureNow()); + fixture.Checkout("support-1.1"); + fixture.MergeNoFF("hotfix-1.1.1"); fixture.AssertFullSemver("1.1.1+5"); - fixture.Repository.ApplyTag("1.1.1"); + fixture.ApplyTag("1.1.1"); fixture.AssertFullSemver("1.1.1"); // Verify develop version - Commands.Checkout(fixture.Repository, "develop"); + fixture.Checkout("develop"); fixture.AssertFullSemver("2.1.0-alpha.1"); - fixture.Repository.MergeNoFF("support-1.1", Generate.SignatureNow()); + fixture.MergeNoFF("support-1.1"); fixture.AssertFullSemver("2.1.0-alpha.7"); } @@ -167,7 +167,7 @@ public void FeatureOnHotfixFeatureBranchDeleted() fixture.Checkout(hotfix451); fixture.MergeNoFF(featureBranch); // commit 2 fixture.Repository.Branches.Remove(featureBranch); - fixture.AssertFullSemver("4.5.1-beta.2", configuration); + fixture.AssertFullSemver("4.5.1-beta.3", configuration); } /// @@ -217,7 +217,8 @@ public void FeatureOnHotfixFeatureBranchNotDeleted() fixture.MakeACommit("blabla"); // commit 1 fixture.Checkout(hotfix451); fixture.MergeNoFF(featureBranch); // commit 2 - fixture.AssertFullSemver("4.5.1-beta.2", configuration); + + fixture.AssertFullSemver("4.5.1-beta.3", configuration); } [Test] diff --git a/src/GitVersion.Core.Tests/IntegrationTests/SupportBranchScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/SupportBranchScenarios.cs index d43aff23d8..42c4431f6c 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/SupportBranchScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/SupportBranchScenarios.cs @@ -12,41 +12,41 @@ public void SupportIsCalculatedCorrectly() { using var fixture = new EmptyRepositoryFixture(); // Start at 1.0.0 - fixture.Repository.MakeACommit(); - fixture.Repository.ApplyTag("1.1.0"); + fixture.MakeACommit(); + fixture.ApplyTag("1.1.0"); // Create 2.0.0 release - Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("release-2.0.0")); + fixture.BranchTo("release-2.0.0"); fixture.Repository.MakeCommits(2); // Merge into develop and main - Commands.Checkout(fixture.Repository, MainBranch); - fixture.Repository.MergeNoFF("release-2.0.0"); - fixture.Repository.ApplyTag("2.0.0"); + fixture.Checkout(MainBranch); + fixture.MergeNoFF("release-2.0.0"); + fixture.ApplyTag("2.0.0"); fixture.AssertFullSemver("2.0.0"); // Now lets support 1.x release - Commands.Checkout(fixture.Repository, "1.1.0"); - Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("support/1.0.0")); + fixture.Checkout("1.1.0"); + fixture.BranchTo("support/1.0.0"); fixture.AssertFullSemver("1.1.0"); // Create release branch from support branch - Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("release/1.2.0")); - fixture.Repository.MakeACommit(); + fixture.BranchTo("release/1.2.0"); + fixture.MakeACommit(); fixture.AssertFullSemver("1.2.0-beta.1+1"); // Create 1.2.0 release - Commands.Checkout(fixture.Repository, "support/1.0.0"); - fixture.Repository.MergeNoFF("release/1.2.0"); + fixture.Checkout("support/1.0.0"); + fixture.MergeNoFF("release/1.2.0"); fixture.AssertFullSemver("1.2.0+0"); - fixture.Repository.ApplyTag("1.2.0"); + fixture.ApplyTag("1.2.0"); // Create 1.2.1 hotfix - Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("hotfix/1.2.1")); - fixture.Repository.MakeACommit(); - fixture.AssertFullSemver("1.2.1-beta.1+1"); - Commands.Checkout(fixture.Repository, "support/1.0.0"); - fixture.Repository.MergeNoFF("hotfix/1.2.1"); + fixture.BranchTo("hotfix/1.2.1"); + fixture.MakeACommit(); + fixture.AssertFullSemver("1.2.1-beta.1+3"); + fixture.Checkout("support/1.0.0"); + fixture.MergeNoFF("hotfix/1.2.1"); fixture.AssertFullSemver("1.2.1+2"); } diff --git a/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/VersionInBranchNameVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/VersionInBranchNameVersionStrategy.cs index ff4fceccc0..55e7a1e021 100644 --- a/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/VersionInBranchNameVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/VersionInBranchNameVersionStrategy.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using GitVersion.Common; using GitVersion.Configuration; using GitVersion.Extensions; @@ -18,30 +19,38 @@ public VersionInBranchNameVersionStrategy(IRepositoryStore repositoryStore, Lazy public override IEnumerable GetBaseVersions(EffectiveBranchConfiguration configuration) { - if (!configuration.Value.IsReleaseBranch) yield break; + if (configuration.Value.IsReleaseBranch && TryGetBaseVersion(out var baseVersion, configuration)) + { + yield return baseVersion; + } + } + private bool TryGetBaseVersion([NotNullWhen(true)] out BaseVersion? baseVersion, EffectiveBranchConfiguration configuration) + { + baseVersion = null; + + Lazy commitBranchWasBranchedFrom = new( + () => this.repositoryStore.FindCommitBranchWasBranchedFrom(configuration.Branch, Context.Configuration) + ); foreach (var branch in new[] { Context.CurrentBranch, configuration.Branch }) { if (branch.Name.TryGetSemanticVersion(out var result, configuration.Value.VersionInBranchRegex, configuration.Value.LabelPrefix, configuration.Value.SemanticVersionFormat)) { - var commitBranchWasBranchedFrom = this.repositoryStore.FindCommitBranchWasBranchedFrom( - configuration.Branch, Context.Configuration - ); - string? branchNameOverride = null; - if (Context.CurrentBranch.Name.Equals(branch.Name) - || Context.Configuration.GetBranchConfiguration(Context.CurrentBranch.Name).Label is null) + if (!result.Name.IsNullOrEmpty() && (Context.CurrentBranch.Name.Equals(branch.Name) + || Context.Configuration.GetBranchConfiguration(Context.CurrentBranch.Name).Label is null)) { branchNameOverride = result.Name; } - yield return new BaseVersion( - "Version in branch name", false, result.Value, commitBranchWasBranchedFrom.Commit, branchNameOverride + baseVersion = new BaseVersion( + "Version in branch name", false, result.Value, commitBranchWasBranchedFrom.Value.Commit, branchNameOverride ); - yield break; + break; } } + return baseVersion != null; } } From 0ea5c524b211790ce397676eb2ace771bee5eac6 Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Sat, 1 Apr 2023 09:13:22 +0200 Subject: [PATCH 04/14] Gnerating the json schemas with: ./build.ps1 -Stage build -Target BuildPrepare ./build.ps1 -Stage docs -Target GenerateSchemas --- schemas/6.0/GitVersion.configuration.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/schemas/6.0/GitVersion.configuration.json b/schemas/6.0/GitVersion.configuration.json index 61160e5161..3bcbfb44f5 100644 --- a/schemas/6.0/GitVersion.configuration.json +++ b/schemas/6.0/GitVersion.configuration.json @@ -161,6 +161,10 @@ "description": "Whether to update the build number in the project file. Defaults to true.", "type": "boolean" }, + "version-in-branch-pattern": { + "description": "A regular expression which is used to determine the version number in the branch name or commit message (e.g., v1.0.0-LTS). The default value is \u0027(?\u003Cversion\u003E[vV]?\\d\u002B(\\.\\d\u002B)?(\\.\\d\u002B)?).*\u0027.", + "type": "string" + }, "mode": { "$ref": "#/$defs/Nullable\u006018" }, From d54cd692bb844d7ee92810c3d5c2babf2fa73a95 Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Sat, 1 Apr 2023 10:17:43 +0200 Subject: [PATCH 05/14] Extract TryGetSemanticVersion method into extensions class --- ...ionInBranchNameBaseVersionStrategyTests.cs | 6 ++- src/GitVersion.Core/Git/ReferenceName.cs | 34 -------------- src/GitVersion.Core/PublicAPI.Unshipped.txt | 3 +- .../ReferenceNameExtensions.cs | 45 +++++++++++++++++++ 4 files changed, 51 insertions(+), 37 deletions(-) create mode 100644 src/GitVersion.Core/VersionCalculation/SemanticVersioning/ReferenceNameExtensions.cs diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs index 4f28c60463..57dbaf78f7 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs @@ -33,10 +33,8 @@ public void CanTakeVersionFromNameOfReleaseBranch(string branchName, string expe baseVersion.SemanticVersion.ToString().ShouldBe(expectedBaseVersion); } - //[TestCase("hotfix-2.0.0")] [TestCase("origin/hotfix-2.0.0")] [TestCase("remotes/origin/hotfix-2.0.0")] - //[TestCase("hotfix/2.0.0")] [TestCase("origin/hotfix/2.0.0")] [TestCase("remotes/origin/hotfix/2.0.0")] [TestCase("custom/JIRA-123")] @@ -70,6 +68,10 @@ public void ShouldNotTakeVersionFromNameOfNonReleaseBranch(string branchName) [TestCase("release/3.0.0", "3.0.0")] [TestCase("support/2.0.0-lts", "2.0.0")] [TestCase("support-3.0.0-lts", "3.0.0")] + [TestCase("hotfix/2.0.0", "2.0.0")] + [TestCase("hotfix-3.0.0", "3.0.0")] + [TestCase("hotfix/2.0.0-lts", "2.0.0")] + [TestCase("hotfix-3.0.0-lts", "3.0.0")] public void CanTakeVersionFromNameOfConfiguredReleaseBranch(string branchName, string expectedBaseVersion) { using var fixture = new EmptyRepositoryFixture(); diff --git a/src/GitVersion.Core/Git/ReferenceName.cs b/src/GitVersion.Core/Git/ReferenceName.cs index fa975c2d53..3f600f6b43 100644 --- a/src/GitVersion.Core/Git/ReferenceName.cs +++ b/src/GitVersion.Core/Git/ReferenceName.cs @@ -1,6 +1,4 @@ using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; -using System.Text.RegularExpressions; using GitVersion.Extensions; using GitVersion.Helpers; @@ -106,39 +104,7 @@ private string RemoveOrigin() return Friendly; } - private char GetBranchSeparator() => WithoutOrigin.Contains('/') || !WithoutOrigin.Contains('-') ? '/' : '-'; - private static bool IsPrefixedBy(string input, string prefix) => input.StartsWith(prefix, StringComparison.Ordinal); private static bool IsPrefixedBy(string input, string[] prefixes) => prefixes.Any(prefix => IsPrefixedBy(input, prefix)); - - public bool TryGetSemanticVersion([NotNullWhen(true)] out (SemanticVersion Value, string? Name) result, - Regex versionPatternRegex, string? labelPrefix, SemanticVersionFormat format) - { - result = default; - - Contract.Assume(versionPatternRegex.ToString().StartsWith("^")); - - int length = 0; - foreach (var branchPart in WithoutOrigin.Split(GetBranchSeparator())) - { - if (branchPart.IsNullOrEmpty()) return false; - - var match = versionPatternRegex.NotNull().Match(branchPart); - if (match.Success) - { - var versionPart = match.Groups["version"].Value; - if (SemanticVersion.TryParse(versionPart, labelPrefix, out var semanticVersion, format)) - { - length += versionPart.Length; - var name = WithoutOrigin[length..].Trim('-'); - result = new(semanticVersion, name.IsEmpty() ? null : name); - return true; - } - } - length += branchPart.Length + 1; - } - - return false; - } } diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt index 1286de50e6..56c7c56a78 100644 --- a/src/GitVersion.Core/PublicAPI.Unshipped.txt +++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt @@ -557,7 +557,7 @@ GitVersion.OutputVariables.VersionVariablesJsonModel.WeightedPreReleaseNumber.ge GitVersion.OutputVariables.VersionVariablesJsonModel.WeightedPreReleaseNumber.set -> void GitVersion.OutputVariables.VersionVariablesJsonStringConverter GitVersion.OutputVariables.VersionVariablesJsonStringConverter.VersionVariablesJsonStringConverter() -> void -GitVersion.ReferenceName.TryGetSemanticVersion(out (GitVersion.SemanticVersion! Value, string? Name) result, System.Text.RegularExpressions.Regex! versionPatternRegex, string? labelPrefix, GitVersion.SemanticVersionFormat format) -> bool +GitVersion.ReferenceNameExtensions GitVersion.RefSpecDirection GitVersion.RefSpecDirection.Fetch = 0 -> GitVersion.RefSpecDirection GitVersion.RefSpecDirection.Push = 1 -> GitVersion.RefSpecDirection @@ -887,6 +887,7 @@ static GitVersion.OutputVariables.VersionVariablesHelper.ToJsonString(this GitVe static GitVersion.ReferenceName.FromBranchName(string! branchName) -> GitVersion.ReferenceName! static GitVersion.ReferenceName.Parse(string! canonicalName) -> GitVersion.ReferenceName! static GitVersion.ReferenceName.TryParse(out GitVersion.ReferenceName? value, string! canonicalName) -> bool +static GitVersion.ReferenceNameExtensions.TryGetSemanticVersion(this GitVersion.ReferenceName! source, out (GitVersion.SemanticVersion! Value, string? Name) result, System.Text.RegularExpressions.Regex! versionPatternRegex, string? labelPrefix, GitVersion.SemanticVersionFormat format) -> bool static GitVersion.SemanticVersion.Parse(string! version, string? tagPrefixRegex, GitVersion.SemanticVersionFormat versionFormat = GitVersion.SemanticVersionFormat.Strict) -> GitVersion.SemanticVersion! static GitVersion.SemanticVersion.TryParse(string! version, string? tagPrefixRegex, out GitVersion.SemanticVersion? semanticVersion, GitVersion.SemanticVersionFormat format = GitVersion.SemanticVersionFormat.Strict) -> bool static GitVersion.SemanticVersion.operator !=(GitVersion.SemanticVersion? v1, GitVersion.SemanticVersion? v2) -> bool diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/ReferenceNameExtensions.cs b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/ReferenceNameExtensions.cs new file mode 100644 index 0000000000..09664f5290 --- /dev/null +++ b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/ReferenceNameExtensions.cs @@ -0,0 +1,45 @@ +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Text.RegularExpressions; +using GitVersion.Extensions; + +namespace GitVersion; + +public static class ReferenceNameExtensions +{ + public static bool TryGetSemanticVersion(this ReferenceName source, + [NotNullWhen(true)] out (SemanticVersion Value, string? Name) result, + Regex versionPatternRegex, string? labelPrefix, SemanticVersionFormat format) + { + source.NotNull(); + + result = default; + + Contract.Assume(versionPatternRegex.ToString().StartsWith("^")); + + int length = 0; + foreach (var branchPart in source.WithoutOrigin.Split(GetBranchSeparator(source))) + { + if (branchPart.IsNullOrEmpty()) return false; + + var match = versionPatternRegex.NotNull().Match(branchPart); + if (match.Success) + { + var versionPart = match.Groups["version"].Value; + if (SemanticVersion.TryParse(versionPart, labelPrefix, out var semanticVersion, format)) + { + length += versionPart.Length; + var name = source.WithoutOrigin[length..].Trim('-'); + result = new(semanticVersion, name.IsEmpty() ? null : name); + return true; + } + } + length += branchPart.Length + 1; + } + + return false; + } + + private static char GetBranchSeparator(ReferenceName source) + => source.WithoutOrigin.Contains('/') || !source.WithoutOrigin.Contains('-') ? '/' : '-'; +} From 26b5465ecd2b3a81d973bd961405628223849edb Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Sat, 1 Apr 2023 14:08:04 +0200 Subject: [PATCH 06/14] Change documentation --- docs/input/docs/reference/configuration.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/input/docs/reference/configuration.md b/docs/input/docs/reference/configuration.md index c7c34b1244..296612439d 100644 --- a/docs/input/docs/reference/configuration.md +++ b/docs/input/docs/reference/configuration.md @@ -43,7 +43,7 @@ The global configuration looks like this: assembly-versioning-scheme: MajorMinorPatch assembly-file-versioning-scheme: MajorMinorPatch label-prefix: '[vV]?' -version-in-branch-pattern: '(?[vV]?\d+(\.\d+)?(\.\d+)?).*' +version-in-branch-pattern: (?[vV]?\d+(\.\d+)?(\.\d+)?).* major-version-bump-message: '\+semver:\s?(breaking|major)' minor-version-bump-message: '\+semver:\s?(feature|minor)' patch-version-bump-message: '\+semver:\s?(fix|patch)' @@ -62,6 +62,7 @@ branches: track-merge-target: true regex: ^dev(elop)?(ment)?$ source-branches: [] + is-source-branch-for: [] tracks-release-branches: true is-release-branch: false is-mainline: false @@ -75,6 +76,7 @@ branches: source-branches: - develop - release + is-source-branch-for: [] tracks-release-branches: false is-release-branch: false is-mainline: true @@ -90,6 +92,7 @@ branches: - main - support - release + is-source-branch-for: [] tracks-release-branches: false is-release-branch: true is-mainline: false @@ -106,6 +109,7 @@ branches: - feature - support - hotfix + is-source-branch-for: [] pre-release-weight: 30000 pull-request: mode: ContinuousDelivery @@ -120,6 +124,7 @@ branches: - feature - support - hotfix + is-source-branch-for: [] pre-release-weight: 30000 hotfix: mode: ContinuousDelivery @@ -131,6 +136,8 @@ branches: - main - support - hotfix + is-source-branch-for: [] + is-release-branch: true pre-release-weight: 30000 support: label: '' @@ -140,6 +147,7 @@ branches: regex: ^support[/-] source-branches: - main + is-source-branch-for: [] tracks-release-branches: false is-release-branch: false is-mainline: true @@ -157,6 +165,7 @@ branches: - pull-request - hotfix - support + is-source-branch-for: [] ignore: sha: [] mode: ContinuousDelivery @@ -167,6 +176,8 @@ track-merge-target: false track-merge-message: true commit-message-incrementing: Enabled regex: '' +source-branches: [] +is-source-branch-for: [] tracks-release-branches: false is-release-branch: false is-mainline: false @@ -259,12 +270,15 @@ and [tracks-release-branches](#tracks-release-branches). ### label-prefix -A regular expression which is used to trim Git tags before processing (e.g., v1.0.0). The default value is `[vV]`. +A regular expression which is used to trim Git tags before processing (e.g., +v1.0.0). The default value is `[vV]`. ### version-in-branch-pattern -A regular expression which is used to determine the version number in the branch name or commit message (e.g., v1.0.0-LTS). -The default value is `(?[vV]?\d+(\.\d+)?(\.\d+)?).*`. +A regular expression which is used to determine the version number in the branch +name or commit message (e.g., v1.0.0-LTS). This setting only applies on branches +where the option `is-release-branch` is set to `true`. The default value is +`(?[vV]?\d+(\.\d+)?(\.\d+)?).*`. ### major-version-bump-message From a50892afafefd8d409f1b4e014e2d2faa317c86e Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Sun, 2 Apr 2023 10:02:26 +0200 Subject: [PATCH 07/14] minor refactoring in MergeMessage.cs --- src/GitVersion.Core/MergeMessage.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/GitVersion.Core/MergeMessage.cs b/src/GitVersion.Core/MergeMessage.cs index d1ae4149c5..133bac3194 100644 --- a/src/GitVersion.Core/MergeMessage.cs +++ b/src/GitVersion.Core/MergeMessage.cs @@ -50,7 +50,7 @@ public MergeMessage(string mergeMessage, IGitVersionConfiguration configuration) Version = ParseVersion( configuration.VersionInBranchRegex, configuration.LabelPrefix, configuration.SemanticVersionFormat - )?.Value; + ); break; } @@ -64,11 +64,10 @@ public MergeMessage(string mergeMessage, IGitVersionConfiguration configuration) public int? PullRequestNumber { get; } public SemanticVersion? Version { get; } - private (SemanticVersion Value, string? Name)? ParseVersion( - Regex versionPatternRegex, string? labelPrefix, SemanticVersionFormat format) + private SemanticVersion? ParseVersion(Regex versionInBranchRegex, string? labelPrefix, SemanticVersionFormat format) { - if (MergedBranch?.TryGetSemanticVersion(out var result, versionPatternRegex, labelPrefix, format) == true) - return result; + if (MergedBranch?.TryGetSemanticVersion(out var result, versionInBranchRegex, labelPrefix, format) == true) + return result.Value; return null; } From 14d33d845593dca37c5b36ef05a17a3f40930839 Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Mon, 3 Apr 2023 13:15:02 +0200 Subject: [PATCH 08/14] Change breaking change documentation and remove WithLabelPrefix in unit test --- BREAKING_CHANGES.md | 2 ++ .../Strategies/VersionInBranchNameBaseVersionStrategyTests.cs | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 5df5e9ff4a..1287c7cf78 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -25,6 +25,8 @@ * A new branch related property with name `track-merge-message` has been introduced. Consider we have a `main` branch and a `release/1.0.0` branch and merge changes from `release/1.0.0` to the main branch. In this scenario the merge message will be interpreted as a next version `1.0.0` when `track-merge-message` is set to `true` otherwise `0.0.1`. * The pre-release tags are only considered when they are matching with the label name of the branch. This has an effect on the way how the `CommitCountSource` will be determined. * The process of increasing the version with bump message when `CommitMessageIncrementing` is enabled and increment strategy is `None` has been changed. +* A new configuration property with name `version-in-branch-pattern` has been introduced. This setting only applies on branches where the option `is-release-branch` is set to `true`. Please notice that the branch name needs to be defined after the version number by default (instead of `support/lts-2.0.0` please name the branch like `support/2.0.0-lts`). +* The `is-release-branch` property of the `hotfix` branch setting has been changed from `false` to `true`. If present the hotfix number will be considered now by default. ## v5.0.0 diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs index 57dbaf78f7..c6c01ae80e 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/VersionInBranchNameBaseVersionStrategyTests.cs @@ -82,7 +82,6 @@ public void CanTakeVersionFromNameOfConfiguredReleaseBranch(string branchName, s var repository = fixture.Repository.ToGitRepository(); var configuration = GitFlowConfigurationBuilder.New - .WithLabelPrefix("([vV]|lts-)?") .WithBranch("support", builder => builder.WithIsReleaseBranch(true)) .Build(); ConfigurationHelper configurationHelper = new(configuration); From cbfce467e3e6fc1c8597d581f8488040fc6b8933 Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Mon, 3 Apr 2023 15:59:08 +0200 Subject: [PATCH 09/14] Remove ReferenceNameExtensions and integrate functionality into ReferenceName.cs --- .../GitVersion.Common.csproj | 18 ++++ src/GitVersion.Core/Git/ReferenceName.cs | 34 +++++++ .../SemanticVersion.cs | 88 +++++++------------ .../SemanticVersionBuildMetaData.cs | 12 +-- .../SemanticVersionFormat.cs | 0 .../SemanticVersionPreReleaseTag.cs | 9 +- .../VersionField.cs | 0 .../Exceptions => Git}/WarningException.cs | 0 src/GitVersion.Core/PublicAPI.Unshipped.txt | 3 +- .../ReferenceNameExtensions.cs | 45 ---------- 10 files changed, 97 insertions(+), 112 deletions(-) rename src/GitVersion.Core/{VersionCalculation/SemanticVersioning => Git}/SemanticVersion.cs (79%) rename src/GitVersion.Core/{VersionCalculation/SemanticVersioning => Git}/SemanticVersionBuildMetaData.cs (89%) rename src/GitVersion.Core/{VersionCalculation/SemanticVersioning => Git}/SemanticVersionFormat.cs (100%) rename src/GitVersion.Core/{VersionCalculation/SemanticVersioning => Git}/SemanticVersionPreReleaseTag.cs (93%) rename src/GitVersion.Core/{VersionCalculation/SemanticVersioning => Git}/VersionField.cs (100%) rename src/GitVersion.Core/{Core/Exceptions => Git}/WarningException.cs (100%) delete mode 100644 src/GitVersion.Core/VersionCalculation/SemanticVersioning/ReferenceNameExtensions.cs diff --git a/new-cli/GitVersion.Common/GitVersion.Common.csproj b/new-cli/GitVersion.Common/GitVersion.Common.csproj index f2507e4fbd..0284be2ba5 100644 --- a/new-cli/GitVersion.Common/GitVersion.Common.csproj +++ b/new-cli/GitVersion.Common/GitVersion.Common.csproj @@ -63,5 +63,23 @@ Git\RefSpecDirection.cs + + Git\SemanticVersion.cs + + + Git\SemanticVersionBuildMetaData.cs + + + Git\SemanticVersionFormat.cs + + + Git\SemanticVersionPreReleaseTag.cs + + + Git\VersionField.cs + + + Git\WarningException.cs + diff --git a/src/GitVersion.Core/Git/ReferenceName.cs b/src/GitVersion.Core/Git/ReferenceName.cs index 3f600f6b43..4393a51734 100644 --- a/src/GitVersion.Core/Git/ReferenceName.cs +++ b/src/GitVersion.Core/Git/ReferenceName.cs @@ -1,4 +1,6 @@ using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Text.RegularExpressions; using GitVersion.Extensions; using GitVersion.Helpers; @@ -76,6 +78,38 @@ public static ReferenceName FromBranchName(string branchName) public override int GetHashCode() => equalityHelper.GetHashCode(this); public override string ToString() => Friendly; + public bool TryGetSemanticVersion([NotNullWhen(true)] out (SemanticVersion Value, string? Name) result, + Regex versionPatternRegex, string? labelPrefix, SemanticVersionFormat format) + { + result = default; + + Contract.Assume(versionPatternRegex.ToString().StartsWith("^")); + + int length = 0; + foreach (var branchPart in WithoutOrigin.Split(GetBranchSeparator())) + { + if (string.IsNullOrEmpty(branchPart)) return false; + + var match = versionPatternRegex.NotNull().Match(branchPart); + if (match.Success) + { + var versionPart = match.Groups["version"].Value; + if (SemanticVersion.TryParse(versionPart, labelPrefix, out var semanticVersion, format)) + { + length += versionPart.Length; + var name = WithoutOrigin[length..].Trim('-'); + result = new(semanticVersion, name == string.Empty ? null : name); + return true; + } + } + length += branchPart.Length + 1; + } + + return false; + } + + private char GetBranchSeparator() => WithoutOrigin.Contains('/') || !WithoutOrigin.Contains('-') ? '/' : '-'; + public bool EquivalentTo(string? name) => Canonical.Equals(name, StringComparison.OrdinalIgnoreCase) || Friendly.Equals(name, StringComparison.OrdinalIgnoreCase) diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersion.cs b/src/GitVersion.Core/Git/SemanticVersion.cs similarity index 79% rename from src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersion.cs rename to src/GitVersion.Core/Git/SemanticVersion.cs index a68dd49faf..e557d93ea7 100644 --- a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersion.cs +++ b/src/GitVersion.Core/Git/SemanticVersion.cs @@ -28,39 +28,37 @@ public class SemanticVersion : IFormattable, IComparable, IEqua public SemanticVersionBuildMetaData BuildMetaData { get; init; } - public bool IsLabeledWith(string value) => PreReleaseTag.HasTag() && PreReleaseTag.Name.IsEquivalentTo(value); + public bool IsLabeledWith(string value) => PreReleaseTag.HasTag() && string.Equals(PreReleaseTag.Name, value, StringComparison.OrdinalIgnoreCase); public bool IsMatchForBranchSpecificLabel(string? value) => PreReleaseTag.Name == string.Empty || value is null || IsLabeledWith(value); public SemanticVersion(long major = 0, long minor = 0, long patch = 0) { - this.Major = major; - this.Minor = minor; - this.Patch = patch; - this.PreReleaseTag = new SemanticVersionPreReleaseTag(); - this.BuildMetaData = new SemanticVersionBuildMetaData(); + Major = major; + Minor = minor; + Patch = patch; + PreReleaseTag = new SemanticVersionPreReleaseTag(); + BuildMetaData = new SemanticVersionBuildMetaData(); } public SemanticVersion(SemanticVersion semanticVersion) { semanticVersion.NotNull(); - this.Major = semanticVersion.Major; - this.Minor = semanticVersion.Minor; - this.Patch = semanticVersion.Patch; + Major = semanticVersion.Major; + Minor = semanticVersion.Minor; + Patch = semanticVersion.Patch; - this.PreReleaseTag = new SemanticVersionPreReleaseTag(semanticVersion.PreReleaseTag); - this.BuildMetaData = new SemanticVersionBuildMetaData(semanticVersion.BuildMetaData); + PreReleaseTag = new SemanticVersionPreReleaseTag(semanticVersion.PreReleaseTag); + BuildMetaData = new SemanticVersionBuildMetaData(semanticVersion.BuildMetaData); } public bool Equals(SemanticVersion? obj) { if (obj == null) - { return false; - } - return this.Major == obj.Major && this.Minor == obj.Minor && this.Patch == obj.Patch && this.PreReleaseTag == obj.PreReleaseTag && this.BuildMetaData == obj.BuildMetaData; + return Major == obj.Major && Minor == obj.Minor && Patch == obj.Patch && PreReleaseTag == obj.PreReleaseTag && BuildMetaData == obj.BuildMetaData; } public bool IsEmpty() => Equals(Empty); @@ -68,13 +66,9 @@ public bool Equals(SemanticVersion? obj) public override bool Equals(object? obj) { if (obj is null) - { return false; - } if (ReferenceEquals(this, obj)) - { return true; - } return obj.GetType() == GetType() && Equals((SemanticVersion)obj); } @@ -82,11 +76,11 @@ public override int GetHashCode() { unchecked { - var hashCode = this.Major.GetHashCode(); - hashCode = (hashCode * 397) ^ this.Minor.GetHashCode(); - hashCode = (hashCode * 397) ^ this.Patch.GetHashCode(); - hashCode = (hashCode * 397) ^ this.PreReleaseTag.GetHashCode(); - hashCode = (hashCode * 397) ^ this.BuildMetaData.GetHashCode(); + var hashCode = Major.GetHashCode(); + hashCode = hashCode * 397 ^ Minor.GetHashCode(); + hashCode = hashCode * 397 ^ Patch.GetHashCode(); + hashCode = hashCode * 397 ^ PreReleaseTag.GetHashCode(); + hashCode = hashCode * 397 ^ BuildMetaData.GetHashCode(); return hashCode; } } @@ -94,9 +88,7 @@ public override int GetHashCode() public static bool operator ==(SemanticVersion? v1, SemanticVersion? v2) { if (v1 is null) - { return v2 is null; - } return v1.Equals(v2); } @@ -225,39 +217,29 @@ private static bool TryParseLoose(string version, [NotNullWhen(true)] out Semant public int CompareTo(SemanticVersion? value, bool includePrerelease) { if (value == null) - { return 1; - } - if (this.Major != value.Major) + if (Major != value.Major) { - if (this.Major > value.Major) - { + if (Major > value.Major) return 1; - } return -1; } - if (this.Minor != value.Minor) + if (Minor != value.Minor) { - if (this.Minor > value.Minor) - { + if (Minor > value.Minor) return 1; - } return -1; } - if (this.Patch != value.Patch) + if (Patch != value.Patch) { - if (this.Patch > value.Patch) - { + if (Patch > value.Patch) return 1; - } return -1; } - if (includePrerelease && this.PreReleaseTag != value.PreReleaseTag) + if (includePrerelease && PreReleaseTag != value.PreReleaseTag) { - if (this.PreReleaseTag > value.PreReleaseTag) - { + if (PreReleaseTag > value.PreReleaseTag) return 1; - } return -1; } @@ -277,7 +259,7 @@ public int CompareTo(SemanticVersion? value, bool includePrerelease) /// public string ToString(string? format, IFormatProvider? formatProvider) { - if (format.IsNullOrEmpty()) + if (string.IsNullOrEmpty(format)) format = "s"; if (formatProvider?.GetFormat(GetType()) is ICustomFormatter formatter) @@ -288,22 +270,22 @@ public string ToString(string? format, IFormatProvider? formatProvider) switch (format) { case "j": - return $"{this.Major}.{this.Minor}.{this.Patch}"; + return $"{Major}.{Minor}.{Patch}"; case "s": - return this.PreReleaseTag.HasTag() ? $"{ToString("j")}-{this.PreReleaseTag}" : ToString("j"); + return PreReleaseTag.HasTag() ? $"{ToString("j")}-{PreReleaseTag}" : ToString("j"); case "t": - return this.PreReleaseTag.HasTag() ? $"{ToString("j")}-{this.PreReleaseTag.ToString("t")}" : ToString("j"); + return PreReleaseTag.HasTag() ? $"{ToString("j")}-{PreReleaseTag.ToString("t")}" : ToString("j"); case "f": { - var buildMetadata = this.BuildMetaData.ToString(); + var buildMetadata = BuildMetaData.ToString(); - return !buildMetadata.IsNullOrEmpty() ? $"{ToString("s")}+{buildMetadata}" : ToString("s"); + return !string.IsNullOrEmpty(buildMetadata) ? $"{ToString("s")}+{buildMetadata}" : ToString("s"); } case "i": { - var buildMetadata = this.BuildMetaData.ToString("f"); + var buildMetadata = BuildMetaData.ToString("f"); - return !buildMetadata.IsNullOrEmpty() ? $"{ToString("s")}+{buildMetadata}" : ToString("s"); + return !string.IsNullOrEmpty(buildMetadata) ? $"{ToString("s")}+{buildMetadata}" : ToString("s"); } default: throw new FormatException($"Unknown format '{format}'."); @@ -343,10 +325,8 @@ public SemanticVersion IncrementVersion(VersionField incrementStrategy, string? var preReleaseTagNumber = PreReleaseTag.Number; if (PreReleaseTag.HasTag()) - { preReleaseTagNumber++; - } - else if (!label.IsNullOrEmpty()) + else if (!string.IsNullOrEmpty(label)) { preReleaseTagNumber = 1; preReleaseTagName = label; diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionBuildMetaData.cs b/src/GitVersion.Core/Git/SemanticVersionBuildMetaData.cs similarity index 89% rename from src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionBuildMetaData.cs rename to src/GitVersion.Core/Git/SemanticVersionBuildMetaData.cs index 85ca1bf4ff..5da88b7efb 100644 --- a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionBuildMetaData.cs +++ b/src/GitVersion.Core/Git/SemanticVersionBuildMetaData.cs @@ -87,15 +87,15 @@ public string ToString(string? format, IFormatProvider? formatProvider) if (formatProvider?.GetFormat(GetType()) is ICustomFormatter formatter) return formatter.Format(format, this, formatProvider); - if (format.IsNullOrEmpty()) + if (string.IsNullOrEmpty(format)) format = "b"; format = format.ToLower(); return format.ToLower() switch { "b" => $"{this.CommitsSinceTag}", - "s" => $"{this.CommitsSinceTag}{(this.Sha.IsNullOrEmpty() ? null : ".Sha." + this.Sha)}".TrimStart('.'), - "f" => $"{this.CommitsSinceTag}{(this.Branch.IsNullOrEmpty() ? null : ".Branch." + FormatMetaDataPart(this.Branch))}{(this.Sha.IsNullOrEmpty() ? null : ".Sha." + this.Sha)}{(this.OtherMetaData.IsNullOrEmpty() ? null : "." + FormatMetaDataPart(this.OtherMetaData))}".TrimStart('.'), + "s" => $"{this.CommitsSinceTag}{(string.IsNullOrEmpty(this.Sha) ? null : ".Sha." + this.Sha)}".TrimStart('.'), + "f" => $"{this.CommitsSinceTag}{(string.IsNullOrEmpty(this.Branch) ? null : ".Branch." + FormatMetaDataPart(this.Branch))}{(string.IsNullOrEmpty(this.Sha) ? null : ".Sha." + this.Sha)}{(string.IsNullOrEmpty(this.OtherMetaData) ? null : "." + FormatMetaDataPart(this.OtherMetaData))}".TrimStart('.'), _ => throw new FormatException($"Unknown format '{format}'.") }; } @@ -112,7 +112,7 @@ public string ToString(string? format, IFormatProvider? formatProvider) public static SemanticVersionBuildMetaData Parse(string? buildMetaData) { - if (buildMetaData.IsNullOrEmpty()) + if (string.IsNullOrEmpty(buildMetaData)) return Empty; var parsed = ParseRegex.Match(buildMetaData); @@ -135,7 +135,7 @@ public static SemanticVersionBuildMetaData Parse(string? buildMetaData) buildMetaDataSha = parsed.Groups["Sha"].Value; string? buildMetaDataOtherMetaData = null; - if (parsed.Groups["Other"].Success && !parsed.Groups["Other"].Value.IsNullOrEmpty()) + if (parsed.Groups["Other"].Success && !string.IsNullOrEmpty(parsed.Groups["Other"].Value)) buildMetaDataOtherMetaData = parsed.Groups["Other"].Value.TrimStart('.'); return new() @@ -150,7 +150,7 @@ public static SemanticVersionBuildMetaData Parse(string? buildMetaData) private static string FormatMetaDataPart(string value) { - if (!value.IsNullOrEmpty()) + if (!string.IsNullOrEmpty(value)) value = Regex.Replace(value, "[^0-9A-Za-z-.]", "-"); return value; } diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormat.cs b/src/GitVersion.Core/Git/SemanticVersionFormat.cs similarity index 100% rename from src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionFormat.cs rename to src/GitVersion.Core/Git/SemanticVersionFormat.cs diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionPreReleaseTag.cs b/src/GitVersion.Core/Git/SemanticVersionPreReleaseTag.cs similarity index 93% rename from src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionPreReleaseTag.cs rename to src/GitVersion.Core/Git/SemanticVersionPreReleaseTag.cs index bf88e20489..d474f69bb0 100644 --- a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionPreReleaseTag.cs +++ b/src/GitVersion.Core/Git/SemanticVersionPreReleaseTag.cs @@ -70,7 +70,7 @@ public SemanticVersionPreReleaseTag(SemanticVersionPreReleaseTag preReleaseTag) public static SemanticVersionPreReleaseTag Parse(string? preReleaseTag) { - if (preReleaseTag.IsNullOrEmpty()) + if (string.IsNullOrEmpty(preReleaseTag)) { return new SemanticVersionPreReleaseTag(); } @@ -118,18 +118,17 @@ public string ToString(string? format, IFormatProvider? formatProvider) if (formatProvider?.GetFormat(GetType()) is ICustomFormatter formatter) return formatter.Format(format, this, formatProvider); - if (format.IsNullOrEmpty()) + if (string.IsNullOrEmpty(format)) format = "t"; format = format.ToLower(); return format switch { - "t" => (Number.HasValue ? Name.IsNullOrEmpty() ? $"{Number}" : $"{Name}.{Number}" : Name ?? string.Empty), + "t" => (Number.HasValue ? string.IsNullOrEmpty(Name) ? $"{Number}" : $"{Name}.{Number}" : Name ?? string.Empty), _ => throw new FormatException($"Unknown format '{format}'.") }; } - public bool HasTag() => - !Name.IsNullOrEmpty() || (Number.HasValue && PromotedFromCommits != true); + public bool HasTag() => !string.IsNullOrEmpty(Name) || (Number.HasValue && PromotedFromCommits != true); } diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/VersionField.cs b/src/GitVersion.Core/Git/VersionField.cs similarity index 100% rename from src/GitVersion.Core/VersionCalculation/SemanticVersioning/VersionField.cs rename to src/GitVersion.Core/Git/VersionField.cs diff --git a/src/GitVersion.Core/Core/Exceptions/WarningException.cs b/src/GitVersion.Core/Git/WarningException.cs similarity index 100% rename from src/GitVersion.Core/Core/Exceptions/WarningException.cs rename to src/GitVersion.Core/Git/WarningException.cs diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt index 56c7c56a78..1286de50e6 100644 --- a/src/GitVersion.Core/PublicAPI.Unshipped.txt +++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt @@ -557,7 +557,7 @@ GitVersion.OutputVariables.VersionVariablesJsonModel.WeightedPreReleaseNumber.ge GitVersion.OutputVariables.VersionVariablesJsonModel.WeightedPreReleaseNumber.set -> void GitVersion.OutputVariables.VersionVariablesJsonStringConverter GitVersion.OutputVariables.VersionVariablesJsonStringConverter.VersionVariablesJsonStringConverter() -> void -GitVersion.ReferenceNameExtensions +GitVersion.ReferenceName.TryGetSemanticVersion(out (GitVersion.SemanticVersion! Value, string? Name) result, System.Text.RegularExpressions.Regex! versionPatternRegex, string? labelPrefix, GitVersion.SemanticVersionFormat format) -> bool GitVersion.RefSpecDirection GitVersion.RefSpecDirection.Fetch = 0 -> GitVersion.RefSpecDirection GitVersion.RefSpecDirection.Push = 1 -> GitVersion.RefSpecDirection @@ -887,7 +887,6 @@ static GitVersion.OutputVariables.VersionVariablesHelper.ToJsonString(this GitVe static GitVersion.ReferenceName.FromBranchName(string! branchName) -> GitVersion.ReferenceName! static GitVersion.ReferenceName.Parse(string! canonicalName) -> GitVersion.ReferenceName! static GitVersion.ReferenceName.TryParse(out GitVersion.ReferenceName? value, string! canonicalName) -> bool -static GitVersion.ReferenceNameExtensions.TryGetSemanticVersion(this GitVersion.ReferenceName! source, out (GitVersion.SemanticVersion! Value, string? Name) result, System.Text.RegularExpressions.Regex! versionPatternRegex, string? labelPrefix, GitVersion.SemanticVersionFormat format) -> bool static GitVersion.SemanticVersion.Parse(string! version, string? tagPrefixRegex, GitVersion.SemanticVersionFormat versionFormat = GitVersion.SemanticVersionFormat.Strict) -> GitVersion.SemanticVersion! static GitVersion.SemanticVersion.TryParse(string! version, string? tagPrefixRegex, out GitVersion.SemanticVersion? semanticVersion, GitVersion.SemanticVersionFormat format = GitVersion.SemanticVersionFormat.Strict) -> bool static GitVersion.SemanticVersion.operator !=(GitVersion.SemanticVersion? v1, GitVersion.SemanticVersion? v2) -> bool diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/ReferenceNameExtensions.cs b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/ReferenceNameExtensions.cs deleted file mode 100644 index 09664f5290..0000000000 --- a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/ReferenceNameExtensions.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; -using System.Text.RegularExpressions; -using GitVersion.Extensions; - -namespace GitVersion; - -public static class ReferenceNameExtensions -{ - public static bool TryGetSemanticVersion(this ReferenceName source, - [NotNullWhen(true)] out (SemanticVersion Value, string? Name) result, - Regex versionPatternRegex, string? labelPrefix, SemanticVersionFormat format) - { - source.NotNull(); - - result = default; - - Contract.Assume(versionPatternRegex.ToString().StartsWith("^")); - - int length = 0; - foreach (var branchPart in source.WithoutOrigin.Split(GetBranchSeparator(source))) - { - if (branchPart.IsNullOrEmpty()) return false; - - var match = versionPatternRegex.NotNull().Match(branchPart); - if (match.Success) - { - var versionPart = match.Groups["version"].Value; - if (SemanticVersion.TryParse(versionPart, labelPrefix, out var semanticVersion, format)) - { - length += versionPart.Length; - var name = source.WithoutOrigin[length..].Trim('-'); - result = new(semanticVersion, name.IsEmpty() ? null : name); - return true; - } - } - length += branchPart.Length + 1; - } - - return false; - } - - private static char GetBranchSeparator(ReferenceName source) - => source.WithoutOrigin.Contains('/') || !source.WithoutOrigin.Contains('-') ? '/' : '-'; -} From fa54904f311589310fbc68857e1dd32ab029efa7 Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Tue, 4 Apr 2023 08:15:40 +0200 Subject: [PATCH 10/14] Integrate some StringExtensions function into GitVersionCommon/Extensions --- .../Extensions/StringExtensions.cs | 18 ++++ src/GitVersion.Core/Git/ReferenceName.cs | 4 +- src/GitVersion.Core/Git/SemanticVersion.cs | 88 ++++++++++++------- .../Git/SemanticVersionBuildMetaData.cs | 12 +-- .../Git/SemanticVersionPreReleaseTag.cs | 9 +- 5 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 new-cli/GitVersion.Common/Extensions/StringExtensions.cs diff --git a/new-cli/GitVersion.Common/Extensions/StringExtensions.cs b/new-cli/GitVersion.Common/Extensions/StringExtensions.cs new file mode 100644 index 0000000000..6a47c5a5e5 --- /dev/null +++ b/new-cli/GitVersion.Common/Extensions/StringExtensions.cs @@ -0,0 +1,18 @@ +using System.Diagnostics.CodeAnalysis; + +namespace GitVersion.Extensions +{ + public static class StringExtensions + { + public static bool IsEquivalentTo(this string self, string? other) => + string.Equals(self, other, StringComparison.OrdinalIgnoreCase); + + /// + public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value) => string.IsNullOrEmpty(value); + + /// + public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value) => string.IsNullOrWhiteSpace(value); + + public static bool IsEmpty([NotNullWhen(false)] this string? value) => string.Empty.Equals(value); + } +} diff --git a/src/GitVersion.Core/Git/ReferenceName.cs b/src/GitVersion.Core/Git/ReferenceName.cs index 4393a51734..960df6de18 100644 --- a/src/GitVersion.Core/Git/ReferenceName.cs +++ b/src/GitVersion.Core/Git/ReferenceName.cs @@ -79,7 +79,9 @@ public static ReferenceName FromBranchName(string branchName) public override string ToString() => Friendly; public bool TryGetSemanticVersion([NotNullWhen(true)] out (SemanticVersion Value, string? Name) result, - Regex versionPatternRegex, string? labelPrefix, SemanticVersionFormat format) + Regex versionPatternRegex, + string? labelPrefix, + SemanticVersionFormat format) { result = default; diff --git a/src/GitVersion.Core/Git/SemanticVersion.cs b/src/GitVersion.Core/Git/SemanticVersion.cs index e557d93ea7..a68dd49faf 100644 --- a/src/GitVersion.Core/Git/SemanticVersion.cs +++ b/src/GitVersion.Core/Git/SemanticVersion.cs @@ -28,37 +28,39 @@ public class SemanticVersion : IFormattable, IComparable, IEqua public SemanticVersionBuildMetaData BuildMetaData { get; init; } - public bool IsLabeledWith(string value) => PreReleaseTag.HasTag() && string.Equals(PreReleaseTag.Name, value, StringComparison.OrdinalIgnoreCase); + public bool IsLabeledWith(string value) => PreReleaseTag.HasTag() && PreReleaseTag.Name.IsEquivalentTo(value); public bool IsMatchForBranchSpecificLabel(string? value) => PreReleaseTag.Name == string.Empty || value is null || IsLabeledWith(value); public SemanticVersion(long major = 0, long minor = 0, long patch = 0) { - Major = major; - Minor = minor; - Patch = patch; - PreReleaseTag = new SemanticVersionPreReleaseTag(); - BuildMetaData = new SemanticVersionBuildMetaData(); + this.Major = major; + this.Minor = minor; + this.Patch = patch; + this.PreReleaseTag = new SemanticVersionPreReleaseTag(); + this.BuildMetaData = new SemanticVersionBuildMetaData(); } public SemanticVersion(SemanticVersion semanticVersion) { semanticVersion.NotNull(); - Major = semanticVersion.Major; - Minor = semanticVersion.Minor; - Patch = semanticVersion.Patch; + this.Major = semanticVersion.Major; + this.Minor = semanticVersion.Minor; + this.Patch = semanticVersion.Patch; - PreReleaseTag = new SemanticVersionPreReleaseTag(semanticVersion.PreReleaseTag); - BuildMetaData = new SemanticVersionBuildMetaData(semanticVersion.BuildMetaData); + this.PreReleaseTag = new SemanticVersionPreReleaseTag(semanticVersion.PreReleaseTag); + this.BuildMetaData = new SemanticVersionBuildMetaData(semanticVersion.BuildMetaData); } public bool Equals(SemanticVersion? obj) { if (obj == null) + { return false; - return Major == obj.Major && Minor == obj.Minor && Patch == obj.Patch && PreReleaseTag == obj.PreReleaseTag && BuildMetaData == obj.BuildMetaData; + } + return this.Major == obj.Major && this.Minor == obj.Minor && this.Patch == obj.Patch && this.PreReleaseTag == obj.PreReleaseTag && this.BuildMetaData == obj.BuildMetaData; } public bool IsEmpty() => Equals(Empty); @@ -66,9 +68,13 @@ public bool Equals(SemanticVersion? obj) public override bool Equals(object? obj) { if (obj is null) + { return false; + } if (ReferenceEquals(this, obj)) + { return true; + } return obj.GetType() == GetType() && Equals((SemanticVersion)obj); } @@ -76,11 +82,11 @@ public override int GetHashCode() { unchecked { - var hashCode = Major.GetHashCode(); - hashCode = hashCode * 397 ^ Minor.GetHashCode(); - hashCode = hashCode * 397 ^ Patch.GetHashCode(); - hashCode = hashCode * 397 ^ PreReleaseTag.GetHashCode(); - hashCode = hashCode * 397 ^ BuildMetaData.GetHashCode(); + var hashCode = this.Major.GetHashCode(); + hashCode = (hashCode * 397) ^ this.Minor.GetHashCode(); + hashCode = (hashCode * 397) ^ this.Patch.GetHashCode(); + hashCode = (hashCode * 397) ^ this.PreReleaseTag.GetHashCode(); + hashCode = (hashCode * 397) ^ this.BuildMetaData.GetHashCode(); return hashCode; } } @@ -88,7 +94,9 @@ public override int GetHashCode() public static bool operator ==(SemanticVersion? v1, SemanticVersion? v2) { if (v1 is null) + { return v2 is null; + } return v1.Equals(v2); } @@ -217,29 +225,39 @@ private static bool TryParseLoose(string version, [NotNullWhen(true)] out Semant public int CompareTo(SemanticVersion? value, bool includePrerelease) { if (value == null) + { return 1; - if (Major != value.Major) + } + if (this.Major != value.Major) { - if (Major > value.Major) + if (this.Major > value.Major) + { return 1; + } return -1; } - if (Minor != value.Minor) + if (this.Minor != value.Minor) { - if (Minor > value.Minor) + if (this.Minor > value.Minor) + { return 1; + } return -1; } - if (Patch != value.Patch) + if (this.Patch != value.Patch) { - if (Patch > value.Patch) + if (this.Patch > value.Patch) + { return 1; + } return -1; } - if (includePrerelease && PreReleaseTag != value.PreReleaseTag) + if (includePrerelease && this.PreReleaseTag != value.PreReleaseTag) { - if (PreReleaseTag > value.PreReleaseTag) + if (this.PreReleaseTag > value.PreReleaseTag) + { return 1; + } return -1; } @@ -259,7 +277,7 @@ public int CompareTo(SemanticVersion? value, bool includePrerelease) /// public string ToString(string? format, IFormatProvider? formatProvider) { - if (string.IsNullOrEmpty(format)) + if (format.IsNullOrEmpty()) format = "s"; if (formatProvider?.GetFormat(GetType()) is ICustomFormatter formatter) @@ -270,22 +288,22 @@ public string ToString(string? format, IFormatProvider? formatProvider) switch (format) { case "j": - return $"{Major}.{Minor}.{Patch}"; + return $"{this.Major}.{this.Minor}.{this.Patch}"; case "s": - return PreReleaseTag.HasTag() ? $"{ToString("j")}-{PreReleaseTag}" : ToString("j"); + return this.PreReleaseTag.HasTag() ? $"{ToString("j")}-{this.PreReleaseTag}" : ToString("j"); case "t": - return PreReleaseTag.HasTag() ? $"{ToString("j")}-{PreReleaseTag.ToString("t")}" : ToString("j"); + return this.PreReleaseTag.HasTag() ? $"{ToString("j")}-{this.PreReleaseTag.ToString("t")}" : ToString("j"); case "f": { - var buildMetadata = BuildMetaData.ToString(); + var buildMetadata = this.BuildMetaData.ToString(); - return !string.IsNullOrEmpty(buildMetadata) ? $"{ToString("s")}+{buildMetadata}" : ToString("s"); + return !buildMetadata.IsNullOrEmpty() ? $"{ToString("s")}+{buildMetadata}" : ToString("s"); } case "i": { - var buildMetadata = BuildMetaData.ToString("f"); + var buildMetadata = this.BuildMetaData.ToString("f"); - return !string.IsNullOrEmpty(buildMetadata) ? $"{ToString("s")}+{buildMetadata}" : ToString("s"); + return !buildMetadata.IsNullOrEmpty() ? $"{ToString("s")}+{buildMetadata}" : ToString("s"); } default: throw new FormatException($"Unknown format '{format}'."); @@ -325,8 +343,10 @@ public SemanticVersion IncrementVersion(VersionField incrementStrategy, string? var preReleaseTagNumber = PreReleaseTag.Number; if (PreReleaseTag.HasTag()) + { preReleaseTagNumber++; - else if (!string.IsNullOrEmpty(label)) + } + else if (!label.IsNullOrEmpty()) { preReleaseTagNumber = 1; preReleaseTagName = label; diff --git a/src/GitVersion.Core/Git/SemanticVersionBuildMetaData.cs b/src/GitVersion.Core/Git/SemanticVersionBuildMetaData.cs index 5da88b7efb..85ca1bf4ff 100644 --- a/src/GitVersion.Core/Git/SemanticVersionBuildMetaData.cs +++ b/src/GitVersion.Core/Git/SemanticVersionBuildMetaData.cs @@ -87,15 +87,15 @@ public string ToString(string? format, IFormatProvider? formatProvider) if (formatProvider?.GetFormat(GetType()) is ICustomFormatter formatter) return formatter.Format(format, this, formatProvider); - if (string.IsNullOrEmpty(format)) + if (format.IsNullOrEmpty()) format = "b"; format = format.ToLower(); return format.ToLower() switch { "b" => $"{this.CommitsSinceTag}", - "s" => $"{this.CommitsSinceTag}{(string.IsNullOrEmpty(this.Sha) ? null : ".Sha." + this.Sha)}".TrimStart('.'), - "f" => $"{this.CommitsSinceTag}{(string.IsNullOrEmpty(this.Branch) ? null : ".Branch." + FormatMetaDataPart(this.Branch))}{(string.IsNullOrEmpty(this.Sha) ? null : ".Sha." + this.Sha)}{(string.IsNullOrEmpty(this.OtherMetaData) ? null : "." + FormatMetaDataPart(this.OtherMetaData))}".TrimStart('.'), + "s" => $"{this.CommitsSinceTag}{(this.Sha.IsNullOrEmpty() ? null : ".Sha." + this.Sha)}".TrimStart('.'), + "f" => $"{this.CommitsSinceTag}{(this.Branch.IsNullOrEmpty() ? null : ".Branch." + FormatMetaDataPart(this.Branch))}{(this.Sha.IsNullOrEmpty() ? null : ".Sha." + this.Sha)}{(this.OtherMetaData.IsNullOrEmpty() ? null : "." + FormatMetaDataPart(this.OtherMetaData))}".TrimStart('.'), _ => throw new FormatException($"Unknown format '{format}'.") }; } @@ -112,7 +112,7 @@ public string ToString(string? format, IFormatProvider? formatProvider) public static SemanticVersionBuildMetaData Parse(string? buildMetaData) { - if (string.IsNullOrEmpty(buildMetaData)) + if (buildMetaData.IsNullOrEmpty()) return Empty; var parsed = ParseRegex.Match(buildMetaData); @@ -135,7 +135,7 @@ public static SemanticVersionBuildMetaData Parse(string? buildMetaData) buildMetaDataSha = parsed.Groups["Sha"].Value; string? buildMetaDataOtherMetaData = null; - if (parsed.Groups["Other"].Success && !string.IsNullOrEmpty(parsed.Groups["Other"].Value)) + if (parsed.Groups["Other"].Success && !parsed.Groups["Other"].Value.IsNullOrEmpty()) buildMetaDataOtherMetaData = parsed.Groups["Other"].Value.TrimStart('.'); return new() @@ -150,7 +150,7 @@ public static SemanticVersionBuildMetaData Parse(string? buildMetaData) private static string FormatMetaDataPart(string value) { - if (!string.IsNullOrEmpty(value)) + if (!value.IsNullOrEmpty()) value = Regex.Replace(value, "[^0-9A-Za-z-.]", "-"); return value; } diff --git a/src/GitVersion.Core/Git/SemanticVersionPreReleaseTag.cs b/src/GitVersion.Core/Git/SemanticVersionPreReleaseTag.cs index d474f69bb0..bf88e20489 100644 --- a/src/GitVersion.Core/Git/SemanticVersionPreReleaseTag.cs +++ b/src/GitVersion.Core/Git/SemanticVersionPreReleaseTag.cs @@ -70,7 +70,7 @@ public SemanticVersionPreReleaseTag(SemanticVersionPreReleaseTag preReleaseTag) public static SemanticVersionPreReleaseTag Parse(string? preReleaseTag) { - if (string.IsNullOrEmpty(preReleaseTag)) + if (preReleaseTag.IsNullOrEmpty()) { return new SemanticVersionPreReleaseTag(); } @@ -118,17 +118,18 @@ public string ToString(string? format, IFormatProvider? formatProvider) if (formatProvider?.GetFormat(GetType()) is ICustomFormatter formatter) return formatter.Format(format, this, formatProvider); - if (string.IsNullOrEmpty(format)) + if (format.IsNullOrEmpty()) format = "t"; format = format.ToLower(); return format switch { - "t" => (Number.HasValue ? string.IsNullOrEmpty(Name) ? $"{Number}" : $"{Name}.{Number}" : Name ?? string.Empty), + "t" => (Number.HasValue ? Name.IsNullOrEmpty() ? $"{Number}" : $"{Name}.{Number}" : Name ?? string.Empty), _ => throw new FormatException($"Unknown format '{format}'.") }; } - public bool HasTag() => !string.IsNullOrEmpty(Name) || (Number.HasValue && PromotedFromCommits != true); + public bool HasTag() => + !Name.IsNullOrEmpty() || (Number.HasValue && PromotedFromCommits != true); } From 3ade5b3cc64643c6d20e64244c36bb5d4cdee16c Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Tue, 4 Apr 2023 08:35:41 +0200 Subject: [PATCH 11/14] Add additional unit test --- .../VersionInMergedBranchNameScenarios.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/GitVersion.Core.Tests/IntegrationTests/VersionInMergedBranchNameScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/VersionInMergedBranchNameScenarios.cs index 63e297e7bd..dcfc66d484 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/VersionInMergedBranchNameScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/VersionInMergedBranchNameScenarios.cs @@ -26,6 +26,21 @@ public void DoesNotTakeVersionFromNameOfNonReleaseBranch() fixture.AssertFullSemver("1.1.0-alpha.5"); } + [TestCase("release")] + [TestCase("hotfix")] + public void DoesNotTakeVersionFromNameWhenItHasBeenAccidentalSpecifiedInBranch(string branch) + { + using var fixture = new EmptyRepositoryFixture("main"); + + fixture.MakeATaggedCommit("1.0.0"); + fixture.BranchTo($"{branch}/downgrade-some-lib-to-3.2.1"); + fixture.MakeACommit(); + fixture.Checkout("main"); + fixture.MergeNoFF($"{branch}/downgrade-some-lib-to-3.2.1"); + + fixture.AssertFullSemver("1.0.1+2"); + } + [Test] public void TakesVersionFromNameOfBranchThatIsReleaseByConfig() { From fec1a637dea303a265e075e6f51055273c9f44fe Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Tue, 4 Apr 2023 10:08:17 +0200 Subject: [PATCH 12/14] Link StringExtensions class as reference to new-cli solution --- new-cli/Directory.Build.props | 1 + .../Extensions/StringExtensions.cs | 18 ------------------ .../GitVersion.Common/GitVersion.Common.csproj | 1 + .../Helpers/EncodingHelper.cs | 2 -- .../Infrastructure/IFileSystem.cs | 2 -- .../Infrastructure/FileSystem.cs | 1 - 6 files changed, 2 insertions(+), 23 deletions(-) delete mode 100644 new-cli/GitVersion.Common/Extensions/StringExtensions.cs diff --git a/new-cli/Directory.Build.props b/new-cli/Directory.Build.props index 00858bc1be..28d31920d5 100644 --- a/new-cli/Directory.Build.props +++ b/new-cli/Directory.Build.props @@ -16,6 +16,7 @@ + diff --git a/new-cli/GitVersion.Common/Extensions/StringExtensions.cs b/new-cli/GitVersion.Common/Extensions/StringExtensions.cs deleted file mode 100644 index 6a47c5a5e5..0000000000 --- a/new-cli/GitVersion.Common/Extensions/StringExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace GitVersion.Extensions -{ - public static class StringExtensions - { - public static bool IsEquivalentTo(this string self, string? other) => - string.Equals(self, other, StringComparison.OrdinalIgnoreCase); - - /// - public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value) => string.IsNullOrEmpty(value); - - /// - public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value) => string.IsNullOrWhiteSpace(value); - - public static bool IsEmpty([NotNullWhen(false)] this string? value) => string.Empty.Equals(value); - } -} diff --git a/new-cli/GitVersion.Common/GitVersion.Common.csproj b/new-cli/GitVersion.Common/GitVersion.Common.csproj index 0284be2ba5..6b7ac37412 100644 --- a/new-cli/GitVersion.Common/GitVersion.Common.csproj +++ b/new-cli/GitVersion.Common/GitVersion.Common.csproj @@ -3,6 +3,7 @@ + Git\AuthenticationInfo.cs diff --git a/new-cli/GitVersion.Common/Helpers/EncodingHelper.cs b/new-cli/GitVersion.Common/Helpers/EncodingHelper.cs index 8615d10b64..8f0e3af85f 100644 --- a/new-cli/GitVersion.Common/Helpers/EncodingHelper.cs +++ b/new-cli/GitVersion.Common/Helpers/EncodingHelper.cs @@ -1,5 +1,3 @@ -using System.Text; - namespace GitVersion.Helpers; public static class EncodingHelper diff --git a/new-cli/GitVersion.Common/Infrastructure/IFileSystem.cs b/new-cli/GitVersion.Common/Infrastructure/IFileSystem.cs index b446910030..1c1f8dd9db 100644 --- a/new-cli/GitVersion.Common/Infrastructure/IFileSystem.cs +++ b/new-cli/GitVersion.Common/Infrastructure/IFileSystem.cs @@ -1,5 +1,3 @@ -using System.Text; - namespace GitVersion.Infrastructure; public interface IFileSystem diff --git a/new-cli/GitVersion.Core/Infrastructure/FileSystem.cs b/new-cli/GitVersion.Core/Infrastructure/FileSystem.cs index 5893736006..f656879283 100644 --- a/new-cli/GitVersion.Core/Infrastructure/FileSystem.cs +++ b/new-cli/GitVersion.Core/Infrastructure/FileSystem.cs @@ -1,4 +1,3 @@ -using System.Text; using GitVersion.Helpers; namespace GitVersion.Infrastructure; From 907579cf30916857e0f7dde489aba0fcf1161747 Mon Sep 17 00:00:00 2001 From: Hardy Hobeck Date: Tue, 4 Apr 2023 20:42:15 +0200 Subject: [PATCH 13/14] Try to fix [remark-lint] reported by reviewdog Incorrect list-item indent: add 2 spaces list-item-indent remark-lint --- BREAKING_CHANGES.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 1287c7cf78..938f6449f3 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -23,10 +23,10 @@ * Following root configuration properties have been removed: * continuous-delivery-fallback-tag * A new branch related property with name `track-merge-message` has been introduced. Consider we have a `main` branch and a `release/1.0.0` branch and merge changes from `release/1.0.0` to the main branch. In this scenario the merge message will be interpreted as a next version `1.0.0` when `track-merge-message` is set to `true` otherwise `0.0.1`. -* The pre-release tags are only considered when they are matching with the label name of the branch. This has an effect on the way how the `CommitCountSource` will be determined. -* The process of increasing the version with bump message when `CommitMessageIncrementing` is enabled and increment strategy is `None` has been changed. -* A new configuration property with name `version-in-branch-pattern` has been introduced. This setting only applies on branches where the option `is-release-branch` is set to `true`. Please notice that the branch name needs to be defined after the version number by default (instead of `support/lts-2.0.0` please name the branch like `support/2.0.0-lts`). -* The `is-release-branch` property of the `hotfix` branch setting has been changed from `false` to `true`. If present the hotfix number will be considered now by default. +* The pre-release tags are only considered when they are matching with the label name of the branch. This has an effect on the way how the `CommitCountSource` will be determined. +* The process of increasing the version with bump message when `CommitMessageIncrementing` is enabled and increment strategy is `None` has been changed. +* A new configuration property with name `version-in-branch-pattern` has been introduced. This setting only applies on branches where the option `is-release-branch` is set to `true`. Please notice that the branch name needs to be defined after the version number by default (instead of `support/lts-2.0.0` please name the branch like `support/2.0.0-lts`). +* The `is-release-branch` property of the `hotfix` branch setting has been changed from `false` to `true`. If present the hotfix number will be considered now by default. ## v5.0.0 From 3795785919bee06dbb2ed31d51afe0aca4ab4efe Mon Sep 17 00:00:00 2001 From: Hardy Hobeck <56404113+HHobeck@users.noreply.github.com> Date: Wed, 5 Apr 2023 08:40:42 +0200 Subject: [PATCH 14/14] Update src/GitVersion.Core.Tests/IntegrationTests/VersionInMergedBranchNameScenarios.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Asbjørn Ulsberg --- .../IntegrationTests/VersionInMergedBranchNameScenarios.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitVersion.Core.Tests/IntegrationTests/VersionInMergedBranchNameScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/VersionInMergedBranchNameScenarios.cs index dcfc66d484..39ca78f3c2 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/VersionInMergedBranchNameScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/VersionInMergedBranchNameScenarios.cs @@ -28,7 +28,7 @@ public void DoesNotTakeVersionFromNameOfNonReleaseBranch() [TestCase("release")] [TestCase("hotfix")] - public void DoesNotTakeVersionFromNameWhenItHasBeenAccidentalSpecifiedInBranch(string branch) + public void DoesNotTakeVersionFromBranchWithAccidentalVersion(string branch) { using var fixture = new EmptyRepositoryFixture("main");