diff --git a/docs/input/docs/reference/configuration.md b/docs/input/docs/reference/configuration.md index 59eacc4e5f..97fe064c79 100644 --- a/docs/input/docs/reference/configuration.md +++ b/docs/input/docs/reference/configuration.md @@ -522,7 +522,7 @@ branches: Strategy which will look for tagged merge commits directly off the current branch. For example `develop` → `release/1.0.0` → merge into `main` and tag -`1.0.0`. The tag is *not* on develop, but develop should be version `1.0.0` now. +`1.0.0`. The tag is _not_ on develop, but develop should be version `1.0.0` now. ### tracks-release-branches @@ -551,6 +551,19 @@ is set, it would be added to the `PreReleaseNumber` to get a final `pre-release-weight` will be used in the calculation. Related Issues [1145] and [1366]. +### semver-format + +Specifies the semver format that is used when parsing the string. +Can be `Strict` - using the [regex](https://regex101.com/r/Ly7O1x/3/) +or `Loose` the old way of parsing. The default if not specified is `Strict` +Example of invalid `Strict`, but valid `Loose` + +``` +1.2-alpha4 +01.02.03-rc03 +1.2.3.4 +``` + [1145]: https://github.com/GitTools/GitVersion/issues/1145 [1366]: https://github.com/GitTools/GitVersion/issues/1366 [2506]: https://github.com/GitTools/GitVersion/pull/2506#issuecomment-754754037 diff --git a/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs b/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs index 107e6a3bd9..ca669db1d2 100644 --- a/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs +++ b/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs @@ -288,7 +288,7 @@ public void ConfigChangeInvalidatesCache() versionVariables.AssemblySemVer.ShouldBe("4.10.3.0"); var configPath = PathHelper.Combine(fixture.RepositoryPath, ConfigFileLocator.DefaultFileName); - this.fileSystem.WriteAllText(configPath, "next-version: 5.0"); + this.fileSystem.WriteAllText(configPath, "next-version: 5.0.0"); gitVersionCalculator = GetGitVersionCalculator(gitVersionOptions, fs: this.fileSystem); diff --git a/src/GitVersion.Core.Tests/Helpers/TestEffectiveConfiguration.cs b/src/GitVersion.Core.Tests/Helpers/TestEffectiveConfiguration.cs index 06809a62a1..4a7cd9777e 100644 --- a/src/GitVersion.Core.Tests/Helpers/TestEffectiveConfiguration.cs +++ b/src/GitVersion.Core.Tests/Helpers/TestEffectiveConfiguration.cs @@ -56,6 +56,7 @@ public TestEffectiveConfiguration( isRelease, commitDateFormat, updateBuildNumber, + SemanticVersionFormat.Strict, 0, 0) { diff --git a/src/GitVersion.Core.Tests/IntegrationTests/BranchWithoutCommitScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/BranchWithoutCommitScenarios.cs index b2fa760ada..eeed898772 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/BranchWithoutCommitScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/BranchWithoutCommitScenarios.cs @@ -31,8 +31,8 @@ public void BranchVersionHavePrecedenceOverTagVersionIfVersionGreaterThanTag() fixture.Checkout("develop"); fixture.MakeATaggedCommit("0.1.0-alpha.1"); // simulate merge from feature branch - fixture.Repository.CreateBranch("release/1.0"); - fixture.Checkout("release/1.0"); + fixture.Repository.CreateBranch("release/1.0.0"); + fixture.Checkout("release/1.0.0"); fixture.AssertFullSemver("1.0.0-beta.1+0"); } diff --git a/src/GitVersion.Core.Tests/IntegrationTests/FeatureBranchScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/FeatureBranchScenarios.cs index 9f3d0f0575..12f97532c7 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/FeatureBranchScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/FeatureBranchScenarios.cs @@ -263,7 +263,7 @@ public void ShouldPickUpVersionFromDevelopAfterReleaseBranchCreated() fixture.MakeACommit(); fixture.BranchTo("develop"); fixture.MakeACommit(); - fixture.BranchTo("release/1.0"); + fixture.BranchTo("release/1.0.0"); fixture.MakeACommit(); fixture.Checkout("develop"); fixture.MakeACommit(); @@ -282,12 +282,12 @@ public void ShouldPickUpVersionFromDevelopAfterReleaseBranchMergedBack() fixture.MakeACommit(); fixture.BranchTo("develop"); fixture.MakeACommit(); - fixture.BranchTo("release/1.0"); + fixture.BranchTo("release/1.0.0"); fixture.MakeACommit(); // merge release into develop fixture.Checkout("develop"); - fixture.MergeNoFF("release/1.0"); + fixture.MergeNoFF("release/1.0.0"); fixture.AssertFullSemver("1.1.0-alpha.2"); // create a feature branch from develop and verify the version @@ -317,7 +317,7 @@ public void ShouldPickUpVersionFromMainAfterReleaseBranchCreated() using var fixture = new EmptyRepositoryFixture(); // Create release branch fixture.MakeACommit(); - fixture.BranchTo("release/1.0"); + fixture.BranchTo("release/1.0.0"); fixture.MakeACommit(); fixture.Checkout(MainBranch); fixture.MakeACommit(); @@ -348,12 +348,12 @@ public void ShouldPickUpVersionFromMainAfterReleaseBranchMergedBack() using var fixture = new EmptyRepositoryFixture(); // Create release branch fixture.MakeACommit(); - fixture.BranchTo("release/1.0"); + fixture.BranchTo("release/1.0.0"); fixture.MakeACommit(); // merge release into main fixture.Checkout(MainBranch); - fixture.MergeNoFF("release/1.0"); + fixture.MergeNoFF("release/1.0.0"); fixture.AssertFullSemver("1.0.1+2", config); // create a feature branch from main and verify the version @@ -372,7 +372,7 @@ public void ShouldPickUpVersionFromMainAfterReleaseBranchCreated() fixture.MakeACommit(); fixture.BranchTo("develop"); fixture.MakeACommit(); - fixture.BranchTo("release/1.0"); + fixture.BranchTo("release/1.0.0"); fixture.MakeACommit(); fixture.Checkout("develop"); fixture.MakeACommit(); @@ -391,12 +391,12 @@ public void ShouldPickUpVersionFromDevelopAfterReleaseBranchMergedBack() fixture.MakeACommit(); fixture.BranchTo("develop"); fixture.MakeACommit(); - fixture.BranchTo("release/1.0"); + fixture.BranchTo("release/1.0.0"); fixture.MakeACommit(); // merge release into develop fixture.Checkout("develop"); - fixture.MergeNoFF("release/1.0"); + fixture.MergeNoFF("release/1.0.0"); fixture.AssertFullSemver("1.1.0-alpha.2"); // create a misnamed feature branch (i.e. it uses the default config) from develop and verify the version @@ -427,7 +427,7 @@ public void ShouldPickUpVersionFromMainAfterReleaseBranchCreated() using var fixture = new EmptyRepositoryFixture(); // Create release branch fixture.MakeACommit(); - fixture.BranchTo("release/1.0"); + fixture.BranchTo("release/1.0.0"); fixture.MakeACommit(); fixture.Checkout(MainBranch); fixture.MakeACommit(); @@ -458,12 +458,12 @@ public void ShouldPickUpVersionFromMainAfterReleaseBranchMergedBack() using var fixture = new EmptyRepositoryFixture(); // Create release branch fixture.MakeACommit(); - fixture.BranchTo("release/1.0"); + fixture.BranchTo("release/1.0.0"); fixture.MakeACommit(); // merge release into main fixture.Checkout(MainBranch); - fixture.MergeNoFF("release/1.0"); + fixture.MergeNoFF("release/1.0.0"); fixture.AssertFullSemver("1.0.1+2", config); // create a misnamed feature branch (i.e. it uses the default config) from main and verify the version diff --git a/src/GitVersion.Core.Tests/IntegrationTests/ReleaseBranchScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/ReleaseBranchScenarios.cs index 0fd75f14a8..30ef7f92a6 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/ReleaseBranchScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/ReleaseBranchScenarios.cs @@ -485,11 +485,11 @@ public static void ReleaseBranchShouldUseBranchNameVersionDespiteBumpInPreviousC public void ReleaseBranchWithACommitShouldUseBranchNameVersionDespiteBumpInPreviousCommit() { using var fixture = new EmptyRepositoryFixture(); - fixture.Repository.MakeATaggedCommit("1.0"); + fixture.Repository.MakeATaggedCommit("1.0.0"); fixture.Repository.MakeACommit("+semver:major"); fixture.Repository.MakeACommit(); - fixture.BranchTo("release/2.0"); + fixture.BranchTo("release/2.0.0"); fixture.Repository.MakeACommit(); @@ -500,10 +500,10 @@ public void ReleaseBranchWithACommitShouldUseBranchNameVersionDespiteBumpInPrevi public void ReleaseBranchedAtCommitWithSemverMessageShouldUseBranchNameVersion() { using var fixture = new EmptyRepositoryFixture(); - fixture.Repository.MakeATaggedCommit("1.0"); + fixture.Repository.MakeATaggedCommit("1.0.0"); fixture.Repository.MakeACommit("+semver:major"); - fixture.BranchTo("release/2.0"); + fixture.BranchTo("release/2.0.0"); fixture.AssertFullSemver("2.0.0-beta.1+1"); } diff --git a/src/GitVersion.Core.Tests/IntegrationTests/RemoteRepositoryScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/RemoteRepositoryScenarios.cs index b85daea32e..7bc38a0226 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/RemoteRepositoryScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/RemoteRepositoryScenarios.cs @@ -23,7 +23,7 @@ public void GivenARemoteGitRepositoryWithCommitsThenClonedLocalShouldMatchRemote [Test] public void GivenARemoteGitRepositoryWithCommitsAndBranchesThenClonedLocalShouldMatchRemoteVersion() { - const string targetBranch = "release-1.0"; + const string targetBranch = "release-1.0.0"; using var fixture = new RemoteRepositoryFixture( path => { diff --git a/src/GitVersion.Core.Tests/IntegrationTests/SwitchingToGitFlowScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/SwitchingToGitFlowScenarios.cs index 6f8fd6fce9..aedfba97ce 100644 --- a/src/GitVersion.Core.Tests/IntegrationTests/SwitchingToGitFlowScenarios.cs +++ b/src/GitVersion.Core.Tests/IntegrationTests/SwitchingToGitFlowScenarios.cs @@ -13,7 +13,7 @@ public void WhenDevelopBranchedFromMainWithLegacyVersionTagsDevelopCanUseReachab { using var fixture = new EmptyRepositoryFixture(); fixture.Repository.MakeCommits(5); - fixture.Repository.MakeATaggedCommit("1.0.0.0"); + fixture.Repository.MakeATaggedCommit("1.0.0"); fixture.Repository.MakeCommits(2); Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("develop")); fixture.AssertFullSemver("1.1.0-alpha.2"); diff --git a/src/GitVersion.Core.Tests/Model/MergeMessageTests.cs b/src/GitVersion.Core.Tests/Model/MergeMessageTests.cs index 132e8526b1..ab4ab72a03 100644 --- a/src/GitVersion.Core.Tests/Model/MergeMessageTests.cs +++ b/src/GitVersion.Core.Tests/Model/MergeMessageTests.cs @@ -56,8 +56,8 @@ public void EmptyTagPrefix(string prefix) new object?[] { "Merge branch 'origin/feature/one'", "origin/feature/one", null, null }, new object?[] { $"Merge tag 'v4.0.0' into {MainBranch}", "v4.0.0", MainBranch, new SemanticVersion(4) }, new object?[] { $"Merge tag 'V4.0.0' into {MainBranch}", "V4.0.0", MainBranch, new SemanticVersion(4) }, - new object?[] { "Merge branch 'feature/4.1/one'", "feature/4.1/one", null, new SemanticVersion(4, 1) }, - new object?[] { "Merge branch 'origin/4.1/feature/one'", "origin/4.1/feature/one", null, new SemanticVersion(4, 1) }, + new object?[] { "Merge branch 'feature/4.1.0/one'", "feature/4.1.0/one", null, new SemanticVersion(4, 1) }, + new object?[] { "Merge branch 'origin/4.1.0/feature/one'", "origin/4.1.0/feature/one", null, new SemanticVersion(4, 1) }, new object?[] { $"Merge tag 'v://10.10.10.10' into {MainBranch}", "v://10.10.10.10", MainBranch, null } }; @@ -86,7 +86,7 @@ public void ParsesMergeMessage( new object?[] { "Merge pull request #1234 in feature/one", "feature/one", null, null, 1234 }, new object?[] { "Merge pull request #1234 in v4.0.0", "v4.0.0", null, new SemanticVersion(4), 1234 }, new object?[] { "Merge pull request #1234 from origin/feature/one", "origin/feature/one", null, null, 1234 }, - new object?[] { "Merge pull request #1234 in feature/4.1/one", "feature/4.1/one", null, new SemanticVersion(4,1), 1234 }, + new object?[] { "Merge pull request #1234 in feature/4.1.0/one", "feature/4.1.0/one", null, new SemanticVersion(4,1), 1234 }, new object?[] { "Merge pull request #1234 in V://10.10.10.10", "V://10.10.10.10", null, null, 1234 }, new object?[] { "Merge pull request #1234 from feature/one into dev", "feature/one", "dev", null, 1234 } }; @@ -116,8 +116,8 @@ public void ParsesGitHubPullMergeMessage( 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/two to dev", "origin/feature/4.2/two", "dev", new SemanticVersion(4,2), 1234 }, - new object?[] { "Merge pull request #1234 in feature/4.1/one from feature/4.2/two to dev", "feature/4.2/two", "dev", new SemanticVersion(4,2), 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 @@ -147,11 +147,11 @@ public void ParsesBitBucketPullMergeMessage( private static readonly object[] BitBucketPullMergeMessages_v7 = { - new object[] { $@"Pull request #68: Release/2.2 + new object[] { $@"Pull request #68: Release/2.2.0 -Merge in aaa/777 from release/2.2 to {MainBranch} +Merge in aaa/777 from release/2.2.0 to {MainBranch} -* commit '750aa37753dec1a85b22cc16db851187649d9e97':", "release/2.2", MainBranch, new SemanticVersion(2,2), 68 } +* commit '750aa37753dec1a85b22cc16db851187649d9e97':", "release/2.2.0", MainBranch, new SemanticVersion(2,2), 68 } }; [TestCaseSource(nameof(BitBucketPullMergeMessages_v7))] @@ -179,8 +179,8 @@ public void ParsesBitBucketPullMergeMessage_v7( new object?[] { "Finish feature/one", "feature/one", null, null }, new object?[] { "Finish origin/feature/one", "origin/feature/one", null, null }, new object?[] { "Finish v4.0.0", "v4.0.0", null, new SemanticVersion(4) }, - new object?[] { "Finish feature/4.1/one", "feature/4.1/one", null, new SemanticVersion(4, 1) }, - new object?[] { "Finish origin/4.1/feature/one", "origin/4.1/feature/one", null, new SemanticVersion(4, 1) }, + new object?[] { "Finish feature/4.1.0/one", "feature/4.1.0/one", null, new SemanticVersion(4, 1) }, + new object?[] { "Finish origin/4.1.0/feature/one", "origin/4.1.0/feature/one", null, new SemanticVersion(4, 1) }, new object?[] { "Finish V://10.10.10.10", "V://10.10.10.10", null, null }, new object?[] { $"Finish V4.0.0 into {MainBranch}", "V4.0.0", MainBranch, new SemanticVersion(4) } }; @@ -210,8 +210,8 @@ public void ParsesSmartGitMergeMessage( new object?[] { "Merge remote-tracking branch 'origin/feature/one' into dev", "origin/feature/one", "dev", null }, new object?[] { $"Merge remote-tracking branch 'v4.0.0' into {MainBranch}", "v4.0.0", MainBranch, new SemanticVersion(4) }, new object?[] { $"Merge remote-tracking branch 'V4.0.0' into {MainBranch}", "V4.0.0", MainBranch, new SemanticVersion(4) }, - new object?[] { "Merge remote-tracking branch 'feature/4.1/one' into dev", "feature/4.1/one", "dev", new SemanticVersion(4, 1) }, - new object?[] { $"Merge remote-tracking branch 'origin/4.1/feature/one' into {MainBranch}", "origin/4.1/feature/one", MainBranch, new SemanticVersion(4, 1) }, + new object?[] { "Merge remote-tracking branch 'feature/4.1.0/one' into dev", "feature/4.1.0/one", "dev", new SemanticVersion(4, 1) }, + new object?[] { $"Merge remote-tracking branch 'origin/4.1.0/feature/one' into {MainBranch}", "origin/4.1.0/feature/one", MainBranch, new SemanticVersion(4, 1) }, new object?[] { $"Merge remote-tracking branch 'v://10.10.10.10' into {MainBranch}", "v://10.10.10.10", MainBranch, null } }; @@ -321,7 +321,7 @@ public void MatchesCaptureGroupsFromCustomMessages() }; const int pr = 1234; const string target = MainBranch; - const string source = "feature/2.0/example"; + const string source = "feature/2.0.0/example"; // Act var sut = new MergeMessage($"Merged PR #{pr} into {target} from {source}", this.config); diff --git a/src/GitVersion.Core.Tests/VersionCalculation/SemanticVersionTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/SemanticVersionTests.cs index 58e5463762..d2789ab88e 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/SemanticVersionTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/SemanticVersionTests.cs @@ -8,43 +8,44 @@ namespace GitVersion.Core.Tests; [TestFixture] public class SemanticVersionTests : TestBase { - [TestCase("1.2.3", 1, 2, 3, null, null, null, null, null, null, null, null)] - [TestCase("1.2", 1, 2, 0, null, null, null, null, null, null, "1.2.0", null)] - [TestCase("1.2.3-beta", 1, 2, 3, "beta", null, null, null, null, null, null, null)] - [TestCase("1.2.3-beta3", 1, 2, 3, "beta", 3, null, null, null, null, "1.2.3-beta.3", null)] - [TestCase("1.2.3-beta.3", 1, 2, 3, "beta", 3, null, null, null, null, "1.2.3-beta.3", null)] - [TestCase("1.2.3-beta-3", 1, 2, 3, "beta-3", null, null, null, null, null, "1.2.3-beta-3", null)] - [TestCase("1.2.3-alpha", 1, 2, 3, "alpha", null, null, null, null, null, null, null)] - [TestCase("1.2-alpha4", 1, 2, 0, "alpha", 4, null, null, null, null, "1.2.0-alpha.4", null)] - [TestCase("1.2.3-rc", 1, 2, 3, "rc", null, null, null, null, null, null, null)] - [TestCase("1.2.3-rc3", 1, 2, 3, "rc", 3, null, null, null, null, "1.2.3-rc.3", null)] - [TestCase("1.2.3-3", 1, 2, 3, "", 3, null, null, null, null, "1.2.3-3", null)] - [TestCase("1.2.3-RC3", 1, 2, 3, "RC", 3, null, null, null, null, "1.2.3-RC.3", null)] - [TestCase("1.2.3-rc3.1", 1, 2, 3, "rc3", 1, null, null, null, null, "1.2.3-rc3.1", null)] - [TestCase("01.02.03-rc03", 1, 2, 3, "rc", 3, null, null, null, null, "1.2.3-rc.3", null)] - [TestCase("1.2.3-beta3f", 1, 2, 3, "beta3f", null, null, null, null, null, null, null)] - [TestCase("1.2.3-notAStability1", 1, 2, 3, "notAStability", 1, null, null, null, null, "1.2.3-notAStability.1", null)] - [TestCase("1.2.3.4", 1, 2, 3, null, null, 4, null, null, null, "1.2.3+4", null)] - [TestCase("1.2.3+4", 1, 2, 3, null, null, 4, null, null, null, null, null)] - [TestCase("1.2.3+4.Branch.Foo", 1, 2, 3, null, null, 4, "Foo", null, null, null, null)] - [TestCase("1.2.3+randomMetaData", 1, 2, 3, null, null, null, null, null, "randomMetaData", null, null)] - [TestCase("1.2.3-beta.1+4.Sha.12234.Othershiz", 1, 2, 3, "beta", 1, 4, null, "12234", "Othershiz", null, null)] - [TestCase("1.2.3", 1, 2, 3, null, null, null, null, null, null, null, Config.DefaultTagPrefix)] - [TestCase("v1.2.3", 1, 2, 3, null, null, null, null, null, null, "1.2.3", Config.DefaultTagPrefix)] - [TestCase("V1.2.3", 1, 2, 3, null, null, null, null, null, null, "1.2.3", Config.DefaultTagPrefix)] - [TestCase("version-1.2.3", 1, 2, 3, null, null, null, null, null, null, "1.2.3", "version-")] - [TestCase("1", 1, 0, 0, null, null, null, null, null, null, "1.0.0", null)] - [TestCase("1.1", 1, 1, 0, null, null, null, null, null, null, "1.1.0", null)] - [TestCase("1.0.0-develop-20201007113711", 1, 0, 0, "develop-20201007113711", null, null, null, null, null, "1.0.0-develop-20201007113711", null)] - [TestCase("20201007113711.658165168461351.64136516984163213-develop-20201007113711.98848747823+65416321321", 20201007113711, 658165168461351, 64136516984163213, "develop-20201007113711", 98848747823, 65416321321, null, null, null, "20201007113711.658165168461351.64136516984163213-develop-20201007113711.98848747823+65416321321", null)] + [TestCase("1.2.3", 1, 2, 3, null, null, null, null, null, null, null, null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-beta", 1, 2, 3, "beta", null, null, null, null, null, null, null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-beta3", 1, 2, 3, "beta", 3, null, null, null, null, "1.2.3-beta.3", null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-beta.3", 1, 2, 3, "beta", 3, null, null, null, null, "1.2.3-beta.3", null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-beta-3", 1, 2, 3, "beta-3", null, null, null, null, null, "1.2.3-beta-3", null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-alpha", 1, 2, 3, "alpha", null, null, null, null, null, null, null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-rc", 1, 2, 3, "rc", null, null, null, null, null, null, null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-rc3", 1, 2, 3, "rc", 3, null, null, null, null, "1.2.3-rc.3", null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-3", 1, 2, 3, "", 3, null, null, null, null, "1.2.3-3", null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-RC3", 1, 2, 3, "RC", 3, null, null, null, null, "1.2.3-RC.3", null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-rc3.1", 1, 2, 3, "rc3", 1, null, null, null, null, "1.2.3-rc3.1", null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-beta3f", 1, 2, 3, "beta3f", null, null, null, null, null, null, null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-notAStability1", 1, 2, 3, "notAStability", 1, null, null, null, null, "1.2.3-notAStability.1", null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3+4", 1, 2, 3, null, null, 4, null, null, null, null, null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3+4.Branch.Foo", 1, 2, 3, null, null, 4, "Foo", null, null, null, null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3+randomMetaData", 1, 2, 3, null, null, null, null, null, "randomMetaData", null, null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3-beta.1+4.Sha.12234.Othershiz", 1, 2, 3, "beta", 1, 4, null, "12234", "Othershiz", null, null, SemanticVersionFormat.Strict)] + [TestCase("1.2.3", 1, 2, 3, null, null, null, null, null, null, null, Config.DefaultTagPrefix, SemanticVersionFormat.Strict)] + [TestCase("v1.2.3", 1, 2, 3, null, null, null, null, null, null, "1.2.3", Config.DefaultTagPrefix, SemanticVersionFormat.Strict)] + [TestCase("V1.2.3", 1, 2, 3, null, null, null, null, null, null, "1.2.3", Config.DefaultTagPrefix, SemanticVersionFormat.Strict)] + [TestCase("version-1.2.3", 1, 2, 3, null, null, null, null, null, null, "1.2.3", "version-", SemanticVersionFormat.Strict)] + [TestCase("1.0.0-develop-20201007113711", 1, 0, 0, "develop-20201007113711", null, null, null, null, null, "1.0.0-develop-20201007113711", null, SemanticVersionFormat.Strict)] + [TestCase("20201007113711.658165168461351.64136516984163213-develop-20201007113711.98848747823+65416321321", 20201007113711, 658165168461351, 64136516984163213, "develop-20201007113711", 98848747823, 65416321321, null, null, null, "20201007113711.658165168461351.64136516984163213-develop-20201007113711.98848747823+65416321321", null, SemanticVersionFormat.Strict)] + + [TestCase("1.2", 1, 2, 0, null, null, null, null, null, null, "1.2.0", null, SemanticVersionFormat.Loose)] + [TestCase("1.2-alpha4", 1, 2, 0, "alpha", 4, null, null, null, null, "1.2.0-alpha.4", null, SemanticVersionFormat.Loose)] + [TestCase("01.02.03-rc03", 1, 2, 3, "rc", 3, null, null, null, null, "1.2.3-rc.3", null, SemanticVersionFormat.Loose)] + [TestCase("1.2.3.4", 1, 2, 3, null, null, 4, null, null, null, "1.2.3+4", null, SemanticVersionFormat.Loose)] + [TestCase("1", 1, 0, 0, null, null, null, null, null, null, "1.0.0", null, SemanticVersionFormat.Loose)] + [TestCase("1.1", 1, 1, 0, null, null, null, null, null, null, "1.1.0", null, SemanticVersionFormat.Loose)] public void ValidateVersionParsing( string? versionString, long major, long minor, long patch, string? tag, long? tagNumber, long? numberOfBuilds, - string? branchName, string? sha, string? otherMetaData, string? fullFormattedVersionString, string? tagPrefixRegex) + string? branchName, string? sha, string? otherMetaData, string? fullFormattedVersionString, string? tagPrefixRegex, SemanticVersionFormat format = SemanticVersionFormat.Strict) { fullFormattedVersionString ??= versionString; versionString.ShouldNotBeNull(); - SemanticVersion.TryParse(versionString, tagPrefixRegex, out var version).ShouldBe(true, versionString); + SemanticVersion.TryParse(versionString, tagPrefixRegex, out var version, format).ShouldBe(true, versionString); version.ShouldNotBeNull(); Assert.AreEqual(major, version.Major); diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/ConfigNextVersionBaseVersionStrategyTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/ConfigNextVersionBaseVersionStrategyTests.cs index 773aebcb18..c57e418dd9 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/ConfigNextVersionBaseVersionStrategyTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/ConfigNextVersionBaseVersionStrategyTests.cs @@ -19,8 +19,6 @@ public void ReturnsNullWhenNoNextVersionIsInConfig() } [TestCase("1.0.0", "1.0.0")] - [TestCase("2", "2.0.0")] - [TestCase("2.118998723", "2.118998723.0")] [TestCase("2.12.654651698", "2.12.654651698")] public void ConfigNextVersionTest(string nextVersion, string expectedVersion) { diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs index 4d1ededce0..0b4ba7188b 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs @@ -53,7 +53,6 @@ public void ShouldNotAllowIncrementOfVersion() [TestCase("Merge branch 'release-0.1.5'\n\nRelates to: TicketId", true, "0.1.5")] [TestCase("Finish Release-0.12.0", true, "0.12.0")] //Support Syntevo SmartGit/Hg's Gitflow merge commit messages for finishing a 'Release' branch [TestCase("Merge branch 'Release-v0.2.0'", true, "0.2.0")] - [TestCase("Merge branch 'Release-v2.2'", true, "2.2.0")] [TestCase("Merge remote-tracking branch 'origin/release/0.8.0' into develop/" + MainBranch, true, "0.8.0")] [TestCase("Merge remote-tracking branch 'refs/remotes/origin/release/2.0.0'", true, "2.0.0")] public void TakesVersionFromMergeOfReleaseBranch(string message, bool isMergeCommit, string expectedVersion) diff --git a/src/GitVersion.Core.Tests/VersionCalculation/VersionSourceTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/VersionSourceTests.cs index 57dac3edcd..93191e424e 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/VersionSourceTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/VersionSourceTests.cs @@ -53,7 +53,7 @@ public void VersionSourceShaUsingTag() _ = fixture.Repository.MakeACommit(); Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("develop")); var secondCommit = fixture.Repository.MakeACommit(); - _ = fixture.Repository.Tags.Add("1.0", secondCommit); + _ = fixture.Repository.Tags.Add("1.0.0", secondCommit); var featureBranch = fixture.Repository.CreateBranch("feature/foo"); Commands.Checkout(fixture.Repository, featureBranch); _ = fixture.Repository.MakeACommit(); diff --git a/src/GitVersion.Core/Configuration/ConfigurationBuilder.cs b/src/GitVersion.Core/Configuration/ConfigurationBuilder.cs index 98fd36bca5..104b662e5e 100644 --- a/src/GitVersion.Core/Configuration/ConfigurationBuilder.cs +++ b/src/GitVersion.Core/Configuration/ConfigurationBuilder.cs @@ -54,6 +54,7 @@ private static void ApplyOverrides(Config targetConfig, Config overrideConfig) targetConfig.CommitDateFormat = overrideConfig.CommitDateFormat ?? targetConfig.CommitDateFormat; targetConfig.MergeMessageFormats = overrideConfig.MergeMessageFormats.Any() ? overrideConfig.MergeMessageFormats : targetConfig.MergeMessageFormats; targetConfig.UpdateBuildNumber = overrideConfig.UpdateBuildNumber ?? targetConfig.UpdateBuildNumber; + targetConfig.SemanticVersionFormat = overrideConfig.SemanticVersionFormat; if (overrideConfig.Ignore is { IsEmpty: false }) { @@ -185,6 +186,7 @@ private static Config CreateDefaultConfiguration() CommitMessageIncrementing = CommitMessageIncrementMode.Enabled, CommitDateFormat = "yyyy-MM-dd", UpdateBuildNumber = true, + SemanticVersionFormat = SemanticVersionFormat.Strict, TagPreReleaseWeight = DefaultTagPreReleaseWeight }; diff --git a/src/GitVersion.Core/Model/Configuration/Config.cs b/src/GitVersion.Core/Model/Configuration/Config.cs index a6c340cc30..4188523fce 100644 --- a/src/GitVersion.Core/Model/Configuration/Config.cs +++ b/src/GitVersion.Core/Model/Configuration/Config.cs @@ -86,6 +86,9 @@ public string? NextVersion [YamlMember(Alias = "update-build-number")] public bool? UpdateBuildNumber { get; set; } + [YamlMember(Alias = "semver-format")] + public SemanticVersionFormat SemanticVersionFormat { get; set; } = SemanticVersionFormat.Strict; + public override string ToString() { var stringBuilder = new StringBuilder(); diff --git a/src/GitVersion.Core/Model/Configuration/EffectiveConfiguration.cs b/src/GitVersion.Core/Model/Configuration/EffectiveConfiguration.cs index c9eec627f5..ad2ae203c8 100644 --- a/src/GitVersion.Core/Model/Configuration/EffectiveConfiguration.cs +++ b/src/GitVersion.Core/Model/Configuration/EffectiveConfiguration.cs @@ -71,6 +71,7 @@ public EffectiveConfiguration(Config configuration, BranchConfig currentBranchCo IsCurrentBranchRelease = currentBranchConfig.IsReleaseBranch.Value; CommitDateFormat = configuration.CommitDateFormat; UpdateBuildNumber = configuration.UpdateBuildNumber ?? true; + SemanticVersionFormat = configuration.SemanticVersionFormat; PreReleaseWeight = currentBranchConfig.PreReleaseWeight ?? 0; TagPreReleaseWeight = configuration.TagPreReleaseWeight.Value; } @@ -100,6 +101,7 @@ protected EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningSche bool isCurrentBranchRelease, string? commitDateFormat, bool updateBuildNumber, + SemanticVersionFormat semanticVersionFormat, int preReleaseWeight, int tagPreReleaseWeight) { @@ -128,6 +130,7 @@ protected EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningSche IsCurrentBranchRelease = isCurrentBranchRelease; CommitDateFormat = commitDateFormat; UpdateBuildNumber = updateBuildNumber; + SemanticVersionFormat = semanticVersionFormat; PreReleaseWeight = preReleaseWeight; TagPreReleaseWeight = tagPreReleaseWeight; } @@ -181,6 +184,8 @@ protected EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningSche public bool UpdateBuildNumber { get; } + public SemanticVersionFormat SemanticVersionFormat { get; set; } = SemanticVersionFormat.Strict; + public int PreReleaseWeight { get; } public int TagPreReleaseWeight { get; } diff --git a/src/GitVersion.Core/PublicAPI.Shipped.txt b/src/GitVersion.Core/PublicAPI.Shipped.txt index 4c4b273b51..cdcf7df1b7 100644 --- a/src/GitVersion.Core/PublicAPI.Shipped.txt +++ b/src/GitVersion.Core/PublicAPI.Shipped.txt @@ -656,6 +656,8 @@ GitVersion.Model.Configuration.Config.UpdateBuildNumber.get -> bool? GitVersion.Model.Configuration.Config.UpdateBuildNumber.set -> void GitVersion.Model.Configuration.Config.VersioningMode.get -> GitVersion.VersionCalculation.VersioningMode? GitVersion.Model.Configuration.Config.VersioningMode.set -> void +GitVersion.Model.Configuration.Config.SemanticVersionFormat.get -> GitVersion.SemanticVersionFormat +GitVersion.Model.Configuration.Config.SemanticVersionFormat.set -> void GitVersion.Model.Configuration.EffectiveConfiguration GitVersion.Model.Configuration.EffectiveConfiguration.AssemblyFileVersioningFormat.get -> string? GitVersion.Model.Configuration.EffectiveConfiguration.AssemblyFileVersioningScheme.get -> GitVersion.Extensions.AssemblyFileVersioningScheme @@ -667,6 +669,7 @@ GitVersion.Model.Configuration.EffectiveConfiguration.CommitDateFormat.get -> st GitVersion.Model.Configuration.EffectiveConfiguration.CommitMessageIncrementing.get -> GitVersion.VersionCalculation.CommitMessageIncrementMode GitVersion.Model.Configuration.EffectiveConfiguration.Configuration.get -> GitVersion.Model.Configuration.Config! GitVersion.Model.Configuration.EffectiveConfiguration.ContinuousDeploymentFallbackTag.get -> string? +GitVersion.Model.Configuration.EffectiveConfiguration.EffectiveConfiguration(GitVersion.Extensions.AssemblyVersioningScheme assemblyVersioningScheme, GitVersion.Extensions.AssemblyFileVersioningScheme assemblyFileVersioningScheme, string? assemblyInformationalFormat, string? assemblyVersioningFormat, string? assemblyFileVersioningFormat, GitVersion.VersionCalculation.VersioningMode versioningMode, string? gitTagPrefix, string? tag, string? nextVersion, GitVersion.IncrementStrategy increment, string? branchPrefixToTrim, bool preventIncrementForMergedBranchVersion, string? tagNumberPattern, string? continuousDeploymentFallbackTag, bool trackMergeTarget, string? majorVersionBumpMessage, string? minorVersionBumpMessage, string? patchVersionBumpMessage, string? noBumpMessage, GitVersion.VersionCalculation.CommitMessageIncrementMode commitMessageIncrementing, System.Collections.Generic.IEnumerable! versionFilters, bool tracksReleaseBranches, bool isCurrentBranchRelease, string? commitDateFormat, bool updateBuildNumber, GitVersion.SemanticVersionFormat semanticVersionFormat, int preReleaseWeight, int tagPreReleaseWeight) -> void GitVersion.Model.Configuration.EffectiveConfiguration.EffectiveConfiguration(GitVersion.Model.Configuration.Config! configuration, GitVersion.Model.Configuration.BranchConfig! currentBranchConfig) -> void GitVersion.Model.Configuration.EffectiveConfiguration.GitTagPrefix.get -> string? GitVersion.Model.Configuration.EffectiveConfiguration.Increment.get -> GitVersion.IncrementStrategy @@ -686,6 +689,8 @@ GitVersion.Model.Configuration.EffectiveConfiguration.TracksReleaseBranches.get GitVersion.Model.Configuration.EffectiveConfiguration.UpdateBuildNumber.get -> bool GitVersion.Model.Configuration.EffectiveConfiguration.VersionFilters.get -> System.Collections.Generic.IEnumerable! GitVersion.Model.Configuration.EffectiveConfiguration.VersioningMode.get -> GitVersion.VersionCalculation.VersioningMode +GitVersion.Model.Configuration.EffectiveConfiguration.SemanticVersionFormat.get -> GitVersion.SemanticVersionFormat +GitVersion.Model.Configuration.EffectiveConfiguration.SemanticVersionFormat.set -> void GitVersion.Model.Configuration.IgnoreConfig GitVersion.Model.Configuration.IgnoreConfig.Before.get -> System.DateTimeOffset? GitVersion.Model.Configuration.IgnoreConfig.Before.set -> void @@ -836,6 +841,9 @@ GitVersion.RepositoryStore.IsCommitOnBranch(GitVersion.ICommit? baseVersionSourc GitVersion.RepositoryStore.MaybeIncrement(GitVersion.VersionCalculation.BaseVersion! baseVersion, GitVersion.GitVersionContext! context) -> GitVersion.SemanticVersion! GitVersion.RepositoryStore.RepositoryStore(GitVersion.Logging.ILog! log, GitVersion.IGitRepository! repository, GitVersion.VersionCalculation.IIncrementStrategyFinder! incrementStrategyFinder) -> void GitVersion.SemanticVersion +GitVersion.SemanticVersionFormat +GitVersion.SemanticVersionFormat.Loose = 1 -> GitVersion.SemanticVersionFormat +GitVersion.SemanticVersionFormat.Strict = 0 -> GitVersion.SemanticVersionFormat GitVersion.SemanticVersion.BuildMetaData -> GitVersion.SemanticVersionBuildMetaData? GitVersion.SemanticVersion.CompareTo(GitVersion.SemanticVersion! value) -> int GitVersion.SemanticVersion.CompareTo(GitVersion.SemanticVersion? value, bool includePrerelease) -> int @@ -1322,8 +1330,8 @@ static GitVersion.SemanticVersion.operator <=(GitVersion.SemanticVersion! v1, Gi static GitVersion.SemanticVersion.operator ==(GitVersion.SemanticVersion? v1, GitVersion.SemanticVersion? v2) -> bool static GitVersion.SemanticVersion.operator >(GitVersion.SemanticVersion! v1, GitVersion.SemanticVersion! v2) -> bool static GitVersion.SemanticVersion.operator >=(GitVersion.SemanticVersion! v1, GitVersion.SemanticVersion! v2) -> bool -static GitVersion.SemanticVersion.Parse(string! version, string? tagPrefixRegex) -> GitVersion.SemanticVersion! -static GitVersion.SemanticVersion.TryParse(string! version, string? tagPrefixRegex, out GitVersion.SemanticVersion? semanticVersion) -> bool +static GitVersion.SemanticVersion.Parse(string! version, string? tagPrefixRegex, GitVersion.SemanticVersionFormat format = 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.SemanticVersionBuildMetaData.implicit operator GitVersion.SemanticVersionBuildMetaData!(string! preReleaseTag) -> GitVersion.SemanticVersionBuildMetaData! static GitVersion.SemanticVersionBuildMetaData.implicit operator string?(GitVersion.SemanticVersionBuildMetaData? preReleaseTag) -> string? static GitVersion.SemanticVersionBuildMetaData.operator !=(GitVersion.SemanticVersionBuildMetaData? left, GitVersion.SemanticVersionBuildMetaData? right) -> bool diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt index 863b6430c3..e69de29bb2 100644 --- a/src/GitVersion.Core/PublicAPI.Unshipped.txt +++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt @@ -1 +0,0 @@ -GitVersion.Model.Configuration.EffectiveConfiguration.EffectiveConfiguration(GitVersion.Extensions.AssemblyVersioningScheme assemblyVersioningScheme, GitVersion.Extensions.AssemblyFileVersioningScheme assemblyFileVersioningScheme, string? assemblyInformationalFormat, string? assemblyVersioningFormat, string? assemblyFileVersioningFormat, GitVersion.VersionCalculation.VersioningMode versioningMode, string? gitTagPrefix, string? tag, string? nextVersion, GitVersion.IncrementStrategy increment, string? branchPrefixToTrim, bool preventIncrementForMergedBranchVersion, string? tagNumberPattern, string? continuousDeploymentFallbackTag, bool trackMergeTarget, string? majorVersionBumpMessage, string? minorVersionBumpMessage, string? patchVersionBumpMessage, string? noBumpMessage, GitVersion.VersionCalculation.CommitMessageIncrementMode commitMessageIncrementing, System.Collections.Generic.IEnumerable! versionFilters, bool tracksReleaseBranches, bool isCurrentBranchRelease, string? commitDateFormat, bool updateBuildNumber, int preReleaseWeight, int tagPreReleaseWeight) -> void \ No newline at end of file diff --git a/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/ConfigNextVersionVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/ConfigNextVersionVersionStrategy.cs index be3ad26160..9317725c7c 100644 --- a/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/ConfigNextVersionVersionStrategy.cs +++ b/src/GitVersion.Core/VersionCalculation/BaseVersionCalculators/ConfigNextVersionVersionStrategy.cs @@ -18,7 +18,7 @@ public override IEnumerable GetVersions() var nextVersion = Context.Configuration.NextVersion; if (nextVersion.IsNullOrEmpty() || Context.IsCurrentCommitTagged) yield break; - var semanticVersion = SemanticVersion.Parse(nextVersion, Context.Configuration.GitTagPrefix); + var semanticVersion = SemanticVersion.Parse(nextVersion, Context.Configuration.GitTagPrefix, Context.Configuration.SemanticVersionFormat); yield return new BaseVersion("NextVersion in GitVersion configuration file", false, semanticVersion, null, null); } } diff --git a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersion.cs b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersion.cs index 902d827313..2cc0817873 100644 --- a/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersion.cs +++ b/src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersion.cs @@ -9,7 +9,12 @@ public class SemanticVersion : IFormattable, IComparable, IEqua { private static readonly SemanticVersion Empty = new(); - private static readonly Regex ParseSemVer = new( + // uses the git-semver spec https://github.com/semver/semver/blob/master/semver.md + private static readonly Regex ParseSemVerStrict = new( + @"^(?0|[1-9]\d*)\.(?0|[1-9]\d*)\.(?0|[1-9]\d*)(?:-(?(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + + private static readonly Regex ParseSemVerLoose = new( @"^(?(?\d+)(\.(?\d+))?(\.(?\d+))?)(\.(?\d+))?(-(?[^\+]*))?(\+(?.*))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -44,11 +49,7 @@ public bool Equals(SemanticVersion? obj) { return false; } - return this.Major == obj.Major && - this.Minor == obj.Minor && - this.Patch == obj.Patch && - this.PreReleaseTag == obj.PreReleaseTag && - this.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); @@ -96,6 +97,7 @@ public override int GetHashCode() throw new ArgumentNullException(nameof(v1)); if (v2 == null) throw new ArgumentNullException(nameof(v2)); + return v1.CompareTo(v2) > 0; } @@ -105,6 +107,7 @@ public override int GetHashCode() throw new ArgumentNullException(nameof(v1)); if (v2 == null) throw new ArgumentNullException(nameof(v2)); + return v1.CompareTo(v2) >= 0; } @@ -128,15 +131,15 @@ public override int GetHashCode() return v1.CompareTo(v2) < 0; } - public static SemanticVersion Parse(string version, string? tagPrefixRegex) + public static SemanticVersion Parse(string version, string? tagPrefixRegex, SemanticVersionFormat format = SemanticVersionFormat.Strict) { - if (!TryParse(version, tagPrefixRegex, out var semanticVersion)) + if (!TryParse(version, tagPrefixRegex, out var semanticVersion, format)) throw new WarningException($"Failed to parse {version} into a Semantic Version"); return semanticVersion; } - public static bool TryParse(string version, string? tagPrefixRegex, [NotNullWhen(true)] out SemanticVersion? semanticVersion) + public static bool TryParse(string version, string? tagPrefixRegex, [NotNullWhen(true)] out SemanticVersion? semanticVersion, SemanticVersionFormat format = SemanticVersionFormat.Strict) { var match = Regex.Match(version, $"^({tagPrefixRegex})?(?.*)$"); @@ -147,7 +150,36 @@ public static bool TryParse(string version, string? tagPrefixRegex, [NotNullWhen } version = match.Groups["version"].Value; - var parsed = ParseSemVer.Match(version); + return format == SemanticVersionFormat.Strict + ? TryParseStrict(version, out semanticVersion) + : TryParseLoose(version, out semanticVersion); + } + + private static bool TryParseStrict(string version, [NotNullWhen(true)] out SemanticVersion? semanticVersion) + { + var parsed = ParseSemVerStrict.Match(version); + + if (!parsed.Success) + { + semanticVersion = null; + return false; + } + + semanticVersion = new SemanticVersion + { + Major = long.Parse(parsed.Groups["major"].Value), + Minor = parsed.Groups["minor"].Success ? long.Parse(parsed.Groups["minor"].Value) : 0, + Patch = parsed.Groups["patch"].Success ? long.Parse(parsed.Groups["patch"].Value) : 0, + PreReleaseTag = SemanticVersionPreReleaseTag.Parse(parsed.Groups["prerelease"].Value), + BuildMetaData = SemanticVersionBuildMetaData.Parse(parsed.Groups["buildmetadata"].Value) + }; + + return true; + } + + private static bool TryParseLoose(string version, [NotNullWhen(true)] out SemanticVersion? semanticVersion) + { + var parsed = ParseSemVerLoose.Match(version); if (!parsed.Success) { @@ -305,3 +337,9 @@ public enum VersionField Minor, Major } + +public enum SemanticVersionFormat +{ + Strict, + Loose +}