diff --git a/GitVersionCore.Tests/Fixtures/BaseGitFlowRepositoryFixture.cs b/GitVersionCore.Tests/Fixtures/BaseGitFlowRepositoryFixture.cs
index 8c16dffaee..70b6d501d8 100644
--- a/GitVersionCore.Tests/Fixtures/BaseGitFlowRepositoryFixture.cs
+++ b/GitVersionCore.Tests/Fixtures/BaseGitFlowRepositoryFixture.cs
@@ -1,8 +1,6 @@
using System;
using System.IO;
-using System.Text;
using GitVersion;
-using GitVersion.Helpers;
using LibGit2Sharp;
///
@@ -41,19 +39,4 @@ void SetupRepo(Action initialMasterAction)
Repository.CreateBranch("develop").Checkout();
Repository.MakeACommit();
}
-
- public void DumpGraph()
- {
- var output = new StringBuilder();
-
- ProcessHelper.Run(
- o => output.AppendLine(o),
- e => output.AppendLineFormat("ERROR: {0}", e),
- null,
- "git",
- @"log --graph --abbrev-commit --decorate --date=relative --all",
- RepositoryPath);
-
- Console.Write(output.ToString());
- }
}
\ No newline at end of file
diff --git a/GitVersionCore.Tests/Fixtures/EmptyRepositoryFixture.cs b/GitVersionCore.Tests/Fixtures/EmptyRepositoryFixture.cs
index dc88f61b55..8726144b78 100644
--- a/GitVersionCore.Tests/Fixtures/EmptyRepositoryFixture.cs
+++ b/GitVersionCore.Tests/Fixtures/EmptyRepositoryFixture.cs
@@ -1,5 +1,7 @@
using System;
+using System.Text;
using GitVersion;
+using GitVersion.Helpers;
using LibGit2Sharp;
public class EmptyRepositoryFixture : RepositoryFixtureBase
@@ -9,6 +11,21 @@ public EmptyRepositoryFixture(Config configuration) :
{
}
+ public void DumpGraph()
+ {
+ var output = new StringBuilder();
+
+ ProcessHelper.Run(
+ o => output.AppendLine(o),
+ e => output.AppendLineFormat("ERROR: {0}", e),
+ null,
+ "git",
+ @"log --graph --abbrev-commit --decorate --date=relative --all",
+ RepositoryPath);
+
+ Console.Write(output.ToString());
+ }
+
static IRepository CreateNewRepository(string path)
{
LibGit2Sharp.Repository.Init(path);
diff --git a/GitVersionCore.Tests/GitVersionContextBuilder.cs b/GitVersionCore.Tests/GitVersionContextBuilder.cs
new file mode 100644
index 0000000000..6ff6455a18
--- /dev/null
+++ b/GitVersionCore.Tests/GitVersionContextBuilder.cs
@@ -0,0 +1,80 @@
+namespace GitVersionCore.Tests
+{
+ using GitVersion;
+ using LibGit2Sharp;
+
+ public class GitVersionContextBuilder
+ {
+ IRepository repository;
+ Config config;
+
+ public GitVersionContextBuilder WithRepository(IRepository repository)
+ {
+ this.repository = repository;
+ return this;
+ }
+
+ public GitVersionContextBuilder WithConfig(Config config)
+ {
+ this.config = config;
+ return this;
+ }
+
+ public GitVersionContextBuilder WithTaggedMaster()
+ {
+ repository = CreateRepository();
+ var target = repository.Head.Tip;
+ ((MockTagCollection)repository.Tags).Add(new MockTag ("1.0.0", target));
+ return this;
+ }
+
+ public GitVersionContextBuilder AddCommit()
+ {
+ ((MockBranch)repository.Head).Add(new MockCommit());
+ return this;
+ }
+
+ public GitVersionContextBuilder WithDevelopBranch()
+ {
+ return WithBranch("develop");
+ }
+
+ public GitVersionContextBuilder WithBranch(string branchName)
+ {
+ repository = CreateRepository();
+ return AddBranch(branchName);
+ }
+
+ public GitVersionContextBuilder AddBranch(string branchName)
+ {
+ var mockBranch = new MockBranch(branchName)
+ {
+ new MockCommit()
+ };
+ ((MockBranchCollection)repository.Branches).Add(mockBranch);
+ ((MockRepository)repository).Head = mockBranch;
+ return this;
+ }
+
+ public GitVersionContext Build()
+ {
+ return new GitVersionContext(repository ?? CreateRepository(), config ?? new Config());
+ }
+
+ IRepository CreateRepository()
+ {
+ var mockBranch = new MockBranch("master") { new MockCommit { CommitterEx = SignatureBuilder.SignatureNow() } };
+ var mockRepository = new MockRepository
+ {
+ Branches = new MockBranchCollection
+ {
+ mockBranch
+ },
+ Tags = new MockTagCollection(),
+ Head = mockBranch
+ };
+
+ return mockRepository;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore.Tests/GitVersionContextTests.cs b/GitVersionCore.Tests/GitVersionContextTests.cs
index 4bb04108a4..1b31db2850 100644
--- a/GitVersionCore.Tests/GitVersionContextTests.cs
+++ b/GitVersionCore.Tests/GitVersionContextTests.cs
@@ -1,6 +1,7 @@
namespace GitVersionCore.Tests
{
using GitVersion;
+ using LibGit2Sharp;
using NUnit.Framework;
using Shouldly;
@@ -50,5 +51,26 @@ public void UsesBranchSpecificConfigOverTopLevelDefaults()
context.Configuration.VersioningMode.ShouldBe(VersioningMode.ContinuousDeployment);
context.Configuration.Tag.ShouldBe("alpha");
}
+
+ [Test]
+ public void CanFindParentBranchForInheritingIncrementStrategy()
+ {
+ var config = new Config();
+ config.Branches["develop"].Increment = IncrementStrategy.Major;
+ config.Branches["feature[/-]"].Increment = IncrementStrategy.Inherit;
+
+ using (var repo = new EmptyRepositoryFixture(config))
+ {
+ repo.Repository.MakeACommit();
+ repo.Repository.CreateBranch("develop").Checkout();
+ repo.Repository.MakeACommit();
+ var featureBranch = repo.Repository.CreateBranch("feature/foo");
+ featureBranch.Checkout();
+ repo.Repository.MakeACommit();
+
+ var context = new GitVersionContext(repo.Repository, config);
+ context.Configuration.Increment.ShouldBe(IncrementStrategy.Major);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/GitVersionCore.Tests/GitVersionCore.Tests.csproj b/GitVersionCore.Tests/GitVersionCore.Tests.csproj
index 71ec916ba2..df8af3c75d 100644
--- a/GitVersionCore.Tests/GitVersionCore.Tests.csproj
+++ b/GitVersionCore.Tests/GitVersionCore.Tests.csproj
@@ -96,6 +96,7 @@
+
@@ -114,6 +115,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/GitVersionCore.Tests/IntegrationTests/GitFlow/DevelopScenarios.cs b/GitVersionCore.Tests/IntegrationTests/GitFlow/DevelopScenarios.cs
index debfe50352..b082dd493e 100644
--- a/GitVersionCore.Tests/IntegrationTests/GitFlow/DevelopScenarios.cs
+++ b/GitVersionCore.Tests/IntegrationTests/GitFlow/DevelopScenarios.cs
@@ -6,16 +6,29 @@
public class DevelopScenarios
{
[Test]
- public void WhenDevelopBranchedFromMaster_MinorIsIncreased()
+ public void WhenDevelopBranchedFromTaggedCommitOnMasterVersionDoesNotChange()
{
using (var fixture = new EmptyRepositoryFixture(new Config()))
{
fixture.Repository.MakeATaggedCommit("1.0.0");
fixture.Repository.CreateBranch("develop").Checkout();
+ // TODO Should actually be 1.0.0+0
fixture.AssertFullSemver("1.1.0-unstable.0+0");
}
}
+ [Test]
+ public void WhenDevelopBranchedFromMaster_MinorIsIncreased()
+ {
+ using (var fixture = new EmptyRepositoryFixture(new Config()))
+ {
+ fixture.Repository.MakeATaggedCommit("1.0.0");
+ fixture.Repository.CreateBranch("develop").Checkout();
+ fixture.Repository.MakeACommit();
+ fixture.AssertFullSemver("1.1.0-unstable.1+1");
+ }
+ }
+
[Test]
public void MergingReleaseBranchBackIntoDevelopWithoutMergingToMaster_DoesNotBumpDevelopVersion()
{
@@ -23,12 +36,13 @@ public void MergingReleaseBranchBackIntoDevelopWithoutMergingToMaster_DoesNotBum
{
fixture.Repository.MakeATaggedCommit("1.0.0");
fixture.Repository.CreateBranch("develop").Checkout();
+ fixture.Repository.MakeACommit();
fixture.Repository.CreateBranch("release-2.0.0").Checkout();
fixture.AssertFullSemver("2.0.0-beta.1+0");
fixture.Repository.Checkout("develop");
- fixture.AssertFullSemver("1.1.0-unstable.0+0");
+ fixture.AssertFullSemver("1.1.0-unstable.1+1");
fixture.Repository.MergeNoFF("release-2.0.0", Constants.SignatureNow());
- fixture.AssertFullSemver("1.1.0-unstable.0+0");
+ fixture.AssertFullSemver("1.1.0-unstable.1+1");
}
}
diff --git a/GitVersionCore.Tests/Mocks/MockCommit.cs b/GitVersionCore.Tests/Mocks/MockCommit.cs
index 3f6f852eec..a180cac7f7 100644
--- a/GitVersionCore.Tests/Mocks/MockCommit.cs
+++ b/GitVersionCore.Tests/Mocks/MockCommit.cs
@@ -6,12 +6,17 @@
[DebuggerDisplay("{DebuggerDisplay}")]
public class MockCommit : Commit
{
+ static int commitCount = 1;
+ static DateTimeOffset when = DateTimeOffset.Now;
+
public MockCommit(ObjectId id = null)
{
idEx = id ?? new ObjectId(Guid.NewGuid().ToString().Replace("-", "") + "00000000");
- MessageEx = "";
+ MessageEx = "Commit " + commitCount++;
ParentsEx = new List { null };
- CommitterEx = new Signature("Joe", "Joe@bloggs.net", DateTimeOffset.Now);
+ CommitterEx = new Signature("Joe", "Joe@bloggs.net", when);
+ // Make sure each commit is a different time
+ when = when.AddSeconds(1);
}
public string MessageEx;
diff --git a/GitVersionCore.Tests/Mocks/MockCommitLog.cs b/GitVersionCore.Tests/Mocks/MockCommitLog.cs
index aecb492525..a5e3f1d803 100644
--- a/GitVersionCore.Tests/Mocks/MockCommitLog.cs
+++ b/GitVersionCore.Tests/Mocks/MockCommitLog.cs
@@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
+using System.Linq;
using LibGit2Sharp;
public class MockCommitLog : ICommitLog, ICollection
@@ -8,7 +9,10 @@ public class MockCommitLog : ICommitLog, ICollection
public IEnumerator GetEnumerator()
{
- return Commits.GetEnumerator();
+ if (SortedBy == CommitSortStrategies.Reverse)
+ return Commits.GetEnumerator();
+
+ return Enumerable.Reverse(Commits).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
diff --git a/GitVersionCore.Tests/Mocks/MockQueryableCommitLog.cs b/GitVersionCore.Tests/Mocks/MockQueryableCommitLog.cs
new file mode 100644
index 0000000000..e1120b8f5d
--- /dev/null
+++ b/GitVersionCore.Tests/Mocks/MockQueryableCommitLog.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using LibGit2Sharp;
+
+public class MockQueryableCommitLog : IQueryableCommitLog
+{
+ readonly ICommitLog commits;
+
+ public MockQueryableCommitLog(ICommitLog commits)
+ {
+ this.commits = commits;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return commits.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public CommitSortStrategies SortedBy
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public ICommitLog QueryBy(CommitFilter filter)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Commit FindMergeBase(Commit first, Commit second)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Commit FindMergeBase(IEnumerable commits, MergeBaseFindingStrategy strategy)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore.Tests/Mocks/MockRepository.cs b/GitVersionCore.Tests/Mocks/MockRepository.cs
index 252f527648..ea832500b2 100644
--- a/GitVersionCore.Tests/Mocks/MockRepository.cs
+++ b/GitVersionCore.Tests/Mocks/MockRepository.cs
@@ -4,6 +4,8 @@
public class MockRepository : IRepository
{
+ IQueryableCommitLog commits;
+
public MockRepository()
{
Tags = new MockTagCollection();
@@ -116,7 +118,13 @@ public BlameHunkCollection Blame(string path, BlameOptions options = null)
public Configuration Config { get; set; }
public Index Index { get; set; }
public ReferenceCollection Refs { get; set; }
- public IQueryableCommitLog Commits { get; set; }
+
+ public IQueryableCommitLog Commits
+ {
+ get { return commits ?? new MockQueryableCommitLog(Head.Commits); }
+ set { commits = value; }
+ }
+
public BranchCollection Branches { get; set; }
public TagCollection Tags { get; set; }
public RepositoryInformation Info { get; set; }
diff --git a/GitVersionCore.Tests/Mocks/MockTag.cs b/GitVersionCore.Tests/Mocks/MockTag.cs
index 4ea1364815..5400fb5ee0 100644
--- a/GitVersionCore.Tests/Mocks/MockTag.cs
+++ b/GitVersionCore.Tests/Mocks/MockTag.cs
@@ -15,6 +15,15 @@ public override GitObject Target
get { return TargetEx; }
}
public TagAnnotation AnnotationEx;
+
+ public MockTag() { }
+
+ public MockTag(string name, Commit target)
+ {
+ NameEx = name;
+ TargetEx = target;
+ }
+
public override TagAnnotation Annotation
{
get { return AnnotationEx; }
diff --git a/GitVersionCore.Tests/TestEffectiveConfiguration.cs b/GitVersionCore.Tests/TestEffectiveConfiguration.cs
index 055be59556..e0bb2704a4 100644
--- a/GitVersionCore.Tests/TestEffectiveConfiguration.cs
+++ b/GitVersionCore.Tests/TestEffectiveConfiguration.cs
@@ -9,8 +9,9 @@ public TestEffectiveConfiguration(
VersioningMode versioningMode = VersioningMode.ContinuousDelivery,
string gitTagPrefix = "v",
string tag = "",
- string nextVersion = null) :
- base(assemblyVersioningScheme, versioningMode, gitTagPrefix, tag, nextVersion)
+ string nextVersion = null,
+ string branchPrefixToTrim = "") :
+ base(assemblyVersioningScheme, versioningMode, gitTagPrefix, tag, nextVersion, IncrementStrategy.Patch, branchPrefixToTrim)
{
}
}
diff --git a/GitVersionCore.Tests/VersionCalculation/BaseVersionCalculatorTests.cs b/GitVersionCore.Tests/VersionCalculation/BaseVersionCalculatorTests.cs
new file mode 100644
index 0000000000..5f8c204ad7
--- /dev/null
+++ b/GitVersionCore.Tests/VersionCalculation/BaseVersionCalculatorTests.cs
@@ -0,0 +1,86 @@
+namespace GitVersionCore.Tests.VersionCalculation
+{
+ using System;
+ using GitVersion;
+ using GitVersion.VersionCalculation;
+ using GitVersion.VersionCalculation.BaseVersionCalculators;
+ using LibGit2Sharp;
+ using NUnit.Framework;
+ using Shouldly;
+
+ [TestFixture]
+ public class BaseVersionCalculatorTests
+ {
+ [Test]
+ public void ChoosesHighestVersionReturnedFromStrategies()
+ {
+ var context = new GitVersionContextBuilder().Build();
+ var dateTimeOffset = DateTimeOffset.Now;
+ var sut = new BaseVersionCalculator(new V1Strategy(DateTimeOffset.Now), new V2Strategy(dateTimeOffset));
+
+ var baseVersion = sut.GetBaseVersion(context);
+
+ baseVersion.SemanticVersion.ToString().ShouldBe("2.0.0");
+ baseVersion.ShouldIncrement.ShouldBe(true);
+ baseVersion.BaseVersionSource.When().ShouldBe(dateTimeOffset);
+ }
+
+ [Test]
+ public void UsesWhenFromNextBestMatchIfHighestDoesntHaveWhen()
+ {
+ var context = new GitVersionContextBuilder().Build();
+ var when = DateTimeOffset.Now;
+ var sut = new BaseVersionCalculator(new V1Strategy(when), new V2Strategy(null));
+
+ var baseVersion = sut.GetBaseVersion(context);
+
+ baseVersion.SemanticVersion.ToString().ShouldBe("2.0.0");
+ baseVersion.ShouldIncrement.ShouldBe(true);
+ baseVersion.BaseVersionSource.When().ShouldBe(when);
+ }
+
+ [Test]
+ public void UsesWhenFromNextBestMatchIfHighestDoesntHaveWhenReversedOrder()
+ {
+ var context = new GitVersionContextBuilder().Build();
+ var when = DateTimeOffset.Now;
+ var sut = new BaseVersionCalculator(new V1Strategy(null), new V2Strategy(when));
+
+ var baseVersion = sut.GetBaseVersion(context);
+
+ baseVersion.SemanticVersion.ToString().ShouldBe("2.0.0");
+ baseVersion.ShouldIncrement.ShouldBe(true);
+ baseVersion.BaseVersionSource.When().ShouldBe(when);
+ }
+
+ class V1Strategy : BaseVersionStrategy
+ {
+ readonly Commit when;
+
+ public V1Strategy(DateTimeOffset? when)
+ {
+ this.when = when == null ? null : new MockCommit { CommitterEx = when.Value.ToSignature() };
+ }
+
+ public override BaseVersion GetVersion(GitVersionContext context)
+ {
+ return new BaseVersion(false, true, new SemanticVersion(1), when);
+ }
+ }
+
+ class V2Strategy : BaseVersionStrategy
+ {
+ Commit when;
+
+ public V2Strategy(DateTimeOffset? when)
+ {
+ this.when = when == null ? null : new MockCommit { CommitterEx = when.Value.ToSignature() };
+ }
+
+ public override BaseVersion GetVersion(GitVersionContext context)
+ {
+ return new BaseVersion(true, true, new SemanticVersion(2), when);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore.Tests/VersionCalculation/NewNextVersionCalculatorTests.cs b/GitVersionCore.Tests/VersionCalculation/NewNextVersionCalculatorTests.cs
new file mode 100644
index 0000000000..dc61b7a4e1
--- /dev/null
+++ b/GitVersionCore.Tests/VersionCalculation/NewNextVersionCalculatorTests.cs
@@ -0,0 +1,99 @@
+namespace GitVersionCore.Tests.VersionCalculation
+{
+ using System;
+ using GitVersion;
+ using GitVersion.VersionCalculation;
+ using NUnit.Framework;
+ using Shouldly;
+
+ public class NewNextVersionCalculatorTests
+ {
+ [Test]
+ public void ShouldIncrementVersionBasedOnConfig()
+ {
+ var baseCalculator = new TestBaseVersionCalculator(true, true, new SemanticVersion(1), new MockCommit());
+ var semanticVersionBuildMetaData = new SemanticVersionBuildMetaData(1, "master", "b1a34e", DateTimeOffset.Now);
+ var sut = new NewNextVersionCalculator(baseCalculator, new TestMetaDataCalculator(semanticVersionBuildMetaData));
+ var config = new Config();
+ config.Branches.Add("master", new BranchConfig
+ {
+ Increment = IncrementStrategy.Major
+ });
+ var context = new GitVersionContextBuilder().WithConfig(config).Build();
+
+ var version = sut.FindVersion(context);
+
+ version.ToString().ShouldBe("2.0.0");
+ }
+
+ [Test]
+ public void DoesNotIncrementWhenBaseVersionSaysNotTo()
+ {
+ var baseCalculator = new TestBaseVersionCalculator(false, true, new SemanticVersion(1), new MockCommit());
+ var semanticVersionBuildMetaData = new SemanticVersionBuildMetaData(1, "master", "b1a34e", DateTimeOffset.Now);
+ var sut = new NewNextVersionCalculator(baseCalculator, new TestMetaDataCalculator(semanticVersionBuildMetaData));
+ var config = new Config();
+ config.Branches.Add("master", new BranchConfig
+ {
+ Increment = IncrementStrategy.Major
+ });
+ var context = new GitVersionContextBuilder().WithConfig(config).Build();
+
+ var version = sut.FindVersion(context);
+
+ version.ToString().ShouldBe("1.0.0");
+ }
+
+ [Test]
+ public void AppliesBranchPreReleaseTag()
+ {
+ var baseCalculator = new TestBaseVersionCalculator(false, true, new SemanticVersion(1), new MockCommit());
+ var semanticVersionBuildMetaData = new SemanticVersionBuildMetaData(2, "develop", "b1a34e", DateTimeOffset.Now);
+ var sut = new NewNextVersionCalculator(baseCalculator, new TestMetaDataCalculator(semanticVersionBuildMetaData));
+ var context = new GitVersionContextBuilder()
+ .WithDevelopBranch()
+ .Build();
+
+ var version = sut.FindVersion(context);
+
+ version.ToString("f").ShouldBe("1.0.0-unstable.1+2");
+ }
+
+ [Test]
+ public void DoesNotApplyPreReleaseTagWhenBaseVersionSaysNotTo()
+ {
+ var baseCalculator = new TestBaseVersionCalculator(false, false, new SemanticVersion(1), new MockCommit());
+ var semanticVersionBuildMetaData = new SemanticVersionBuildMetaData(1, "develop", "b1a34e", DateTimeOffset.Now);
+ var sut = new NewNextVersionCalculator(baseCalculator, new TestMetaDataCalculator(semanticVersionBuildMetaData));
+ var context = new GitVersionContextBuilder()
+ .WithDevelopBranch()
+ .Build();
+
+ var version = sut.FindVersion(context);
+
+ version.ToString("f").ShouldBe("1.0.0+1");
+ }
+
+ [Test]
+ public void PreReleaseTagCanUseBranchName()
+ {
+ var baseCalculator = new TestBaseVersionCalculator(false, true, new SemanticVersion(1), new MockCommit());
+ var semanticVersionBuildMetaData = new SemanticVersionBuildMetaData(2, "develop", "b1a34e", DateTimeOffset.Now);
+ var sut = new NewNextVersionCalculator(baseCalculator, new TestMetaDataCalculator(semanticVersionBuildMetaData));
+ var config = new Config();
+ config.Branches.Add("custom/", new BranchConfig
+ {
+ Tag = "useBranchName"
+ });
+ var context = new GitVersionContextBuilder()
+ .WithConfig(config)
+ .WithDevelopBranch()
+ .AddBranch("custom/foo")
+ .Build();
+
+ var version = sut.FindVersion(context);
+
+ version.ToString("f").ShouldBe("1.0.0-foo.1+2");
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore.Tests/VersionCalculation/Strategies/ConfigNextVersionBaseVersionStrategyTests.cs b/GitVersionCore.Tests/VersionCalculation/Strategies/ConfigNextVersionBaseVersionStrategyTests.cs
new file mode 100644
index 0000000000..d68469ccfd
--- /dev/null
+++ b/GitVersionCore.Tests/VersionCalculation/Strategies/ConfigNextVersionBaseVersionStrategyTests.cs
@@ -0,0 +1,38 @@
+namespace GitVersionCore.Tests.VersionCalculation.Strategies
+{
+ using GitVersion;
+ using GitVersion.VersionCalculation.BaseVersionCalculators;
+ using NUnit.Framework;
+ using Shouldly;
+
+ [TestFixture]
+ public class ConfigNextVersionBaseVersionStrategyTests
+ {
+ [Test]
+ public void ShouldNotBeIncremented()
+ {
+ var contextBuilder = new GitVersionContextBuilder()
+ .WithConfig(new Config
+ {
+ NextVersion = "1.0.0"
+ });
+ var sut = new ConfigNextVersionBaseVersionStrategy();
+
+ var baseVersion = sut.GetVersion(contextBuilder.Build());
+
+ baseVersion.ShouldIncrement.ShouldBe(false);
+ baseVersion.SemanticVersion.ToString().ShouldBe("1.0.0");
+ }
+
+ [Test]
+ public void ReturnsNullWhenNoNextVersionIsInConfig()
+ {
+ var contextBuilder = new GitVersionContextBuilder();
+ var sut = new ConfigNextVersionBaseVersionStrategy();
+
+ var baseVersion = sut.GetVersion(contextBuilder.Build());
+
+ baseVersion.ShouldBe(null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore.Tests/VersionCalculation/Strategies/LastTagBaseVersionStrategyTests.cs b/GitVersionCore.Tests/VersionCalculation/Strategies/LastTagBaseVersionStrategyTests.cs
new file mode 100644
index 0000000000..7341233a86
--- /dev/null
+++ b/GitVersionCore.Tests/VersionCalculation/Strategies/LastTagBaseVersionStrategyTests.cs
@@ -0,0 +1,39 @@
+namespace GitVersionCore.Tests.VersionCalculation.Strategies
+{
+ using GitVersion.VersionCalculation.BaseVersionCalculators;
+ using NUnit.Framework;
+ using Shouldly;
+
+ [TestFixture]
+ public class LastTagBaseVersionStrategyTests
+ {
+ [Test]
+ public void ShouldAllowVersionIncrement()
+ {
+ // TODO Looks like our MockRepostory stuff doesn't work properly. commits are added to end of list, but Tip is first.
+ // Changing behaviour breaks a bunch of tests
+ var context = new GitVersionContextBuilder()
+ .WithTaggedMaster()
+ .AddCommit()
+ .Build();
+ var sut = new LastTagBaseVersionStrategy();
+
+ var baseVersion = sut.GetVersion(context);
+
+ baseVersion.ShouldIncrement.ShouldBe(true);
+ }
+
+ [Test]
+ public void ShouldNotAllowVersionIncrementWhenTagComesFromCurrentCommit()
+ {
+ var context = new GitVersionContextBuilder()
+ .WithTaggedMaster()
+ .Build();
+ var sut = new LastTagBaseVersionStrategy();
+
+ var baseVersion = sut.GetVersion(context);
+
+ baseVersion.ShouldIncrement.ShouldBe(false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs b/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs
new file mode 100644
index 0000000000..ac22497e58
--- /dev/null
+++ b/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs
@@ -0,0 +1,110 @@
+namespace GitVersionCore.Tests.VersionCalculation.Strategies
+{
+ using System.Collections.Generic;
+ using GitVersion.VersionCalculation.BaseVersionCalculators;
+ using LibGit2Sharp;
+ using NUnit.Framework;
+ using Shouldly;
+
+ [TestFixture]
+ public class MergeMessageBaseVersionStrategyTests
+ {
+ [Test]
+ public void ShouldAllowIncrementOfVersion()
+ {
+ var context = new GitVersionContextBuilder().WithRepository(new MockRepository
+ {
+ Head = new MockBranch("master") { new MockCommit
+ {
+ MessageEx = "Merge branch 'hotfix-0.1.5'",
+ ParentsEx = GetParents(true)
+ } }
+ }).Build();
+ var sut = new MergeMessageBaseVersionStrategy();
+
+ var baseVersion = sut.GetVersion(context);
+
+ baseVersion.ShouldIncrement.ShouldBe(true);
+ }
+
+ [TestCase("Merge branch 'hotfix-0.1.5'", false, null)]
+ [TestCase("Merge branch 'develop' of github.com:Particular/NServiceBus into develop", true, null)]
+ [TestCase("Merge branch '4.0.3'", true, "4.0.3")] //TODO: possible make it a config option to support this
+ [TestCase("Merge branch 'release-10.10.50'", true, "10.10.50")]
+ [TestCase("Merge branch 's'", true, null)] // Must start with a number
+ [TestCase("Merge branch 'release-0.2.0'", true, "0.2.0")]
+ [TestCase("Merge branch 'hotfix-4.6.6' into support-4.6", true, "4.6.6")]
+ [TestCase("Merge branch 'hotfix-10.10.50'", true, "10.10.50")]
+ [TestCase("Merge branch 'hotfix-0.1.5'", true, "0.1.5")]
+ [TestCase("Merge branch 'hotfix-0.1.5'\n\nRelates to: TicketId", true, "0.1.5")]
+ [TestCase("Merge branch 'alpha-0.1.5'", true, "0.1.5")]
+ [TestCase("Merge pull request #165 from Particular/release-1.0.0", true, "1.0.0")]
+ [TestCase("Merge pull request #95 from Particular/issue-94", false, null)]
+ [TestCase("Merge pull request #165 in Particular/release-1.0.0", true, "1.0.0")]
+ [TestCase("Merge pull request #95 in Particular/issue-94", true, null)]
+ [TestCase("Merge pull request #95 in Particular/issue-94", false, null)]
+ [TestCase("Merge pull request #64 from arledesma/feature-VS2013_3rd_party_test_framework_support", true, null)]
+ [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("Finish 0.14.1", true, "0.14.1")] //Support Syntevo SmartGit/Hg's Gitflow merge commit messages for finishing a 'Hotfix' branch
+ public void AssertMergeMessage(string message, bool isMergeCommit, string expectedVersion)
+ {
+ var parents = GetParents(isMergeCommit);
+ AssertMergeMessage(message, expectedVersion, parents);
+ AssertMergeMessage(message + " ", expectedVersion, parents);
+ AssertMergeMessage(message + "\r ", expectedVersion, parents);
+ AssertMergeMessage(message + "\r", expectedVersion, parents);
+ AssertMergeMessage(message + "\r\n", expectedVersion, parents);
+ AssertMergeMessage(message + "\r\n ", expectedVersion, parents);
+ AssertMergeMessage(message + "\n", expectedVersion, parents);
+ AssertMergeMessage(message + "\n ", expectedVersion, parents);
+ }
+
+ static void AssertMergeMessage(string message, string expectedVersion, List parents)
+ {
+ var commit = new MockCommit
+ {
+ MessageEx = message,
+ ParentsEx = parents
+ };
+
+ var context = new GitVersionContextBuilder()
+ .WithRepository(new MockRepository
+ {
+ Head = new MockBranch("master")
+ {
+ commit,
+ new MockCommit()
+ }
+ })
+ .Build();
+ var sut = new MergeMessageBaseVersionStrategy();
+
+ var baseVersion = sut.GetVersion(context);
+
+ if (expectedVersion == null)
+ {
+ baseVersion.ShouldBe(null);
+ }
+ else
+ {
+ baseVersion.SemanticVersion.ToString().ShouldBe(expectedVersion);
+ }
+ }
+
+ static List GetParents(bool isMergeCommit)
+ {
+ if (isMergeCommit)
+ {
+ return new List
+ {
+ null,
+ null
+ };
+ }
+ return new List
+ {
+ null
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore.Tests/VersionCalculation/Strategies/VersionInBranchBaseVersionStrategyTests.cs b/GitVersionCore.Tests/VersionCalculation/Strategies/VersionInBranchBaseVersionStrategyTests.cs
new file mode 100644
index 0000000000..9900c795a5
--- /dev/null
+++ b/GitVersionCore.Tests/VersionCalculation/Strategies/VersionInBranchBaseVersionStrategyTests.cs
@@ -0,0 +1,34 @@
+namespace GitVersionCore.Tests.VersionCalculation.Strategies
+{
+ using GitVersion.VersionCalculation.BaseVersionCalculators;
+ using NUnit.Framework;
+ using Shouldly;
+
+ [TestFixture]
+ public class VersionInBranchBaseVersionStrategyTests
+ {
+ [Test]
+ [TestCase("release-2.0.0", "2.0.0")]
+ [TestCase("release/2.0.0", "2.0.0")]
+ [TestCase("hotfix-2.0.0", "2.0.0")]
+ [TestCase("hotfix/2.0.0", "2.0.0")]
+ [TestCase("hotfix/2.0.0", "2.0.0")]
+ [TestCase("custom/JIRA-123", null)]
+ public void CanTakeVersionFromBranchName(string branchName, string expectedBaseVersion)
+ {
+ var context = new GitVersionContextBuilder()
+ .WithBranch(branchName)
+ .AddCommit()
+ .Build();
+
+ var sut = new VersionInBranchBaseVersionStrategy();
+
+ var baseVersion = sut.GetVersion(context);
+
+ if (expectedBaseVersion == null)
+ baseVersion.ShouldBe(null);
+ else
+ baseVersion.SemanticVersion.ToString().ShouldBe(expectedBaseVersion);
+ }
+ }
+}
diff --git a/GitVersionCore.Tests/VersionCalculation/TestBaseVersionCalculator.cs b/GitVersionCore.Tests/VersionCalculation/TestBaseVersionCalculator.cs
new file mode 100644
index 0000000000..f38dae098d
--- /dev/null
+++ b/GitVersionCore.Tests/VersionCalculation/TestBaseVersionCalculator.cs
@@ -0,0 +1,28 @@
+namespace GitVersionCore.Tests.VersionCalculation
+{
+ using GitVersion;
+ using GitVersion.VersionCalculation;
+ using GitVersion.VersionCalculation.BaseVersionCalculators;
+ using LibGit2Sharp;
+
+ public class TestBaseVersionCalculator : IBaseVersionCalculator
+ {
+ readonly SemanticVersion semanticVersion;
+ bool shouldIncrement;
+ bool shouldUpdateTag;
+ Commit source;
+
+ public TestBaseVersionCalculator(bool shouldIncrement, bool shouldUpdateTag, SemanticVersion semanticVersion, Commit source)
+ {
+ this.semanticVersion = semanticVersion;
+ this.source = source;
+ this.shouldUpdateTag = shouldUpdateTag;
+ this.shouldIncrement = shouldIncrement;
+ }
+
+ public BaseVersion GetBaseVersion(GitVersionContext context)
+ {
+ return new BaseVersion(shouldIncrement, shouldUpdateTag, semanticVersion, source);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore.Tests/VersionCalculation/TestMetaDataCalculator.cs b/GitVersionCore.Tests/VersionCalculation/TestMetaDataCalculator.cs
new file mode 100644
index 0000000000..51f7a95b22
--- /dev/null
+++ b/GitVersionCore.Tests/VersionCalculation/TestMetaDataCalculator.cs
@@ -0,0 +1,21 @@
+namespace GitVersionCore.Tests.VersionCalculation
+{
+ using GitVersion;
+ using GitVersion.VersionCalculation;
+ using LibGit2Sharp;
+
+ public class TestMetaDataCalculator : IMetaDataCalculator
+ {
+ SemanticVersionBuildMetaData metaData;
+
+ public TestMetaDataCalculator(SemanticVersionBuildMetaData metaData)
+ {
+ this.metaData = metaData;
+ }
+
+ public SemanticVersionBuildMetaData Create(Commit baseVersionSource, GitVersionContext context)
+ {
+ return metaData;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/Configuration/BranchConfig.cs b/GitVersionCore/Configuration/BranchConfig.cs
index 1b7494e0f0..2f09fd4f90 100644
--- a/GitVersionCore/Configuration/BranchConfig.cs
+++ b/GitVersionCore/Configuration/BranchConfig.cs
@@ -4,10 +4,27 @@
public class BranchConfig
{
+ public BranchConfig()
+ {
+ }
+
+ public BranchConfig(BranchConfig branchConfiguration)
+ {
+ VersioningMode = branchConfiguration.VersioningMode;
+ Tag = branchConfiguration.Tag;
+ Increment = branchConfiguration.Increment;
+ }
+
[YamlAlias("mode")]
public VersioningMode? VersioningMode { get; set; }
+ ///
+ /// Special value 'useBranchName' will extract the tag from the branch name
+ ///
[YamlAlias("tag")]
public string Tag { get; set; }
+
+ [YamlAlias("increment")]
+ public IncrementStrategy? Increment { get; set; }
}
}
diff --git a/GitVersionCore/Configuration/Config.cs b/GitVersionCore/Configuration/Config.cs
index ed487c57db..2d602b338f 100644
--- a/GitVersionCore/Configuration/Config.cs
+++ b/GitVersionCore/Configuration/Config.cs
@@ -14,10 +14,16 @@ public Config()
TagPrefix = "[vV]";
VersioningMode = GitVersion.VersioningMode.ContinuousDelivery;
Branches["release[/-]"] = new BranchConfig { Tag = "beta" };
+ Branches["feature[/-]"] = new BranchConfig
+ {
+ Increment = IncrementStrategy.Inherit,
+ Tag = "useBranchName"
+ };
Branches["hotfix[/-]"] = new BranchConfig { Tag = "beta" };
Branches["develop"] = new BranchConfig
{
Tag = "unstable",
+ Increment = IncrementStrategy.Minor,
VersioningMode = GitVersion.VersioningMode.ContinuousDeployment
};
}
diff --git a/GitVersionCore/Configuration/IncrementStrategy.cs b/GitVersionCore/Configuration/IncrementStrategy.cs
new file mode 100644
index 0000000000..cd3b8de0b7
--- /dev/null
+++ b/GitVersionCore/Configuration/IncrementStrategy.cs
@@ -0,0 +1,14 @@
+namespace GitVersion
+{
+ public enum IncrementStrategy
+ {
+ None,
+ Major,
+ Minor,
+ Patch,
+ ///
+ /// Uses the increment strategy from the branch the current branch was branched from
+ ///
+ Inherit
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/EffectiveConfiguration.cs b/GitVersionCore/EffectiveConfiguration.cs
index 9daed63748..0c8a66c3ae 100644
--- a/GitVersionCore/EffectiveConfiguration.cs
+++ b/GitVersionCore/EffectiveConfiguration.cs
@@ -5,13 +5,15 @@
///
public class EffectiveConfiguration
{
- public EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningScheme, VersioningMode versioningMode, string gitTagPrefix, string tag, string nextVersion)
+ public EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningScheme, VersioningMode versioningMode, string gitTagPrefix, string tag, string nextVersion, IncrementStrategy increment, string branchPrefixToTrim)
{
AssemblyVersioningScheme = assemblyVersioningScheme;
VersioningMode = versioningMode;
GitTagPrefix = gitTagPrefix;
Tag = tag;
NextVersion = nextVersion;
+ Increment = increment;
+ BranchPrefixToTrim = branchPrefixToTrim;
}
public VersioningMode VersioningMode { get; private set; }
@@ -29,5 +31,9 @@ public EffectiveConfiguration(AssemblyVersioningScheme assemblyVersioningScheme,
public string Tag { get; private set; }
public string NextVersion { get; private set; }
+
+ public IncrementStrategy Increment { get; private set; }
+
+ public string BranchPrefixToTrim { get; private set; }
}
}
\ No newline at end of file
diff --git a/GitVersionCore/GitVersionContext.cs b/GitVersionCore/GitVersionContext.cs
index 3bd8a0ef7e..0b8cbf2c67 100644
--- a/GitVersionCore/GitVersionContext.cs
+++ b/GitVersionCore/GitVersionContext.cs
@@ -81,30 +81,82 @@ IEnumerable GetBranchesContainingCommit(string commitSha)
void CalculateEffectiveConfiguration()
{
- var matchingBranches = configuration.Branches.Where(b => Regex.IsMatch("^" + CurrentBranch.Name, b.Key)).ToArray();
+ var currentBranchConfig = GetBranchConfiguration(CurrentBranch);
- var currentBranchConfig = GetBranchConfiguration(matchingBranches);
-
- var versioningMode = currentBranchConfig.VersioningMode ?? configuration.VersioningMode ?? VersioningMode.ContinuousDelivery;
- var tag = currentBranchConfig.Tag;
+ var versioningMode = currentBranchConfig.Value.VersioningMode ?? configuration.VersioningMode ?? VersioningMode.ContinuousDelivery;
+ var tag = currentBranchConfig.Value.Tag;
var nextVersion = configuration.NextVersion;
-
- Configuration = new EffectiveConfiguration(configuration.AssemblyVersioningScheme, versioningMode, configuration.TagPrefix, tag, nextVersion);
+ var incrementStrategy = currentBranchConfig.Value.Increment ?? IncrementStrategy.Patch;
+ var assemblyVersioningScheme = configuration.AssemblyVersioningScheme;
+ var gitTagPrefix = configuration.TagPrefix;
+ Configuration = new EffectiveConfiguration(assemblyVersioningScheme, versioningMode, gitTagPrefix, tag, nextVersion, incrementStrategy, currentBranchConfig.Key);
}
- BranchConfig GetBranchConfiguration(KeyValuePair[] matchingBranches)
+ KeyValuePair GetBranchConfiguration(Branch currentBranch)
{
+ var matchingBranches = configuration.Branches.Where(b => Regex.IsMatch("^" + currentBranch.Name, b.Key)).ToArray();
+
if (matchingBranches.Length == 0)
{
- return new BranchConfig();
+ return new KeyValuePair(string.Empty, new BranchConfig());
}
if (matchingBranches.Length == 1)
{
- return matchingBranches[0].Value;
+ var keyValuePair = matchingBranches[0];
+ var branchConfiguration = keyValuePair.Value;
+
+ if (branchConfiguration.Increment == IncrementStrategy.Inherit)
+ {
+ var branchPoint = currentBranch.FindCommitBranchWasBranchedFrom(Repository);
+
+ List possibleParents;
+ if (branchPoint.Sha == CurrentCommit.Sha)
+ {
+ possibleParents = ListBranchesContaininingCommit(Repository, CurrentCommit.Sha).Except(new[]
+ {
+ currentBranch
+ }).ToList();
+ }
+ else
+ {
+ var branches = ListBranchesContaininingCommit(Repository, branchPoint.Sha).ToArray();
+ var currentTipBranches = ListBranchesContaininingCommit(Repository, CurrentCommit.Sha).ToArray();
+ possibleParents = branches
+ .Except(currentTipBranches)
+ .ToList();
+ }
+
+ // If it comes down to master and something, master is always first so we pick other branch
+ if (possibleParents.Count == 2 && possibleParents.Any(p => p.Name == "master"))
+ possibleParents.Remove(possibleParents.Single(p => p.Name == "master"));
+
+ if (possibleParents.Count == 1)
+ {
+ return new KeyValuePair(
+ keyValuePair.Key,
+ new BranchConfig(branchConfiguration)
+ {
+ Increment = GetBranchConfiguration(possibleParents[0]).Value.Increment
+ });
+ }
+
+ throw new Exception("Failed to inherit Increment branch configuration");
+ }
+
+ return keyValuePair;
}
- const string format = "Multiple branch configurations match the current branch name of '{0}'. Matching configurations: '{1}'";
- throw new Exception(string.Format(format, CurrentBranch.Name, string.Join(", ", matchingBranches.Select(b => b.Key))));
+ const string format = "Multiple branch configurations match the current branch branchName of '{0}'. Matching configurations: '{1}'";
+ throw new Exception(string.Format(format, currentBranch.Name, string.Join(", ", matchingBranches.Select(b => b.Key))));
+ }
+
+ static IEnumerable ListBranchesContaininingCommit(IRepository repo, string commitSha)
+ {
+ return from branch in repo.Branches
+ where !branch.IsRemote
+ let commits = repo.Commits.QueryBy(new CommitFilter { Since = branch }).Where(c => c.Sha == commitSha)
+ where commits.Any()
+ select branch;
}
}
}
\ No newline at end of file
diff --git a/GitVersionCore/GitVersionCore.csproj b/GitVersionCore/GitVersionCore.csproj
index 1505d8477c..c67c96743e 100644
--- a/GitVersionCore/GitVersionCore.csproj
+++ b/GitVersionCore/GitVersionCore.csproj
@@ -74,6 +74,7 @@
+
@@ -87,6 +88,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -143,6 +156,7 @@
+
diff --git a/GitVersionCore/GitVersionFinder.cs b/GitVersionCore/GitVersionFinder.cs
index c9faa91e15..05bda271d2 100644
--- a/GitVersionCore/GitVersionFinder.cs
+++ b/GitVersionCore/GitVersionFinder.cs
@@ -3,6 +3,7 @@ namespace GitVersion
using System;
using System.IO;
using System.Linq;
+ using GitVersion.VersionCalculation;
using LibGit2Sharp;
public class GitVersionFinder
@@ -18,20 +19,21 @@ public SemanticVersion FindVersion(GitVersionContext context)
throw new Exception("NextVersion.txt has been depreciated. See https://github.com/ParticularLabs/GitVersion/wiki/GitVersionConfig.yaml-Configuration-File for replacement");
}
- if (ShouldGitHubFlowVersioningSchemeApply(context.Repository))
- {
- Logger.WriteInfo("GitHubFlow version strategy will be used");
- return new GitHubFlowVersionFinder().FindVersion(context);
- }
+ return new NewNextVersionCalculator().FindVersion(context);
+ //if (ShouldGitHubFlowVersioningSchemeApply(context.Repository))
+ //{
+ // Logger.WriteInfo("GitHubFlow version strategy will be used");
+ // return new GitHubFlowVersionFinder().FindVersion(context);
+ //}
- Logger.WriteInfo("GitFlow version strategy will be used");
- return new GitFlowVersionFinder().FindVersion(context);
+ //Logger.WriteInfo("GitFlow version strategy will be used");
+ //return new GitFlowVersionFinder().FindVersion(context);
}
- static bool ShouldGitHubFlowVersioningSchemeApply(IRepository repo)
- {
- return repo.FindBranch("develop") == null;
- }
+ //static bool ShouldGitHubFlowVersioningSchemeApply(IRepository repo)
+ //{
+ // return repo.FindBranch("develop") == null;
+ //}
void EnsureMainTopologyConstraints(GitVersionContext context)
{
diff --git a/GitVersionCore/LibGitExtensions.cs b/GitVersionCore/LibGitExtensions.cs
index bbea6117b3..e7ad5e5b19 100644
--- a/GitVersionCore/LibGitExtensions.cs
+++ b/GitVersionCore/LibGitExtensions.cs
@@ -24,6 +24,12 @@ public static Branch FindBranch(this IRepository repository, string branchName)
return repository.Branches.FirstOrDefault(x => x.Name == "origin/" + branchName);
}
+ public static Commit FindCommitBranchWasBranchedFrom(this Branch branch, IRepository repository)
+ {
+ var tips = repository.Branches.Select(b => b.Tip).Where(c => c.Sha != branch.Tip.Sha).ToList();
+ return repository.Commits.FirstOrDefault(c => tips.Contains(c) || c.Parents.Count() > 1) ?? branch.Tip;
+ }
+
public static IEnumerable TagsByDate(this IRepository repository, Commit commit)
{
return repository.Tags
diff --git a/GitVersionCore/MergeMessageParser.cs b/GitVersionCore/MergeMessageParser.cs
index e97b741335..a477a4da27 100644
--- a/GitVersionCore/MergeMessageParser.cs
+++ b/GitVersionCore/MergeMessageParser.cs
@@ -6,14 +6,14 @@ namespace GitVersion
static class MergeMessageParser
{
- public static bool TryParse(Commit mergeCommit, EffectiveConfiguration configuration, out SemanticVersion shortVersion)
+ public static bool TryParse(Commit mergeCommit, EffectiveConfiguration configuration, out SemanticVersion semanticVersion)
{
string versionPart;
if (Inner(mergeCommit, out versionPart))
{
- return SemanticVersion.TryParse(versionPart, configuration.GitTagPrefix, out shortVersion);
+ return SemanticVersion.TryParse(versionPart, configuration.GitTagPrefix, out semanticVersion);
}
- shortVersion = null;
+ semanticVersion = null;
return false;
}
diff --git a/GitVersionCore/SemanticVersion.cs b/GitVersionCore/SemanticVersion.cs
index 77e628ce14..e5a4778854 100644
--- a/GitVersionCore/SemanticVersion.cs
+++ b/GitVersionCore/SemanticVersion.cs
@@ -15,8 +15,11 @@ public class SemanticVersion : IFormattable, IComparable
public SemanticVersionPreReleaseTag PreReleaseTag;
public SemanticVersionBuildMetaData BuildMetaData;
- public SemanticVersion()
+ public SemanticVersion(int major = 0, int minor = 0, int patch = 0)
{
+ Major = major;
+ Minor = minor;
+ Patch = patch;
PreReleaseTag = new SemanticVersionPreReleaseTag();
BuildMetaData = new SemanticVersionBuildMetaData();
}
diff --git a/GitVersionCore/VersionCalculation/BaseVersionCalculator.cs b/GitVersionCore/VersionCalculation/BaseVersionCalculator.cs
new file mode 100644
index 0000000000..a87e55fd8c
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/BaseVersionCalculator.cs
@@ -0,0 +1,31 @@
+namespace GitVersion.VersionCalculation
+{
+ using System.Linq;
+ using BaseVersionCalculators;
+
+ public class BaseVersionCalculator : IBaseVersionCalculator
+ {
+ readonly BaseVersionStrategy[] strategies;
+
+ public BaseVersionCalculator(params BaseVersionStrategy[] strategies)
+ {
+ this.strategies = strategies;
+ }
+
+ public BaseVersion GetBaseVersion(GitVersionContext context)
+ {
+ return strategies
+ .Select(s => s.GetVersion(context))
+ .Where(v => v != null)
+ .Aggregate((v1, v2) =>
+ {
+ if (v1.SemanticVersion > v2.SemanticVersion)
+ {
+ return new BaseVersion(v1.ShouldIncrement, v1.ShouldUpdateTag, v1.SemanticVersion, v1.BaseVersionSource ?? v2.BaseVersionSource);
+ }
+
+ return new BaseVersion(v2.ShouldIncrement, v2.ShouldUpdateTag, v2.SemanticVersion, v2.BaseVersionSource ?? v1.BaseVersionSource);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/BaseVersionCalculators/BaseVersion.cs b/GitVersionCore/VersionCalculation/BaseVersionCalculators/BaseVersion.cs
new file mode 100644
index 0000000000..f566090ce1
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/BaseVersionCalculators/BaseVersion.cs
@@ -0,0 +1,23 @@
+namespace GitVersion.VersionCalculation.BaseVersionCalculators
+{
+ using LibGit2Sharp;
+
+ public class BaseVersion
+ {
+ public BaseVersion(bool shouldIncrement, bool shouldUpdateTag, SemanticVersion semanticVersion, Commit baseVersionSource)
+ {
+ ShouldIncrement = shouldIncrement;
+ ShouldUpdateTag = shouldUpdateTag;
+ SemanticVersion = semanticVersion;
+ BaseVersionSource = baseVersionSource;
+ }
+
+ public bool ShouldIncrement { get; private set; }
+
+ public bool ShouldUpdateTag { get; private set; }
+
+ public SemanticVersion SemanticVersion { get; private set; }
+
+ public Commit BaseVersionSource { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/BaseVersionCalculators/ConfigNextVersionBaseVersionStrategy.cs b/GitVersionCore/VersionCalculation/BaseVersionCalculators/ConfigNextVersionBaseVersionStrategy.cs
new file mode 100644
index 0000000000..3bccf10ad9
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/BaseVersionCalculators/ConfigNextVersionBaseVersionStrategy.cs
@@ -0,0 +1,12 @@
+namespace GitVersion.VersionCalculation.BaseVersionCalculators
+{
+ public class ConfigNextVersionBaseVersionStrategy : BaseVersionStrategy
+ {
+ public override BaseVersion GetVersion(GitVersionContext context)
+ {
+ if (string.IsNullOrEmpty(context.Configuration.NextVersion))
+ return null;
+ return new BaseVersion(false, true, SemanticVersion.Parse(context.Configuration.NextVersion, context.Configuration.GitTagPrefix), null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/BaseVersionCalculators/LastTagBaseVersionStrategy.cs b/GitVersionCore/VersionCalculation/BaseVersionCalculators/LastTagBaseVersionStrategy.cs
new file mode 100644
index 0000000000..ce621a87af
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/BaseVersionCalculators/LastTagBaseVersionStrategy.cs
@@ -0,0 +1,17 @@
+namespace GitVersion.VersionCalculation.BaseVersionCalculators
+{
+ public class LastTagBaseVersionStrategy : BaseVersionStrategy
+ {
+ public override BaseVersion GetVersion(GitVersionContext context)
+ {
+ VersionTaggedCommit version;
+ if (new LastTaggedReleaseFinder(context).GetVersion(out version))
+ {
+ var shouldUpdateVersion = version.Commit.Sha != context.CurrentCommit.Sha;
+ return new BaseVersion(shouldUpdateVersion, shouldUpdateVersion, version.SemVer, version.Commit);
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs b/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs
new file mode 100644
index 0000000000..dea7b0736f
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs
@@ -0,0 +1,28 @@
+namespace GitVersion.VersionCalculation.BaseVersionCalculators
+{
+ using System.Linq;
+
+ public class MergeMessageBaseVersionStrategy : BaseVersionStrategy
+ {
+ public override BaseVersion GetVersion(GitVersionContext context)
+ {
+ var commitsPriorToThan = context.CurrentBranch
+ .CommitsPriorToThan(context.CurrentCommit.When());
+ var baseVersions = commitsPriorToThan
+ .SelectMany(c =>
+ {
+ SemanticVersion semanticVersion;
+ // TODO when this approach works, inline the other class into here
+ if (MergeMessageParser.TryParse(c, context.Configuration, out semanticVersion))
+ return new[]
+ {
+ new BaseVersion(true, true, semanticVersion, c)
+ };
+ return Enumerable.Empty();
+ })
+ .ToArray();
+
+ return baseVersions.Length > 1 ? baseVersions.Aggregate((x, y) => x.SemanticVersion > y.SemanticVersion ? x : y) : baseVersions.SingleOrDefault();
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchBaseVersionStrategy.cs b/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchBaseVersionStrategy.cs
new file mode 100644
index 0000000000..7531c2a989
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchBaseVersionStrategy.cs
@@ -0,0 +1,36 @@
+namespace GitVersion.VersionCalculation.BaseVersionCalculators
+{
+ using System;
+ using System.Linq;
+
+ public class VersionInBranchBaseVersionStrategy : BaseVersionStrategy
+ {
+ public override BaseVersion GetVersion(GitVersionContext context)
+ {
+ var versionInBranch = GetVersionInBranch(context);
+ if (versionInBranch != null)
+ {
+ var commitBranchWasBranchedFrom = context.CurrentBranch.FindCommitBranchWasBranchedFrom(context.Repository);
+ var baseVersionSource = context.CurrentBranch.Commits.First(c => c.Sha != commitBranchWasBranchedFrom.Sha);
+ return new BaseVersion(false, true, versionInBranch.Item2, baseVersionSource);
+ }
+
+ return null;
+ }
+
+ Tuple GetVersionInBranch(GitVersionContext context)
+ {
+ var branchParts = context.CurrentBranch.Name.Split('/', '-');
+ foreach (var part in branchParts)
+ {
+ SemanticVersion semanticVersion;
+ if (SemanticVersion.TryParse(part, context.Configuration.GitTagPrefix, out semanticVersion))
+ {
+ return Tuple.Create(part, semanticVersion);
+ }
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/BaseVersionStrategy.cs b/GitVersionCore/VersionCalculation/BaseVersionStrategy.cs
new file mode 100644
index 0000000000..855d4cbc3a
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/BaseVersionStrategy.cs
@@ -0,0 +1,9 @@
+namespace GitVersion.VersionCalculation
+{
+ using GitVersion.VersionCalculation.BaseVersionCalculators;
+
+ public abstract class BaseVersionStrategy
+ {
+ public abstract BaseVersion GetVersion(GitVersionContext context);
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/FallbackBaseVersionStrategy.cs b/GitVersionCore/VersionCalculation/FallbackBaseVersionStrategy.cs
new file mode 100644
index 0000000000..e0943ff2e4
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/FallbackBaseVersionStrategy.cs
@@ -0,0 +1,13 @@
+namespace GitVersion.VersionCalculation
+{
+ using System.Linq;
+ using GitVersion.VersionCalculation.BaseVersionCalculators;
+
+ public class FallbackBaseVersionStrategy : BaseVersionStrategy
+ {
+ public override BaseVersion GetVersion(GitVersionContext context)
+ {
+ return new BaseVersion(false, true, new SemanticVersion(minor: 1), context.CurrentBranch.Commits.Last());
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/IBaseVersionCalculator.cs b/GitVersionCore/VersionCalculation/IBaseVersionCalculator.cs
new file mode 100644
index 0000000000..b6e8f3d67a
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/IBaseVersionCalculator.cs
@@ -0,0 +1,9 @@
+namespace GitVersion.VersionCalculation
+{
+ using GitVersion.VersionCalculation.BaseVersionCalculators;
+
+ public interface IBaseVersionCalculator
+ {
+ BaseVersion GetBaseVersion(GitVersionContext context);
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/IMetaDataCalculator.cs b/GitVersionCore/VersionCalculation/IMetaDataCalculator.cs
new file mode 100644
index 0000000000..967baf8528
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/IMetaDataCalculator.cs
@@ -0,0 +1,9 @@
+namespace GitVersion.VersionCalculation
+{
+ using LibGit2Sharp;
+
+ public interface IMetaDataCalculator
+ {
+ SemanticVersionBuildMetaData Create(Commit baseVersionSource, GitVersionContext context);
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/MetaDataCalculator.cs b/GitVersionCore/VersionCalculation/MetaDataCalculator.cs
new file mode 100644
index 0000000000..9afb84787f
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/MetaDataCalculator.cs
@@ -0,0 +1,26 @@
+namespace GitVersion.VersionCalculation
+{
+ using System.Linq;
+ using LibGit2Sharp;
+
+ public class MetaDataCalculator : IMetaDataCalculator
+ {
+ public SemanticVersionBuildMetaData Create(Commit baseVersionSource, GitVersionContext context)
+ {
+ var qf = new CommitFilter
+ {
+ Since = context.CurrentCommit,
+ Until = baseVersionSource,
+ SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Time
+ };
+
+ var commitsSinceTag = context.Repository.Commits.QueryBy(qf).Count();
+
+ return new SemanticVersionBuildMetaData(
+ commitsSinceTag,
+ context.CurrentBranch.Name,
+ context.CurrentCommit.Sha,
+ context.CurrentCommit.When());
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionCore/VersionCalculation/NewNextVersionCalculator.cs b/GitVersionCore/VersionCalculation/NewNextVersionCalculator.cs
new file mode 100644
index 0000000000..91762f9d4a
--- /dev/null
+++ b/GitVersionCore/VersionCalculation/NewNextVersionCalculator.cs
@@ -0,0 +1,74 @@
+namespace GitVersion.VersionCalculation
+{
+ using System;
+ using System.Text.RegularExpressions;
+ using BaseVersionCalculators;
+
+ public class NewNextVersionCalculator
+ {
+ IBaseVersionCalculator baseVersionFinder;
+ IMetaDataCalculator metaDataCalculator;
+
+ public NewNextVersionCalculator(IBaseVersionCalculator baseVersionCalculator = null, IMetaDataCalculator metaDataCalculator = null)
+ {
+ this.metaDataCalculator = metaDataCalculator ?? new MetaDataCalculator();
+ baseVersionFinder = baseVersionCalculator ??
+ new BaseVersionCalculator(
+ new FallbackBaseVersionStrategy(),
+ new ConfigNextVersionBaseVersionStrategy(),
+ new LastTagBaseVersionStrategy(),
+ new MergeMessageBaseVersionStrategy(),
+ new VersionInBranchBaseVersionStrategy());
+ }
+
+ public SemanticVersion FindVersion(GitVersionContext context)
+ {
+ var baseVersion = baseVersionFinder.GetBaseVersion(context);
+
+ if (baseVersion.ShouldIncrement) IncrementVersion(context, baseVersion);
+
+ if (baseVersion.ShouldUpdateTag && !baseVersion.SemanticVersion.PreReleaseTag.HasTag() && !string.IsNullOrEmpty(context.Configuration.Tag))
+ {
+ var tagToUse = context.Configuration.Tag;
+ if (tagToUse == "useBranchName")
+ tagToUse = context.CurrentBranch.Name.RegexReplace(context.Configuration.BranchPrefixToTrim, string.Empty, RegexOptions.IgnoreCase);
+ baseVersion.SemanticVersion.PreReleaseTag = new SemanticVersionPreReleaseTag(tagToUse, 1);
+ }
+
+ baseVersion.SemanticVersion.BuildMetaData = metaDataCalculator.Create(baseVersion.BaseVersionSource, context);
+
+ return baseVersion.SemanticVersion;
+ }
+
+ static void IncrementVersion(GitVersionContext context, BaseVersion baseVersion)
+ {
+ if (!baseVersion.SemanticVersion.PreReleaseTag.HasTag())
+ {
+ switch (context.Configuration.Increment)
+ {
+ case IncrementStrategy.None:
+ break;
+ case IncrementStrategy.Major:
+ baseVersion.SemanticVersion.Major++;
+ break;
+ case IncrementStrategy.Minor:
+ baseVersion.SemanticVersion.Minor++;
+ break;
+ case IncrementStrategy.Patch:
+ baseVersion.SemanticVersion.Patch++;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+ else
+ {
+ if (baseVersion.SemanticVersion.PreReleaseTag.Number != null)
+ {
+ baseVersion.SemanticVersion.PreReleaseTag.Number = baseVersion.SemanticVersion.PreReleaseTag.Number;
+ baseVersion.SemanticVersion.PreReleaseTag.Number++;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/GitVersionTask.Tests/GitFlow/GitFlowVersionFinderTests.cs b/GitVersionTask.Tests/GitFlow/GitFlowVersionFinderTests.cs
index b935ee3d94..16d89a4547 100644
--- a/GitVersionTask.Tests/GitFlow/GitFlowVersionFinderTests.cs
+++ b/GitVersionTask.Tests/GitFlow/GitFlowVersionFinderTests.cs
@@ -39,27 +39,6 @@ public void RequiresALocalDevelopBranch()
}
}
- [Test]
- public void AFeatureBranchIsRequiredToBranchOffOfDevelopBranch()
- {
- var repoPath = Clone(ASBMTestRepoWorkingDirPath);
- using (var repo = new Repository(repoPath))
- {
- const string branchName = "feature/unborn";
-
- // Create a new unborn feature branch sharing no history with "develop"
- repo.Refs.UpdateTarget(repo.Refs.Head.CanonicalName, "refs/heads/" + branchName);
-
- AddOneCommitToHead(repo, "feature");
-
- var feature = repo.Branches[branchName];
-
- var finder = new GitVersionFinder();
-
- Assert.Throws(() => finder.FindVersion(new GitVersionContext(repo, feature, new Config())));
- }
- }
-
[Test]
public void AHotfixBranchIsRequiredToBranchOffOfMasterBranch()
{
diff --git a/GitVersionTask.Tests/VersionOnMasterFinderTests.cs b/GitVersionTask.Tests/VersionOnMasterFinderTests.cs
index 1b5570d470..80bc5e2c95 100644
--- a/GitVersionTask.Tests/VersionOnMasterFinderTests.cs
+++ b/GitVersionTask.Tests/VersionOnMasterFinderTests.cs
@@ -21,9 +21,9 @@ public void Should_find_previous_commit_that_was_at_least_a_minor_bump()
var mockBranch = new MockBranch("master")
{
- new MockMergeCommit(new ObjectId(sha))
+ new MockMergeCommit
{
- MessageEx = "Merge branch 'hotfix-0.3.0'",
+ MessageEx = "Merge branch 'hotfix-0.2.0'",
CommitterEx = signature
},
new MockMergeCommit
@@ -31,9 +31,9 @@ public void Should_find_previous_commit_that_was_at_least_a_minor_bump()
MessageEx = "Merge branch 'hotfix-0.3.1'",
CommitterEx = signature,
},
- new MockMergeCommit
+ new MockMergeCommit(new ObjectId(sha))
{
- MessageEx = "Merge branch 'hotfix-0.2.0'",
+ MessageEx = "Merge branch 'hotfix-0.3.0'",
CommitterEx = signature
},
};