diff --git a/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt b/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt index 2650aedd2b..0c87a0b723 100644 --- a/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt +++ b/src/GitVersionCore.Tests/ConfigProviderTests.CanWriteOutEffectiveConfiguration.approved.txt @@ -47,7 +47,6 @@ branches: - develop - master - support - - release tracks-release-branches: false is-release-branch: true is-mainline: false diff --git a/src/GitVersionCore.Tests/ConfigProviderTests.cs b/src/GitVersionCore.Tests/ConfigProviderTests.cs index c39740a69a..ea54b02fa0 100644 --- a/src/GitVersionCore.Tests/ConfigProviderTests.cs +++ b/src/GitVersionCore.Tests/ConfigProviderTests.cs @@ -251,6 +251,7 @@ public void VerifyAliases() var config = typeof(Config); var propertiesMissingAlias = config.GetProperties() .Where(p => p.GetCustomAttribute() == null) + .Where(p => p.GetCustomAttribute() == null) .Where(p => p.GetCustomAttribute(typeof(YamlMemberAttribute)) == null) .Select(p => p.Name); diff --git a/src/GitVersionCore.Tests/ExecuteCoreTests.cs b/src/GitVersionCore.Tests/ExecuteCoreTests.cs index d167b60a52..e279093455 100644 --- a/src/GitVersionCore.Tests/ExecuteCoreTests.cs +++ b/src/GitVersionCore.Tests/ExecuteCoreTests.cs @@ -1,6 +1,7 @@ using GitTools.Testing; using GitVersion; using GitVersion.Helpers; +using LibGit2Sharp; using NUnit.Framework; using Shouldly; using System; @@ -189,6 +190,8 @@ public void ConfigChangeInvalidatesCache() var configPath = Path.Combine(fixture.RepositoryPath, "GitVersionConfig.yaml"); fileSystem.WriteAllText(configPath, "next-version: 5.0"); + Commands.Stage(fixture.Repository, configPath); + fixture.Repository.Commit("Added config", Generate.SignatureNow(), Generate.SignatureNow()); vv = versionAndBranchFinder.ExecuteGitVersion(null, null, null, null, false, fixture.RepositoryPath, null); vv.AssemblySemVer.ShouldBe("5.0.0.0"); @@ -300,10 +303,7 @@ LogMessages RepositoryScope(ExecuteCore executeCore = null, Action + @@ -58,9 +59,8 @@ ..\packages\NSubstitute.1.10.0.0\lib\net45\NSubstitute.dll True - - ..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll - True + + ..\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll ..\packages\Shouldly.2.7.0\lib\net40\Shouldly.dll @@ -97,6 +97,7 @@ + @@ -107,6 +108,7 @@ + @@ -149,7 +151,6 @@ - @@ -215,6 +216,7 @@ + \ No newline at end of file diff --git a/src/GitVersionCore.Tests/IntegrationTests/MasterScenarios.cs b/src/GitVersionCore.Tests/IntegrationTests/MasterScenarios.cs index 93f9fc3832..ae38fb5cc9 100644 --- a/src/GitVersionCore.Tests/IntegrationTests/MasterScenarios.cs +++ b/src/GitVersionCore.Tests/IntegrationTests/MasterScenarios.cs @@ -114,7 +114,10 @@ public void GivenARepositoryWithTagAndNextVersionInConfig_VersionShouldMatchVers fixture.Repository.MakeATaggedCommit(TaggedVersion); fixture.Repository.MakeCommits(5); - fixture.AssertFullSemver(config, "1.1.0+5"); + // GitVersion uses commit count from where the config file was updated + // because we didn't check this change into the test repo + // it's 0 + fixture.AssertFullSemver(config, "1.1.0+0"); } } diff --git a/src/GitVersionCore.Tests/IntegrationTests/OtherScenarios.cs b/src/GitVersionCore.Tests/IntegrationTests/OtherScenarios.cs index 5fef1447c6..a07fe69f5d 100644 --- a/src/GitVersionCore.Tests/IntegrationTests/OtherScenarios.cs +++ b/src/GitVersionCore.Tests/IntegrationTests/OtherScenarios.cs @@ -6,6 +6,7 @@ using LibGit2Sharp; using NUnit.Framework; using System.Collections.Generic; + using System; [TestFixture] public class OtherScenarios @@ -105,5 +106,28 @@ public void DoNotBlowUpWhenDevelopAndFeatureBranchPointAtSameCommit() fixture.AssertFullSemver("1.1.0-alpha.1"); } } + + [Test] + public void AllowUnrelatedBranchesInRepo() + { + // This test unsures we handle when GitVersion cannot find mergebases etc + using (var fixture = new EmptyRepositoryFixture()) + { + fixture.Repository.MakeACommit(); + fixture.Repository.MakeACommit(); + + // Create a new root commit and then a branch pointing at that commit + var treeDefinition = new TreeDefinition(); + var tree = fixture.Repository.ObjectDatabase.CreateTree(treeDefinition); + var commit = fixture.Repository.ObjectDatabase.CreateCommit( + new Signature("name", "mail", DateTimeOffset.Now), + new Signature("name", "mail", DateTimeOffset.Now), + "Create new empty branch", + tree, new Commit[0], false); + fixture.Repository.Branches.Add("gh-pages", commit); + + fixture.AssertFullSemver("0.1.0+1"); + } + } } } \ No newline at end of file diff --git a/src/GitVersionCore.Tests/IntegrationTests/ReleaseBranchScenarios.cs b/src/GitVersionCore.Tests/IntegrationTests/ReleaseBranchScenarios.cs index 0dacc90c58..a36139cf94 100644 --- a/src/GitVersionCore.Tests/IntegrationTests/ReleaseBranchScenarios.cs +++ b/src/GitVersionCore.Tests/IntegrationTests/ReleaseBranchScenarios.cs @@ -357,7 +357,7 @@ public void MergeOnReleaseBranchShouldNotResetCount() fixture.AssertFullSemver(config, "2.0.0-beta.1"); fixture.Repository.MergeNoFF("release/2.0.0-xxx"); - fixture.AssertFullSemver(config, "2.0.0-beta.2"); + fixture.AssertFullSemver(config, "2.0.0-beta.3"); } } diff --git a/src/GitVersionCore.Tests/MockObjectDatabase.cs b/src/GitVersionCore.Tests/MockObjectDatabase.cs new file mode 100644 index 0000000000..416cf7503f --- /dev/null +++ b/src/GitVersionCore.Tests/MockObjectDatabase.cs @@ -0,0 +1,9 @@ +using LibGit2Sharp; + +public class MockObjectDatabase : ObjectDatabase +{ + public override Commit FindMergeBase(Commit first, Commit second) + { + return second; + } +} \ No newline at end of file diff --git a/src/GitVersionCore.Tests/Mocks/MockQueryableCommitLog.cs b/src/GitVersionCore.Tests/Mocks/MockQueryableCommitLog.cs index d9241619b7..6f4ff5c635 100644 --- a/src/GitVersionCore.Tests/Mocks/MockQueryableCommitLog.cs +++ b/src/GitVersionCore.Tests/Mocks/MockQueryableCommitLog.cs @@ -34,7 +34,7 @@ public ICommitLog QueryBy(CommitFilter filter) public IEnumerable QueryBy(string path) { - throw new NotImplementedException(); + return new[] { new LogEntry () }; } #pragma warning disable CS0618 // Type or member is obsolete diff --git a/src/GitVersionCore.Tests/Mocks/MockRepository.cs b/src/GitVersionCore.Tests/Mocks/MockRepository.cs index 33e8709a4d..4f21deacf9 100644 --- a/src/GitVersionCore.Tests/Mocks/MockRepository.cs +++ b/src/GitVersionCore.Tests/Mocks/MockRepository.cs @@ -10,6 +10,7 @@ public MockRepository() { Tags = new MockTagCollection(); Refs = new MockReferenceCollection(); + ObjectDatabase = new MockObjectDatabase(); } public void Dispose() diff --git a/src/GitVersionCore.Tests/VersionCalculation/BaseVersionCalculatorTests.cs b/src/GitVersionCore.Tests/VersionCalculation/BaseVersionCalculatorTests.cs deleted file mode 100644 index 7a7057b058..0000000000 --- a/src/GitVersionCore.Tests/VersionCalculation/BaseVersionCalculatorTests.cs +++ /dev/null @@ -1,166 +0,0 @@ -namespace GitVersionCore.Tests.VersionCalculation -{ - using System; - using System.Collections.Generic; - using GitTools.Testing; - using GitVersion; - using GitVersion.VersionCalculation; - using GitVersion.VersionCalculation.BaseVersionCalculators; - using GitVersion.VersionFilters; - 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 = Generate.Signature(when.Value) }; - } - - public override IEnumerable GetVersions(GitVersionContext context) - { - yield return new BaseVersion(context, "Source 1", false, new SemanticVersion(1), when, null); - } - } - - class V2Strategy : BaseVersionStrategy - { - Commit when; - - public V2Strategy(DateTimeOffset? when) - { - this.when = when == null ? null : new MockCommit { CommitterEx = Generate.Signature(when.Value) }; - } - - public override IEnumerable GetVersions(GitVersionContext context) - { - yield return new BaseVersion(context, "Source 2", true, new SemanticVersion(2), when, null); - } - } - - [Test] - public void ShouldNotFilterVersion() - { - var fakeIgnoreConfig = new TestIgnoreConfig(new ExcludeSourcesContainingExclude()); - var context = new GitVersionContextBuilder().WithConfig(new Config() { Ignore = fakeIgnoreConfig }).Build(); - var version = new BaseVersion(context, "dummy", false, new SemanticVersion(2), new MockCommit(), null); - var sut = new BaseVersionCalculator(new TestVersionStrategy(version)); - - var baseVersion = sut.GetBaseVersion(context); - - baseVersion.Source.ShouldBe(version.Source); - baseVersion.ShouldIncrement.ShouldBe(version.ShouldIncrement); - baseVersion.SemanticVersion.ShouldBe(version.SemanticVersion); - } - - [Test] - public void ShouldFilterVersion() - { - var fakeIgnoreConfig = new TestIgnoreConfig(new ExcludeSourcesContainingExclude()); - var context = new GitVersionContextBuilder().WithConfig(new Config() { Ignore = fakeIgnoreConfig }).Build(); - var higherVersion = new BaseVersion(context, "exclude", false, new SemanticVersion(2), new MockCommit(), null); - var lowerVersion = new BaseVersion(context, "dummy", false, new SemanticVersion(1), new MockCommit(), null); - var sut = new BaseVersionCalculator(new TestVersionStrategy(higherVersion, lowerVersion)); - - var baseVersion = sut.GetBaseVersion(context); - - baseVersion.Source.ShouldNotBe(higherVersion.Source); - baseVersion.SemanticVersion.ShouldNotBe(higherVersion.SemanticVersion); - baseVersion.Source.ShouldBe(lowerVersion.Source); - baseVersion.SemanticVersion.ShouldBe(lowerVersion.SemanticVersion); - } - - internal class TestIgnoreConfig : IgnoreConfig - { - private readonly IVersionFilter filter; - - public TestIgnoreConfig(IVersionFilter filter) - { - this.filter = filter; - } - - public override IEnumerable ToFilters() - { - yield return filter; - } - } - - internal class ExcludeSourcesContainingExclude : IVersionFilter - { - public bool Exclude(BaseVersion version, out string reason) - { - reason = null; - - if (version.Source.Contains("exclude")) - { - reason = "was excluded"; - return true; - } - return false; - } - } - - class TestVersionStrategy : BaseVersionStrategy - { - private readonly IEnumerable versions; - - public TestVersionStrategy(params BaseVersion[] versions) - { - this.versions = versions; - } - - public override IEnumerable GetVersions(GitVersionContext context) - { - return versions; - } - } - } -} \ No newline at end of file diff --git a/src/GitVersionCore.Tests/VersionCalculation/NextVersionCalculatorTests.cs b/src/GitVersionCore.Tests/VersionCalculation/NextVersionCalculatorTests.cs index b3b947b796..56ef0ba585 100644 --- a/src/GitVersionCore.Tests/VersionCalculation/NextVersionCalculatorTests.cs +++ b/src/GitVersionCore.Tests/VersionCalculation/NextVersionCalculatorTests.cs @@ -9,13 +9,15 @@ using LibGit2Sharp; using NUnit.Framework; using Shouldly; + using GitVersion.VersionCalculation.BaseVersionCalculators; + using GitVersion.GitRepoInformation; public class NextVersionCalculatorTests { [Test] public void ShouldIncrementVersionBasedOnConfig() { - var baseCalculator = new TestBaseVersionCalculator(true, new SemanticVersion(1), new MockCommit()); + var baseCalculator = new TestBaseVersionCalculator(true, new SemanticVersion(1), new BaseVersionSource(new MCommit(new MockCommit(), new Lazy(0)), "dummy")); var semanticVersionBuildMetaData = new SemanticVersionBuildMetaData(1, "master", "b1a34e", DateTimeOffset.Now); var sut = new NextVersionCalculator(baseCalculator, new TestMetaDataCalculator(semanticVersionBuildMetaData)); var config = new Config(); @@ -29,7 +31,7 @@ public void ShouldIncrementVersionBasedOnConfig() [Test] public void DoesNotIncrementWhenBaseVersionSaysNotTo() { - var baseCalculator = new TestBaseVersionCalculator(false, new SemanticVersion(1), new MockCommit()); + var baseCalculator = new TestBaseVersionCalculator(false, new SemanticVersion(1), new BaseVersionSource(new MCommit(new MockCommit(), new Lazy(0)), "dummy")); var semanticVersionBuildMetaData = new SemanticVersionBuildMetaData(1, "master", "b1a34e", DateTimeOffset.Now); var sut = new NextVersionCalculator(baseCalculator, new TestMetaDataCalculator(semanticVersionBuildMetaData)); var config = new Config(); @@ -43,7 +45,7 @@ public void DoesNotIncrementWhenBaseVersionSaysNotTo() [Test] public void AppliesBranchPreReleaseTag() { - var baseCalculator = new TestBaseVersionCalculator(false, new SemanticVersion(1), new MockCommit()); + var baseCalculator = new TestBaseVersionCalculator(false, new SemanticVersion(1), new BaseVersionSource(new MCommit(new MockCommit(), new Lazy(0)), "dummy")); var semanticVersionBuildMetaData = new SemanticVersionBuildMetaData(2, "develop", "b1a34e", DateTimeOffset.Now); var sut = new NextVersionCalculator(baseCalculator, new TestMetaDataCalculator(semanticVersionBuildMetaData)); var context = new GitVersionContextBuilder() @@ -82,7 +84,7 @@ public void PreReleaseTagCanUseBranchName() fixture.BranchTo("custom/foo"); fixture.MakeACommit(); - fixture.AssertFullSemver(config, "1.0.0-foo.1+2"); + fixture.AssertFullSemver(config, "1.0.0-foo.1+0"); } } @@ -113,7 +115,7 @@ public void PreReleaseTagCanUseBranchNameVariable() fixture.BranchTo("custom/foo"); fixture.MakeACommit(); - fixture.AssertFullSemver(config, "1.0.0-alpha.foo.1+2"); + fixture.AssertFullSemver(config, "1.0.0-alpha.foo.1+0"); } } diff --git a/src/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs b/src/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs index 6890b1080f..cc7f2b50be 100644 --- a/src/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs +++ b/src/GitVersionCore.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs @@ -17,11 +17,15 @@ public void ShouldNotAllowIncrementOfVersion() // So we shouldn't bump the version var context = new GitVersionContextBuilder().WithRepository(new MockRepository { - Head = new MockBranch("master") { new MockCommit + Head = new MockBranch("master") { - MessageEx = "Merge branch 'hotfix-0.1.5'", - ParentsEx = GetParents(true) - } } + new MockCommit + { + MessageEx = "Merge branch 'hotfix-0.1.5'", + ParentsEx = GetParents(true) + } + }, + Branches = new MockBranchCollection() }).Build(); var sut = new MergeMessageBaseVersionStrategy(); @@ -108,7 +112,8 @@ static void AssertMergeMessage(string message, string expectedVersion, List(() => sut.Exclude(null, out reason)); + Should.Throw(() => sut.Exclude(null, new MockRepository(), out reason)); } [Test] public void WhenCommitShouldExcludeWithReason() { var context = new GitVersionContextBuilder().Build(); - var commit = new MockCommit(); //when = UtcNow - var version = new BaseVersion(context, "dummy", false, new SemanticVersion(1), commit, string.Empty); + var source = new BaseVersionSource(new MCommit(new MockCommit(), new Lazy(0)), "dummy"); + var version = new BaseVersion(context, false, new SemanticVersion(1), source, string.Empty); var futureDate = DateTimeOffset.UtcNow.AddYears(1); var sut = new MinDateVersionFilter(futureDate); string reason; - sut.Exclude(version, out reason).ShouldBeTrue(); + sut.Exclude(version, context.Repository, out reason).ShouldBeTrue(); reason.ShouldNotBeNullOrWhiteSpace(); } [Test] public void WhenShaMismatchShouldNotExclude() { - var commit = new MockCommit(); //when = UtcNow + var source = new BaseVersionSource(new MCommit(new MockCommit(), new Lazy(0)), "dummy"); var context = new GitVersionContextBuilder().Build(); - var version = new BaseVersion(context, "dummy", false, new SemanticVersion(1), commit, string.Empty); + var version = new BaseVersion(context, false, new SemanticVersion(1), source, string.Empty); var pastDate = DateTimeOffset.UtcNow.AddYears(-1); var sut = new MinDateVersionFilter(pastDate); string reason; - sut.Exclude(version, out reason).ShouldBeFalse(); - reason.ShouldBeNull(); - } - - [Test] - public void ExcludeShouldAcceptVersionWithNullCommit() - { - var context = new GitVersionContextBuilder().Build(); - var version = new BaseVersion(context, "dummy", false, new SemanticVersion(1), null, string.Empty); - var futureDate = DateTimeOffset.UtcNow.AddYears(1); - var sut = new MinDateVersionFilter(futureDate); - - string reason; - sut.Exclude(version, out reason).ShouldBeFalse(); + sut.Exclude(version, context.Repository, out reason).ShouldBeFalse(); reason.ShouldBeNull(); } } diff --git a/src/GitVersionCore.Tests/VersionFilters/ShaVersionFilterTests.cs b/src/GitVersionCore.Tests/VersionFilters/ShaVersionFilterTests.cs index 9374fa7b0b..013e02b124 100644 --- a/src/GitVersionCore.Tests/VersionFilters/ShaVersionFilterTests.cs +++ b/src/GitVersionCore.Tests/VersionFilters/ShaVersionFilterTests.cs @@ -4,6 +4,7 @@ using GitVersion.VersionFilters; using NUnit.Framework; using Shouldly; +using GitVersion.GitRepoInformation; namespace GitVersionCore.Tests.VersionFilters { @@ -23,7 +24,7 @@ public void VerifyNullGuard2() var sut = new ShaVersionFilter(new[] { commit.Sha }); string reason; - Should.Throw(() => sut.Exclude(null, out reason)); + Should.Throw(() => sut.Exclude(null, new MockRepository(), out reason)); } [Test] @@ -31,11 +32,11 @@ public void WhenShaMatchShouldExcludeWithReason() { var commit = new MockCommit(); var context = new GitVersionContextBuilder().Build(); - var version = new BaseVersion(context, "dummy", false, new SemanticVersion(1), commit, string.Empty); + var version = new BaseVersion(context, false, new SemanticVersion(1), new BaseVersionSource(new MCommit(commit, new Lazy(0)), "dummy"), string.Empty); var sut = new ShaVersionFilter(new[] { commit.Sha }); string reason; - sut.Exclude(version, out reason).ShouldBeTrue(); + sut.Exclude(version, context.Repository, out reason).ShouldBeTrue(); reason.ShouldNotBeNullOrWhiteSpace(); } @@ -44,23 +45,11 @@ public void WhenShaMismatchShouldNotExclude() { var commit = new MockCommit(); var context = new GitVersionContextBuilder().Build(); - var version = new BaseVersion(context, "dummy", false, new SemanticVersion(1), commit, string.Empty); + var version = new BaseVersion(context, false, new SemanticVersion(1), new BaseVersionSource(new MCommit(commit, new Lazy(0)), "dummy"), string.Empty); var sut = new ShaVersionFilter(new[] { "mismatched" }); string reason; - sut.Exclude(version, out reason).ShouldBeFalse(); - reason.ShouldBeNull(); - } - - [Test] - public void ExcludeShouldAcceptVersionWithNullCommit() - { - var context = new GitVersionContextBuilder().Build(); - var version = new BaseVersion(context, "dummy", false, new SemanticVersion(1), null, string.Empty); - var sut = new ShaVersionFilter(new[] { "mismatched" }); - - string reason; - sut.Exclude(version, out reason).ShouldBeFalse(); + sut.Exclude(version, context.Repository, out reason).ShouldBeFalse(); reason.ShouldBeNull(); } } diff --git a/src/GitVersionCore.Tests/packages.config b/src/GitVersionCore.Tests/packages.config index 0797568c38..2d04afbb50 100644 --- a/src/GitVersionCore.Tests/packages.config +++ b/src/GitVersionCore.Tests/packages.config @@ -8,8 +8,8 @@ - - + + diff --git a/src/GitVersionCore/Configuration/Config.cs b/src/GitVersionCore/Configuration/Config.cs index a1d7e3f010..08a21571b8 100644 --- a/src/GitVersionCore/Configuration/Config.cs +++ b/src/GitVersionCore/Configuration/Config.cs @@ -17,6 +17,9 @@ public Config() Ignore = new IgnoreConfig(); } + [YamlIgnore] + public string Filename { get; set; } + [YamlMember(Alias = "assembly-versioning-scheme")] public AssemblyVersioningScheme? AssemblyVersioningScheme { get; set; } diff --git a/src/GitVersionCore/Configuration/ConfigurationProvider.cs b/src/GitVersionCore/Configuration/ConfigurationProvider.cs index b72cd9ff3c..bbb0831a96 100644 --- a/src/GitVersionCore/Configuration/ConfigurationProvider.cs +++ b/src/GitVersionCore/Configuration/ConfigurationProvider.cs @@ -123,7 +123,7 @@ public static void ApplyDefaultsTo(Config config) ApplyBranchDefaults(config, GetOrCreateBranchDefaults(config, ReleaseBranchKey), ReleaseBranchRegex, - new List { "develop", "master", "support", "release" }, + new List { "develop", "master", "support" }, defaultTag: "beta", defaultPreventIncrement: true, defaultIncrementStrategy: IncrementStrategy.Patch, @@ -239,7 +239,9 @@ static Config ReadConfig(string workingDirectory, IFileSystem fileSystem) { var readAllText = fileSystem.ReadAllText(configFilePath); LegacyConfigNotifier.Notify(new StringReader(readAllText)); - return ConfigSerialiser.Read(new StringReader(readAllText)); + var config = ConfigSerialiser.Read(new StringReader(readAllText)); + config.Filename = configFilePath.Replace(workingDirectory, "").TrimStart('/', '\\'); + return config; } return new Config(); diff --git a/src/GitVersionCore/GitRepoInformation/GitRepoMetadata.cs b/src/GitVersionCore/GitRepoInformation/GitRepoMetadata.cs new file mode 100644 index 0000000000..e5fe014a41 --- /dev/null +++ b/src/GitVersionCore/GitRepoInformation/GitRepoMetadata.cs @@ -0,0 +1,119 @@ +using LibGit2Sharp; +using System; +using System.Collections.Generic; + +namespace GitVersion.GitRepoInformation +{ + public class GitRepoMetadata + { + public GitRepoMetadata( + MBranch currentBranch, MBranch master, + List releaseBranches) + { + MasterBranch = master; + CurrentBranch = currentBranch; + ReleaseBranches = releaseBranches; + } + + // Wonder if this can be 'mainline' + public MBranch MasterBranch { get; } + public List ReleaseBranches { get; } + public MBranch CurrentBranch { get; } + } + + public class MBranchTag + { + public MBranchTag(MBranch branch, MTag tag) + { + Branch = branch; + Tag = tag; + } + + public MBranch Branch { get; } + public MTag Tag { get; } + } + + public class MTag + { + public MTag(string friendlyName, MCommit commit, Config config) + { + Name = friendlyName; + Commit = commit; + SemanticVersion version; + if (SemanticVersion.TryParse(friendlyName, config.TagPrefix, out version)) + { + Version = version; + } + } + + public MTag(MTag tag, Lazy newDistance) + { + Name = tag.Name; + Commit = new MCommit(tag.Commit.Sha, tag.Commit.When, tag.Commit.Message, newDistance); + Version = tag.Version; + } + + public string Name { get; } + public MCommit Commit { get; } + public SemanticVersion Version { get; } + } + + public class MBranch + { + public MBranch( + string name, + MCommit tip, + MCommit root, + MParent parent, + List tags, + List mergeMessages) + { + Name = name; + Tip = tip; + Root = root; + Parent = parent; + MergeMessages = mergeMessages; + Tags = tags; + } + + public string Name { get; } + public MCommit Tip { get; } + public MCommit Root { get; } + public MParent Parent { get; } + public List MergeMessages { get; } + public List Tags { get; } + } + + public class MCommit + { + Lazy distanceFromTip; + + public MCommit(Commit commit, Lazy distanceFromTip) : this( + commit.Sha, commit.When().DateTime, commit.Message, distanceFromTip) + { + } + + public MCommit(string sha, DateTime when, string message, Lazy distanceFromTip) + { + Sha = sha; + When = when; + Message = message; + this.distanceFromTip = distanceFromTip; + } + + public string Sha { get; } + public string Message { get; } + public DateTime When { get; } + public int DistanceFromTip { get { return distanceFromTip.Value; } } + } + + public class MParent + { + public MParent(MCommit mergeBase) + { + MergeBase = mergeBase; + } + + public MCommit MergeBase { get; } + } +} diff --git a/src/GitVersionCore/GitRepoMetadataProvider.cs b/src/GitVersionCore/GitRepoInformation/GitRepoMetadataProvider.cs similarity index 76% rename from src/GitVersionCore/GitRepoMetadataProvider.cs rename to src/GitVersionCore/GitRepoInformation/GitRepoMetadataProvider.cs index 9927ed899d..edf0f958a1 100644 --- a/src/GitVersionCore/GitRepoMetadataProvider.cs +++ b/src/GitVersionCore/GitRepoInformation/GitRepoMetadataProvider.cs @@ -9,7 +9,7 @@ namespace GitVersion public class GitRepoMetadataProvider { private Dictionary> mergeBaseCommitsCache; - private Dictionary, MergeBaseData> mergeBaseCache; + private Dictionary, MergeBaseData> mergeBaseCache; private Dictionary> semanticVersionTagsOnBranchCache; private IRepository Repository { get; set; } const string missingTipFormat = "{0} has no tip. Please see http://example.com/docs for information on how to fix this."; @@ -17,7 +17,7 @@ public class GitRepoMetadataProvider public GitRepoMetadataProvider(IRepository repository, Config configuration) { - mergeBaseCache = new Dictionary, MergeBaseData>(); + mergeBaseCache = new Dictionary, MergeBaseData>(); mergeBaseCommitsCache = new Dictionary>(); semanticVersionTagsOnBranchCache = new Dictionary>(); Repository = repository; @@ -110,28 +110,42 @@ public IEnumerable GetBranchesContainingCommit(Commit commit, IList public Commit FindMergeBase(Branch branch, Branch otherBranch) { - var key = Tuple.Create(branch, otherBranch); + return FindMergeBase(branch.Tip.Sha, otherBranch.Tip.Sha, branch.FriendlyName, otherBranch.FriendlyName); + } + + /// + /// Find the merge base of the two branches, i.e. the best common ancestor of the two branches' tips. + /// + public Commit FindMergeBase(string sha1, string sha2, string sha1Desc = null, string sha2Desc = null) + { + var key = Tuple.Create(sha1, sha2); + var source1 = Repository.Lookup(sha1); + var source2 = Repository.Lookup(sha2); + var sha1Name = sha1Desc ?? sha1; + var sha2Name = sha2Desc ?? sha2; if (mergeBaseCache.ContainsKey(key)) { - Logger.WriteDebug($"Cache hit for merge base between '{branch.FriendlyName}' and '{otherBranch.FriendlyName}'."); - return mergeBaseCache[key].MergeBase; + Logger.WriteDebug($"Cache hit for merge base between '{sha1Name}' and '{sha2Name}'."); + var mergeBase = mergeBaseCache[key].MergeBase; + if (mergeBase == null) { return null; } + return Repository.Lookup(mergeBase); } - using (Logger.IndentLog($"Finding merge base between '{branch.FriendlyName}' and '{otherBranch.FriendlyName}'.")) + using (Logger.IndentLog($"Finding merge base between '{sha1Name}' and '{sha2Name}'.")) { - // Otherbranch tip is a forward merge - var commitToFindCommonBase = otherBranch.Tip; - var commit = branch.Tip; - if (otherBranch.Tip.Parents.Contains(commit)) + // source2 is a forward merge (Jake: I have no idea what this means right now....) + var commitToFindCommonBase = source2; + var commit = source1; + if (source2.Parents.Contains(commit)) { - commitToFindCommonBase = otherBranch.Tip.Parents.First(); + commitToFindCommonBase = source2.Parents.First(); } var findMergeBase = Repository.ObjectDatabase.FindMergeBase(commit, commitToFindCommonBase); if (findMergeBase != null) { - Logger.WriteInfo($"Found merge base of {findMergeBase.Sha}"); + Logger.WriteDebug($"Found possible merge base of {findMergeBase.Sha}, ensuring is not a forward merge"); // We do not want to include merge base commits which got forward merged into the other branch Commit forwardMerge; do @@ -149,19 +163,19 @@ public Commit FindMergeBase(Branch branch, Branch otherBranch) { // TODO Fix the logging up in this section var second = forwardMerge.Parents.First(); - Logger.WriteDebug("Second " + second.Sha); + Logger.WriteDebug($"It looks like the found merge base was a forward merge, finding next merge base '{sha1Name}' and '{second.Sha}'"); var mergeBase = Repository.ObjectDatabase.FindMergeBase(commit, second); if (mergeBase == null) { - Logger.WriteWarning("Could not find mergbase for " + commit); + Logger.WriteWarning($"Could not find mergbase for '{sha1Name}' and '{second.Sha}'"); } else { - Logger.WriteDebug("New Merge base " + mergeBase.Sha); + Logger.WriteDebug("Next possible merge base is " + mergeBase.Sha); } if (mergeBase == findMergeBase) { - Logger.WriteDebug("Breaking"); + Logger.WriteDebug("Original merge base and forward merge merge base was the same, using original result"); break; } findMergeBase = mergeBase; @@ -172,9 +186,9 @@ public Commit FindMergeBase(Branch branch, Branch otherBranch) } // Store in cache. - mergeBaseCache.Add(key, new MergeBaseData(branch, otherBranch, Repository, findMergeBase)); + mergeBaseCache.Add(key, new MergeBaseData(sha1, sha2, findMergeBase?.Sha)); - Logger.WriteInfo($"Merge base of {branch.FriendlyName}' and '{otherBranch.FriendlyName} is {findMergeBase}"); + Logger.WriteInfo($"Merge base of {sha1Name}' and '{sha2Name} is {findMergeBase}"); return findMergeBase; } } @@ -198,7 +212,7 @@ public BranchCommit FindCommitBranchWasBranchedFrom(Branch branch, params Branch return BranchCommit.Empty; } - var possibleBranches = GetMergeCommitsForBranch(branch) + var possibleBranches = GetMergeBasesForBranch(branch) .ExcludingBranches(excludedBranches) .Where(b => !branch.IsSameBranch(b.Branch)) .ToList(); @@ -216,7 +230,23 @@ public BranchCommit FindCommitBranchWasBranchedFrom(Branch branch, params Branch } } - List GetMergeCommitsForBranch(Branch branch) + public int GetCommitCount(Commit tip, Commit since) + { + var qf = new CommitFilter + { + IncludeReachableFrom = tip, + ExcludeReachableFrom = since, + SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Time + }; + + var commitLog = Repository.Commits.QueryBy(qf); + var commitsSinceTag = commitLog.Count(); + Logger.WriteInfo(string.Format("{0} commits found between {1} and {2}", commitsSinceTag, since.Sha, tip.Sha)); + + return commitsSinceTag; + } + + List GetMergeBasesForBranch(Branch branch) { if (mergeBaseCommitsCache.ContainsKey(branch)) { @@ -259,17 +289,15 @@ List GetMergeCommitsForBranch(Branch branch) private class MergeBaseData { - public Branch Branch { get; private set; } - public Branch OtherBranch { get; private set; } - public IRepository Repository { get; private set; } + public string Sha1 { get; private set; } + public string Sha2 { get; private set; } - public Commit MergeBase { get; private set; } + public string MergeBase { get; private set; } - public MergeBaseData(Branch branch, Branch otherBranch, IRepository repository, Commit mergeBase) + public MergeBaseData(string sha1, string sha2, string mergeBase) { - Branch = branch; - OtherBranch = otherBranch; - Repository = repository; + Sha1 = sha1; + Sha2 = sha2; MergeBase = mergeBase; } } diff --git a/src/GitVersionCore/GitRepoInformation/Libgit2RepoMetadataProvider.cs b/src/GitVersionCore/GitRepoInformation/Libgit2RepoMetadataProvider.cs new file mode 100644 index 0000000000..c15a4ad749 --- /dev/null +++ b/src/GitVersionCore/GitRepoInformation/Libgit2RepoMetadataProvider.cs @@ -0,0 +1,155 @@ +using LibGit2Sharp; +using System.Collections.Generic; +using System.Linq; +using System; +using System.Text.RegularExpressions; +using GitTools; +using System.IO; + +namespace GitVersion.GitRepoInformation +{ + public class Libgit2RepoMetadataProvider + { + public static GitRepoMetadata ReadMetadata(GitVersionContext context) + { + using (Logger.IndentLog("Building information about your Git repository")) + { + Logger.WriteInfo($"Current branch is {context.CurrentBranch.FriendlyName}"); + if (context.CurrentBranch.Tip != context.CurrentCommit) + { + Logger.WriteInfo($@"Running against older commit of { + context.CurrentBranch.FriendlyName}, Tip: { + context.CurrentBranch.Tip.Sha.Substring(0, 8)}, Target: { + context.CurrentCommit.Sha.Substring(0, 8)}"); + } + var tags = ReadRepoTags(context); + var currentBranchInfo = ReadBranchInfo(context, context.CurrentBranch, context.CurrentCommit, tags); + var releaseBranches = ReadReleaseBranches(context, tags, currentBranchInfo); + var masterBranch = ReadMasterBranch(context, tags); + + return new GitRepoMetadata( + currentBranchInfo, + masterBranch, + releaseBranches); + } + } + + private static List ReadReleaseBranches(GitVersionContext context, List allTags, MBranch currentBranch) + { + using (Logger.IndentLog("Building information about release branches")) + { + var releaseBranchConfig = context.FullConfiguration.Branches + .Where(b => b.Value.IsReleaseBranch == true) + .ToList(); + + var releaseBranches = context.Repository + .Branches + .Where(b => releaseBranchConfig.Any(c => Regex.IsMatch(b.FriendlyName, c.Key))) + .ToList(); + + Logger.WriteInfo($"Found {string.Join(", ", releaseBranches.Select(b => b.FriendlyName))}"); + return releaseBranches + .Select(b => + { + // If current branch is a release branch, don't calculate everything again + if (b.FriendlyName == currentBranch.Name) + { + return currentBranch; + } + + return ReadBranchInfo(context, b, b.Tip, allTags); + }) + .ToList(); + } + } + + private static List ReadRepoTags(GitVersionContext context) + { + var olderThan = context.CurrentCommit.When(); + return context.Repository + .Tags + .Select(tag => + { + var commit = tag.PeeledTarget as Commit; + if (commit == null) + { + return null; + } + + return new MTag(tag.FriendlyName, CreateCommit(commit, context), context.FullConfiguration); + }) + .Where(t => t != null) + .ToList(); + } + + static MBranch ReadMasterBranch(GitVersionContext context, List tags) + { + var masterBranch = context.Repository.Branches["master"]; + if (masterBranch == null) + { + return null; + } + return ReadBranchInfo(context, masterBranch, masterBranch.Tip, tags); + } + + static MCommit CreateCommit(Commit commit, GitVersionContext context) + { + var commitCount = new Lazy(() => + context.RepositoryMetadataProvider.GetCommitCount(context.CurrentCommit, commit)); + + return new MCommit(commit, commitCount); + } + + private static MBranch ReadBranchInfo(GitVersionContext context, Branch branch, Commit at, List allTags) + { + using (Logger.IndentLog($"Calculating branch information for {branch.FriendlyName}")) + { + var filter = new CommitFilter + { + IncludeReachableFrom = at ?? branch.Tip, + SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Time, + }; + + var mergeMessages = new List(); + var branchTags = new List(); + var commits = context.Repository.Commits.QueryBy(filter); + var parent = context.RepositoryMetadataProvider.FindCommitBranchWasBranchedFrom(branch); + Commit tipCommit = null; + Commit lastCommit = null; + Commit parentMCommit = null; + + foreach (var branchCommit in commits) + { + if (tipCommit == null) + { + tipCommit = branchCommit; + } + lastCommit = branchCommit; + if (branchCommit.Parents.Count() >= 2) + { + mergeMessages.Add(new MergeMessage( + CreateCommit(branchCommit, context), + context.FullConfiguration)); + } + if (parent != BranchCommit.Empty && branchCommit.Sha == parent.Commit.Sha) + { + parentMCommit = parent.Commit; + } + + // Adding range because the same commit may have two tags + branchTags.AddRange(allTags.Where(t => t.Commit.Sha == branchCommit.Sha)); + } + + var mbranch = new MBranch( + branch.FriendlyName, + CreateCommit(tipCommit, context), + CreateCommit(lastCommit, context), + parentMCommit != null ? new MParent(CreateCommit(parentMCommit, context)) : null, + new List(), + mergeMessages); + mbranch.Tags.AddRange(branchTags.Select(t => new MBranchTag(mbranch, t))); + return mbranch; + } + } + } +} diff --git a/src/GitVersionCore/GitVersionContext.cs b/src/GitVersionCore/GitVersionContext.cs index 67bd267ef0..a84745c5e8 100644 --- a/src/GitVersionCore/GitVersionContext.cs +++ b/src/GitVersionCore/GitVersionContext.cs @@ -1,5 +1,6 @@ namespace GitVersion { + using GitVersion.GitRepoInformation; using LibGit2Sharp; using System; using System.Linq; @@ -66,6 +67,7 @@ public GitVersionContext(IRepository repository, Branch currentBranch, Config co }) .Max(); IsCurrentCommitTagged = CurrentCommitTaggedVersion != null; + RepositoryMetadata = Libgit2RepoMetadataProvider.ReadMetadata(this); } /// @@ -80,6 +82,13 @@ public GitVersionContext(IRepository repository, Branch currentBranch, Config co public Commit CurrentCommit { get; private set; } public bool IsCurrentCommitTagged { get; private set; } public GitRepoMetadataProvider RepositoryMetadataProvider { get; private set; } + /// + /// This is a new concept which is static metadata + /// It has no runtime dependencies on libgit2 and all information is pre-calculated. + /// We should move to use this, that way libgit2 is used when bootstrapping + /// this will be far easier to optimise then all the logic for gitversion will be entirely in memory + /// + public GitRepoMetadata RepositoryMetadata { get; private set; } void CalculateEffectiveConfiguration() { diff --git a/src/GitVersionCore/GitVersionCore.csproj b/src/GitVersionCore/GitVersionCore.csproj index acebe812b1..af1fe1d69a 100644 --- a/src/GitVersionCore/GitVersionCore.csproj +++ b/src/GitVersionCore/GitVersionCore.csproj @@ -114,7 +114,9 @@ - + + + @@ -137,6 +139,7 @@ + @@ -148,8 +151,7 @@ - - + @@ -232,4 +234,4 @@ - + \ No newline at end of file diff --git a/src/GitVersionCore/GitVersionFinder.cs b/src/GitVersionCore/GitVersionFinder.cs index 77addc07c1..df0dd0d50a 100644 --- a/src/GitVersionCore/GitVersionFinder.cs +++ b/src/GitVersionCore/GitVersionFinder.cs @@ -8,24 +8,23 @@ public class GitVersionFinder { public SemanticVersion FindVersion(GitVersionContext context) { - Logger.WriteInfo(string.Format( - "Running against branch: {0} ({1})", - context.CurrentBranch.FriendlyName, - context.CurrentCommit == null ? "-" : context.CurrentCommit.Sha)); - if (context.IsCurrentCommitTagged) + using (Logger.IndentLog("Calculating version numbers")) { - Logger.WriteInfo($"Current commit is tagged with version {context.CurrentCommitTaggedVersion}, " + - "version calcuation is for metadata only."); - } - EnsureMainTopologyConstraints(context); + if (context.IsCurrentCommitTagged) + { + Logger.WriteInfo($"Current commit is tagged with version {context.CurrentCommitTaggedVersion}, " + + "version calcuation is for metadata only."); + } + EnsureMainTopologyConstraints(context); - var filePath = Path.Combine(context.Repository.GetRepositoryDirectory(), "NextVersion.txt"); - if (File.Exists(filePath)) - { - throw new WarningException("NextVersion.txt has been deprecated. See http://gitversion.readthedocs.org/en/latest/configuration/ for replacement"); - } + var filePath = Path.Combine(context.Repository.GetRepositoryDirectory(), "NextVersion.txt"); + if (File.Exists(filePath)) + { + throw new WarningException("NextVersion.txt has been deprecated. See http://gitversion.readthedocs.org/en/latest/configuration/ for replacement"); + } - return new NextVersionCalculator().FindVersion(context); + return new NextVersionCalculator().FindVersion(context); + } } void EnsureMainTopologyConstraints(GitVersionContext context) diff --git a/src/GitVersionCore/IncrementStrategyFinder.cs b/src/GitVersionCore/IncrementStrategyFinder.cs index 724fae89fe..f09b88ee06 100644 --- a/src/GitVersionCore/IncrementStrategyFinder.cs +++ b/src/GitVersionCore/IncrementStrategyFinder.cs @@ -21,7 +21,7 @@ public static class IncrementStrategyFinder public const string DefaultPatchPattern = @"\+semver:\s?(fix|patch)"; public const string DefaultNoBumpPattern = @"\+semver:\s?(none|skip)"; - public static VersionField? DetermineIncrementedField(GitVersionContext context, BaseVersion baseVersion) + public static VersionField DetermineIncrementedField(GitVersionContext context, BaseVersion baseVersion) { var commitMessageIncrement = FindCommitMessageIncrement(context, baseVersion); var defaultIncrement = context.Configuration.Increment.ToVersionField(); @@ -29,7 +29,13 @@ public static class IncrementStrategyFinder // use the default branch config increment strategy if there are no commit message overrides if (commitMessageIncrement == null) { - return baseVersion.ShouldIncrement ? defaultIncrement : (VersionField?)null; + if (baseVersion.ShouldIncrement) + { + return defaultIncrement; + } + + Logger.WriteInfo($"Source {baseVersion.Source.Description} specifies no version increment, skipping increment"); + return VersionField.None; } // cap the commit message severity to minor for alpha versions @@ -45,7 +51,7 @@ public static class IncrementStrategyFinder return defaultIncrement; } - return commitMessageIncrement; + return commitMessageIncrement.Value; } private static VersionField? FindCommitMessageIncrement(GitVersionContext context, BaseVersion baseVersion) @@ -55,7 +61,9 @@ public static class IncrementStrategyFinder return null; } - var commits = GetIntermediateCommits(context.Repository, baseVersion.BaseVersionSource, context.CurrentCommit); + var commits = GetIntermediateCommits(context.Repository, + context.Repository.Lookup(baseVersion.Source.Commit.Sha), + context.CurrentCommit); if (context.Configuration.CommitMessageIncrementing == CommitMessageIncrementMode.MergeMessageOnly) { diff --git a/src/GitVersionCore/Logger.cs b/src/GitVersionCore/Logger.cs index 89c23d3804..436b4f8683 100644 --- a/src/GitVersionCore/Logger.cs +++ b/src/GitVersionCore/Logger.cs @@ -2,6 +2,7 @@ namespace GitVersion { using System; using System.Globalization; + using System.Linq; using System.Text.RegularExpressions; public static class Logger @@ -89,7 +90,20 @@ public static IDisposable AddLoggersTemporarily(Action debug, Action LogMessage(Action logAction, string level) { - return s => logAction(string.Format(CultureInfo.InvariantCulture, "{0}{1} [{2:MM/dd/yy H:mm:ss:ff}] {3}", indent, level, DateTime.Now, s)); + return s => { + var logPrefix = string.Format(CultureInfo.InvariantCulture, + "{0}{1} [{2:MM/dd/yy H:mm:ss:ff}]", + indent, level, DateTime.Now); + + logAction($"{logPrefix} {IndentMultilineLogs(s, new String(' ', logPrefix.Length))}"); + }; + } + + static Regex splitMultiline = new Regex(@"\r?\n", RegexOptions.Compiled); + private static string IndentMultilineLogs(string logMessage, string indent) + { + return string.Join(Environment.NewLine, splitMultiline.Split(logMessage) + .Select((line, index) => index > 0 ? string.Concat(indent, line) : line)); } public static void Reset() diff --git a/src/GitVersionCore/MergeMessage.cs b/src/GitVersionCore/MergeMessage.cs index 1dd5ecc3ac..c61044a877 100644 --- a/src/GitVersionCore/MergeMessage.cs +++ b/src/GitVersionCore/MergeMessage.cs @@ -1,10 +1,11 @@ -using System; +using GitVersion.GitRepoInformation; +using System; using System.Linq; using System.Text.RegularExpressions; namespace GitVersion { - class MergeMessage + public class MergeMessage { static Regex parseMergeMessage = new Regex( @"^Merge (branch|tag) '(?[^']*)'", @@ -15,19 +16,18 @@ class MergeMessage static Regex smartGitMergeMessage = new Regex( @"^Finish (?.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled); - private string mergeMessage; private Config config; - public MergeMessage(string mergeMessage, Config config) + public MergeMessage(MCommit sourceCommit, Config config) { - this.mergeMessage = mergeMessage; + SourceCommit = sourceCommit; this.config = config; - var lastIndexOf = mergeMessage.LastIndexOf("into", StringComparison.OrdinalIgnoreCase); + var lastIndexOf = SourceCommit.Message.LastIndexOf("into", StringComparison.OrdinalIgnoreCase); if (lastIndexOf != -1) { // If we have into in the merge message the rest should be the target branch - TargetBranch = mergeMessage.Substring(lastIndexOf + 5); + TargetBranch = SourceCommit.Message.Substring(lastIndexOf + 5); } MergedBranch = ParseBranch(); @@ -51,19 +51,19 @@ public MergeMessage(string mergeMessage, Config config) private string ParseBranch() { - var match = parseMergeMessage.Match(mergeMessage); + var match = parseMergeMessage.Match(SourceCommit.Message); if (match.Success) { return match.Groups["Branch"].Value; } - match = smartGitMergeMessage.Match(mergeMessage); + match = smartGitMergeMessage.Match(SourceCommit.Message); if (match.Success) { return match.Groups["Branch"].Value; } - match = parseGitHubPullMergeMessage.Match(mergeMessage); + match = parseGitHubPullMergeMessage.Match(SourceCommit.Message); if (match.Success) { IsMergedPullRequest = true; @@ -85,5 +85,6 @@ private string ParseBranch() public bool IsMergedPullRequest { get; private set; } public int? PullRequestNumber { get; private set; } public SemanticVersion Version { get; } + public MCommit SourceCommit { get; } } } diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculator.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculator.cs index 66d312dfa8..8312b61c1a 100644 --- a/src/GitVersionCore/VersionCalculation/BaseVersionCalculator.cs +++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculator.cs @@ -28,7 +28,7 @@ public BaseVersion GetBaseVersion(GitVersionContext context) foreach (var filter in context.Configuration.VersionFilters) { string reason; - if (filter.Exclude(v, out reason)) + if (filter.Exclude(v, context.Repository, out reason)) { Logger.WriteInfo(reason); return false; @@ -46,35 +46,31 @@ public BaseVersion GetBaseVersion(GitVersionContext context) var maxVersion = baseVersions.Aggregate((v1, v2) => v1.IncrementedVersion > v2.IncrementedVersion ? v1 : v2); var matchingVersionsOnceIncremented = baseVersions - .Where(b => b.Version.BaseVersionSource != null && b.IncrementedVersion == maxVersion.IncrementedVersion) + .Where(b => b.IncrementedVersion == maxVersion.IncrementedVersion) .ToList(); BaseVersion baseVersionWithOldestSource; - if (matchingVersionsOnceIncremented.Any()) + if (matchingVersionsOnceIncremented.Any(b => b != maxVersion)) { - var oldest = matchingVersionsOnceIncremented.Aggregate((v1, v2) => v1.Version.BaseVersionSource.Committer.When < v2.Version.BaseVersionSource.Committer.When ? v1 : v2); + var oldest = matchingVersionsOnceIncremented.Aggregate((v1, v2) => v1.Version.Source.Commit.DistanceFromTip > v2.Version.Source.Commit.DistanceFromTip ? v1 : v2); baseVersionWithOldestSource = oldest.Version; maxVersion = oldest; Logger.WriteInfo(string.Format( - "Found multiple base versions which will produce the same SemVer ({0}), taking oldest source for commit counting ({1})", + "Found multiple base versions which will produce the same SemVer ({0}), taking source with largest distance from tip ({1})", maxVersion.IncrementedVersion, - baseVersionWithOldestSource.Source)); + baseVersionWithOldestSource.Source.Description)); } else { baseVersionWithOldestSource = baseVersions - .Where(v => v.Version.BaseVersionSource != null) .OrderByDescending(v => v.IncrementedVersion) - .ThenByDescending(v => v.Version.BaseVersionSource.Committer.When) + .ThenByDescending(v => v.Version.Source.Commit.When) .First() .Version; } - if (baseVersionWithOldestSource.BaseVersionSource == null) - throw new Exception("Base version should not be null"); - var calculatedBase = new BaseVersion( - context, maxVersion.Version.Source, maxVersion.Version.ShouldIncrement, maxVersion.Version.SemanticVersion, - baseVersionWithOldestSource.BaseVersionSource, maxVersion.Version.BranchNameOverride); + context, maxVersion.Version.ShouldIncrement, maxVersion.Version.SemanticVersion, + baseVersionWithOldestSource.Source, maxVersion.Version.BranchNameOverride); Logger.WriteInfo(string.Format("Base version used: {0}", calculatedBase)); @@ -85,12 +81,7 @@ public BaseVersion GetBaseVersion(GitVersionContext context) public static SemanticVersion MaybeIncrement(GitVersionContext context, BaseVersion version) { var increment = IncrementStrategyFinder.DetermineIncrementedField(context, version); - if (increment != null) - { - return version.SemanticVersion.IncrementVersion(increment.Value); - } - - return version.SemanticVersion; + return version.SemanticVersion.IncrementVersion(increment); } } } \ No newline at end of file diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/BaseVersion.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/BaseVersion.cs index c54d2b00bd..acc526531f 100644 --- a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/BaseVersion.cs +++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/BaseVersion.cs @@ -1,38 +1,47 @@ -namespace GitVersion.VersionCalculation.BaseVersionCalculators -{ - using LibGit2Sharp; +using GitVersion.GitRepoInformation; +using System; +namespace GitVersion.VersionCalculation.BaseVersionCalculators +{ public class BaseVersion { GitVersionContext _context; - public BaseVersion(GitVersionContext context, string source, bool shouldIncrement, SemanticVersion semanticVersion, Commit baseVersionSource, string branchNameOverride) + public BaseVersion( + GitVersionContext context, bool shouldIncrement, + SemanticVersion semanticVersion, BaseVersionSource source, + string branchNameOverride) { - Source = source; ShouldIncrement = shouldIncrement; SemanticVersion = semanticVersion; - BaseVersionSource = baseVersionSource; + Source = source; BranchNameOverride = branchNameOverride; _context = context; } - public string Source { get; private set; } - - public bool ShouldIncrement { get; private set; } + public bool ShouldIncrement { get; } - public SemanticVersion SemanticVersion { get; private set; } + public SemanticVersion SemanticVersion { get; } - public Commit BaseVersionSource { get; private set; } + public BaseVersionSource Source { get; } - public string BranchNameOverride { get; private set; } + public string BranchNameOverride { get; } public override string ToString() { - return string.Format( - "{0}: {1} with commit count source {2} (Incremented: {3})", - Source, SemanticVersion.ToString("f"), - BaseVersionSource == null ? "External Source" : BaseVersionSource.Sha, - ShouldIncrement ? BaseVersionCalculator.MaybeIncrement(_context, this).ToString("t") : "None"); + return $"{Source.Description}: {SemanticVersion.ToString("f")} with commit count of {Source.Commit.DistanceFromTip} (Incremented: {(ShouldIncrement ? BaseVersionCalculator.MaybeIncrement(_context, this).ToString("t") : "None")})"; } } + + public class BaseVersionSource + { + public BaseVersionSource(MCommit sourceCommit, string description) + { + Description = description; + Commit = sourceCommit; + } + + public string Description { get; } + public MCommit Commit { get; } + } } \ No newline at end of file diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/ConfigNextVersionBaseVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/ConfigNextVersionBaseVersionStrategy.cs index d69cf450c4..107575d220 100644 --- a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/ConfigNextVersionBaseVersionStrategy.cs +++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/ConfigNextVersionBaseVersionStrategy.cs @@ -1,6 +1,10 @@ namespace GitVersion.VersionCalculation.BaseVersionCalculators { + using GitVersion.GitRepoInformation; + using LibGit2Sharp; + using System; using System.Collections.Generic; + using System.Linq; /// /// Version is from NextVersion (the configuration value), unless the current commit is tagged. @@ -12,9 +16,25 @@ public class ConfigNextVersionBaseVersionStrategy : BaseVersionStrategy public override IEnumerable GetVersions(GitVersionContext context) { if (string.IsNullOrEmpty(context.Configuration.NextVersion) || context.IsCurrentCommitTagged) + { yield break; + } var semanticVersion = SemanticVersion.Parse(context.Configuration.NextVersion, context.Configuration.GitTagPrefix); - yield return new BaseVersion(context, "NextVersion in GitVersion configuration file", false, semanticVersion, null, null); + var configHistory = string.IsNullOrEmpty(context.FullConfiguration.Filename) + ? null + : context.Repository.Commits.QueryBy(context.FullConfiguration.Filename).FirstOrDefault(); + + var sourceCommit = configHistory == null + ? context.RepositoryMetadata.CurrentBranch.Tip + : new MCommit( + configHistory.Commit, + new Lazy(() => context.RepositoryMetadataProvider.GetCommitCount( + context.CurrentCommit, + context.Repository.Lookup(configHistory.Commit.Sha)))); + var source = new BaseVersionSource( + sourceCommit, + "NextVersion in GitVersion configuration file"); + yield return new BaseVersion(context, false, semanticVersion, source, null); } } } \ No newline at end of file diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/FallbackBaseVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/FallbackBaseVersionStrategy.cs new file mode 100644 index 0000000000..0017572a8a --- /dev/null +++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/FallbackBaseVersionStrategy.cs @@ -0,0 +1,23 @@ +namespace GitVersion.VersionCalculation +{ + using System.Collections.Generic; + using System.Linq; + using BaseVersionCalculators; + using LibGit2Sharp; + + /// + /// Version is 0.1.0. + /// BaseVersionSource is the "root" commit reachable from the current commit. + /// Does not increment. + /// + public class FallbackBaseVersionStrategy : BaseVersionStrategy + { + public override IEnumerable GetVersions(GitVersionContext context) + { + var source = new BaseVersionSource( + context.RepositoryMetadata.CurrentBranch.Root, + $"Fallback to root commit of {context.RepositoryMetadata.CurrentBranch.Name}"); + yield return new BaseVersion(context, false, new SemanticVersion(minor: 1), source, null); + } + } +} \ No newline at end of file diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs index e9fac9c84c..76a00b8593 100644 --- a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs +++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/MergeMessageBaseVersionStrategy.cs @@ -13,40 +13,17 @@ public class MergeMessageBaseVersionStrategy : BaseVersionStrategy { public override IEnumerable GetVersions(GitVersionContext context) { - var commitsPriorToThan = context.CurrentBranch - .CommitsPriorToThan(context.CurrentCommit.When()); - var baseVersions = commitsPriorToThan - .SelectMany(c => + return context + .RepositoryMetadata + .CurrentBranch + .MergeMessages + .Where(m => m.Version != null) + .Select(m => { - SemanticVersion semanticVersion; - if (TryParse(c, context, out semanticVersion)) - { - var shouldIncrement = !context.Configuration.PreventIncrementForMergedBranchVersion; - return new[] - { - new BaseVersion(context, string.Format("Merge message '{0}'", c.Message.Trim()), shouldIncrement, semanticVersion, c, null) - }; - } - return Enumerable.Empty(); - }).ToList(); - return baseVersions; - } - - static bool TryParse(Commit mergeCommit, GitVersionContext context, out SemanticVersion semanticVersion) - { - semanticVersion = Inner(mergeCommit, context); - return semanticVersion != null; - } - - static SemanticVersion Inner(Commit mergeCommit, GitVersionContext context) - { - if (mergeCommit.Parents.Count() < 2) - { - return null; - } - - var mergeMessage = new MergeMessage(mergeCommit.Message, context.FullConfiguration); - return mergeMessage.Version; + var shouldIncrement = !context.Configuration.PreventIncrementForMergedBranchVersion; + var source = new BaseVersionSource(m.SourceCommit, $"Merge message '{m.SourceCommit.Message.Trim()}' @ {m.SourceCommit.Sha}"); + return new BaseVersion(context, shouldIncrement, m.Version, source, null); + }); } } } \ No newline at end of file diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/TaggedCommitVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/TaggedCommitVersionStrategy.cs index 4955be0203..f8837c2393 100644 --- a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/TaggedCommitVersionStrategy.cs +++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/TaggedCommitVersionStrategy.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using LibGit2Sharp; + using GitVersion.GitRepoInformation; /// /// Version is extracted from all tags on the branch which are valid, and not newer than the current commit. @@ -14,63 +15,22 @@ public class TaggedCommitVersionStrategy : BaseVersionStrategy { public override IEnumerable GetVersions(GitVersionContext context) { - return GetTaggedVersions(context, context.CurrentBranch, context.CurrentCommit.When()); + return GetTaggedVersions(context, context.RepositoryMetadata.CurrentBranch); } - public IEnumerable GetTaggedVersions(GitVersionContext context, Branch currentBranch, DateTimeOffset? olderThan) + public IEnumerable GetTaggedVersions(GitVersionContext context, MBranch currentBranch) { - var allTags = context.Repository.Tags - .Where(tag => !olderThan.HasValue || ((Commit) tag.PeeledTarget()).When() <= olderThan.Value) - .ToList(); - var tagsOnBranch = currentBranch - .Commits - .SelectMany(commit => { return allTags.Where(t => IsValidTag(t, commit)); }) - .Select(t => - { - SemanticVersion version; - if (SemanticVersion.TryParse(t.FriendlyName, context.Configuration.GitTagPrefix, out version)) - { - var commit = t.PeeledTarget() as Commit; - if (commit != null) - return new VersionTaggedCommit(commit, version, t.FriendlyName); - } - return null; - }) - .Where(a => a != null) - .ToList(); - - return tagsOnBranch.Select(t => CreateBaseVersion(context, t)); - } - - BaseVersion CreateBaseVersion(GitVersionContext context, VersionTaggedCommit version) - { - var shouldUpdateVersion = version.Commit.Sha != context.CurrentCommit.Sha; - var baseVersion = new BaseVersion(context, FormatSource(version), shouldUpdateVersion, version.SemVer, version.Commit, null); - return baseVersion; + return currentBranch + .Tags + .Where(t => t.Tag.Version != null) + .Select(t => CreateBaseVersion(context, t)); } - protected virtual string FormatSource(VersionTaggedCommit version) + BaseVersion CreateBaseVersion(GitVersionContext context, MBranchTag tag) { - return string.Format("Git tag '{0}'", version.Tag); - } - - protected virtual bool IsValidTag(Tag tag, Commit commit) - { - return tag.PeeledTarget() == commit; - } - - protected class VersionTaggedCommit - { - public string Tag; - public Commit Commit; - public SemanticVersion SemVer; - - public VersionTaggedCommit(Commit commit, SemanticVersion semVer, string tag) - { - Tag = tag; - Commit = commit; - SemVer = semVer; - } + var shouldUpdateVersion = tag.Tag.Commit.Sha != context.CurrentCommit.Sha; + var source = new BaseVersionSource(tag.Tag.Commit, $"Git tag '{tag.Tag.Name}'"); + return new BaseVersion(context, shouldUpdateVersion, tag.Tag.Version, source, null); } } } \ No newline at end of file diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/TrackReleaseBranchesVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/TrackReleaseBranchesVersionStrategy.cs new file mode 100644 index 0000000000..586917c36a --- /dev/null +++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/TrackReleaseBranchesVersionStrategy.cs @@ -0,0 +1,124 @@ +namespace GitVersion.VersionCalculation +{ + using System.Collections.Generic; + using System.Linq; + using System.Text.RegularExpressions; + using BaseVersionCalculators; + using GitTools; + using LibGit2Sharp; + using System; + using GitVersion.GitRepoInformation; + + /// + /// Active only when the branch is marked as IsDevelop. + /// Two different algorithms (results are merged): + /// + /// Using : + /// Version is that of any child branches marked with IsReleaseBranch (except if they have no commits of their own). + /// BaseVersionSource is the commit where the child branch was created. + /// Always increments. + /// + /// + /// Using : + /// Version is extracted from all tags on the master branch which are valid. + /// BaseVersionSource is the tag's commit (same as base strategy). + /// Increments if the tag is not the current commit (same as base strategy). + /// + /// + public class TrackReleaseBranchesVersionStrategy : BaseVersionStrategy + { + VersionInBranchNameBaseVersionStrategy releaseVersionStrategy = new VersionInBranchNameBaseVersionStrategy(); + TaggedCommitVersionStrategy taggedCommitVersionStrategy = new TaggedCommitVersionStrategy(); + Func getBaseVersionCalculator; + + public TrackReleaseBranchesVersionStrategy(Func getBaseVersionCalculator) + { + this.getBaseVersionCalculator = getBaseVersionCalculator; + } + + public override IEnumerable GetVersions(GitVersionContext context) + { + if (context.Configuration.TracksReleaseBranches) + { + + + // I feel this is actually a recursive path for GitVersion and rather than + // having all this logic in here, we should just run it for each release branch and master + + // Something like this, but will need to refactor BaseVersionStrategy + //var baseVersionCalculator = getBaseVersionCalculator(); + //context.RepositoryMetadata.ReleaseBranches + // .Select(r => baseVersionCalculator.GetBaseVersion() + + + return ReleaseBranchBaseVersions(context).Union(MasterTagsVersions(context)); + } + + return new BaseVersion[0]; + } + + private IEnumerable MasterTagsVersions(GitVersionContext context) + { + var master = context.RepositoryMetadata.MasterBranch; + if (master != null) + { + return taggedCommitVersionStrategy + .GetTaggedVersions(context, master) + .Select(b => new BaseVersion( + context, b.ShouldIncrement, b.SemanticVersion, + new BaseVersionSource(b.Source.Commit, $"Tag on master: {b.Source.Description}"), + b.BranchNameOverride)); + } + + return new BaseVersion[0]; + } + + private IEnumerable ReleaseBranchBaseVersions(GitVersionContext context) + { + return context + .RepositoryMetadata + .ReleaseBranches + .SelectMany(b => GetReleaseVersion(context, b)) + .Select(baseVersion => + { + // Need to drop branch overrides and give a bit more context about + // where this version came from + var source1 = "Release branch exists -> " + baseVersion.Source.Description; + return new BaseVersion(context, + baseVersion.ShouldIncrement, + baseVersion.SemanticVersion, + new BaseVersionSource(baseVersion.Source.Commit, source1), + null); + }) + .ToList(); + } + + IEnumerable GetReleaseVersion(GitVersionContext context, MBranch releaseBranch) + { + var tagPrefixRegex = context.Configuration.GitTagPrefix; + var repository = context.Repository; + + // Find the commit where the child branch was created. + var baseSource = context.RepositoryMetadataProvider.FindMergeBase(releaseBranch.Tip.Sha, context.CurrentCommit.Sha); + if (baseSource == context.CurrentCommit) + { + // Ignore the branch if it has no commits. + return new BaseVersion[0]; + } + + return releaseVersionStrategy + .GetVersions(context, tagPrefixRegex, releaseBranch, repository) + .Select(b => + { + var source = new BaseVersionSource( + new MCommit( + baseSource.Sha, + baseSource.When().DateTime, + baseSource.Message, + new Lazy(() => context.RepositoryMetadataProvider.GetCommitCount(context.CurrentCommit, baseSource))), + $"Tracked release branch version: {b.Source.Description}"); + return new BaseVersion(context, true, b.SemanticVersion, source, b.BranchNameOverride); + }); + } + } +} \ No newline at end of file diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchNameBaseVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchNameBaseVersionStrategy.cs index db2546e06a..8509a5a3e5 100644 --- a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchNameBaseVersionStrategy.cs +++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchNameBaseVersionStrategy.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using LibGit2Sharp; + using GitVersion.GitRepoInformation; /// /// Version is extracted from the name of the branch. @@ -13,21 +14,21 @@ public class VersionInBranchNameBaseVersionStrategy : BaseVersionStrategy { public override IEnumerable GetVersions(GitVersionContext context) { - var currentBranch = context.CurrentBranch; + var currentBranch = context.RepositoryMetadata.CurrentBranch; var tagPrefixRegex = context.Configuration.GitTagPrefix; var repository = context.Repository; return GetVersions(context, tagPrefixRegex, currentBranch, repository); } - public IEnumerable GetVersions(GitVersionContext context, string tagPrefixRegex, Branch currentBranch, IRepository repository) + public IEnumerable GetVersions(GitVersionContext context, string tagPrefixRegex, MBranch currentBranch, IRepository repository) { - var branchName = currentBranch.FriendlyName; + var branchName = currentBranch.Name; var versionInBranch = GetVersionInBranch(branchName, tagPrefixRegex); if (versionInBranch != null) { - var commitBranchWasBranchedFrom = context.RepositoryMetadataProvider.FindCommitBranchWasBranchedFrom(currentBranch); var branchNameOverride = branchName.RegexReplace("[-/]" + versionInBranch.Item1, string.Empty); - yield return new BaseVersion(context, "Version in branch name", false, versionInBranch.Item2, commitBranchWasBranchedFrom.Commit, branchNameOverride); + var source = new BaseVersionSource(currentBranch.Parent.MergeBase, $"Version in branch name with origin commit of {currentBranch.Parent.MergeBase.Sha}"); + yield return new BaseVersion(context, false, versionInBranch.Item2, source, branchNameOverride); } } diff --git a/src/GitVersionCore/VersionCalculation/DevelopVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/DevelopVersionStrategy.cs deleted file mode 100644 index 99cea3298d..0000000000 --- a/src/GitVersionCore/VersionCalculation/DevelopVersionStrategy.cs +++ /dev/null @@ -1,99 +0,0 @@ -namespace GitVersion.VersionCalculation -{ - using System.Collections.Generic; - using System.Linq; - using System.Text.RegularExpressions; - using BaseVersionCalculators; - using GitTools; - using LibGit2Sharp; - - /// - /// Active only when the branch is marked as IsDevelop. - /// Two different algorithms (results are merged): - /// - /// Using : - /// Version is that of any child branches marked with IsReleaseBranch (except if they have no commits of their own). - /// BaseVersionSource is the commit where the child branch was created. - /// Always increments. - /// - /// - /// Using : - /// Version is extracted from all tags on the master branch which are valid. - /// BaseVersionSource is the tag's commit (same as base strategy). - /// Increments if the tag is not the current commit (same as base strategy). - /// - /// - public class TrackReleaseBranchesVersionStrategy : BaseVersionStrategy - { - VersionInBranchNameBaseVersionStrategy releaseVersionStrategy = new VersionInBranchNameBaseVersionStrategy(); - TaggedCommitVersionStrategy taggedCommitVersionStrategy = new TaggedCommitVersionStrategy(); - - public override IEnumerable GetVersions(GitVersionContext context) - { - if (context.Configuration.TracksReleaseBranches) - { - return ReleaseBranchBaseVersions(context).Union(MasterTagsVersions(context)); - } - - return new BaseVersion[0]; - } - - private IEnumerable MasterTagsVersions(GitVersionContext context) - { - var master = context.Repository.FindBranch("master"); - if (master != null) - { - return taggedCommitVersionStrategy.GetTaggedVersions(context, master, null); - } - - return new BaseVersion[0]; - } - - private IEnumerable ReleaseBranchBaseVersions(GitVersionContext context) - { - var releaseBranchConfig = context.FullConfiguration.Branches - .Where(b => b.Value.IsReleaseBranch == true) - .ToList(); - if (releaseBranchConfig.Any()) - { - var releaseBranches = context.Repository.Branches - .Where(b => releaseBranchConfig.Any(c => Regex.IsMatch(b.FriendlyName, c.Key))); - - return releaseBranches - .SelectMany(b => GetReleaseVersion(context, b)) - .Select(baseVersion => - { - // Need to drop branch overrides and give a bit more context about - // where this version came from - var source1 = "Release branch exists -> " + baseVersion.Source; - return new BaseVersion(context, - source1, - baseVersion.ShouldIncrement, - baseVersion.SemanticVersion, - baseVersion.BaseVersionSource, - null); - }) - .ToList(); - } - return new BaseVersion[0]; - } - - IEnumerable GetReleaseVersion(GitVersionContext context, Branch releaseBranch) - { - var tagPrefixRegex = context.Configuration.GitTagPrefix; - var repository = context.Repository; - - // Find the commit where the child branch was created. - var baseSource = context.RepositoryMetadataProvider.FindMergeBase(releaseBranch, context.CurrentBranch); - if (baseSource == context.CurrentCommit) - { - // Ignore the branch if it has no commits. - return new BaseVersion[0]; - } - - return releaseVersionStrategy - .GetVersions(context, tagPrefixRegex, releaseBranch, repository) - .Select(b => new BaseVersion(context, b.Source, true, b.SemanticVersion, baseSource, b.BranchNameOverride)); - } - } -} \ No newline at end of file diff --git a/src/GitVersionCore/VersionCalculation/FallbackBaseVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/FallbackBaseVersionStrategy.cs deleted file mode 100644 index a7087923d4..0000000000 --- a/src/GitVersionCore/VersionCalculation/FallbackBaseVersionStrategy.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace GitVersion.VersionCalculation -{ - using System.Collections.Generic; - using System.Linq; - using BaseVersionCalculators; - using LibGit2Sharp; - - /// - /// Version is 0.1.0. - /// BaseVersionSource is the "root" commit reachable from the current commit. - /// Does not increment. - /// - public class FallbackBaseVersionStrategy : BaseVersionStrategy - { - public override IEnumerable GetVersions(GitVersionContext context) - { - Commit baseVersionSource; - var currentBranchTip = context.CurrentBranch.Tip; - - try - { - baseVersionSource = context.Repository.Commits.QueryBy(new CommitFilter - { - IncludeReachableFrom = currentBranchTip - }).First(c => !c.Parents.Any()); - } - catch (NotFoundException exception) - { - throw new GitVersionException($"Can't find commit {currentBranchTip.Sha}. Please ensure that the repository is an unshallow clone with `git fetch --unshallow`.", exception); - } - - yield return new BaseVersion(context, "Fallback base version", false, new SemanticVersion(minor : 1), baseVersionSource, null); - } - } -} \ No newline at end of file diff --git a/src/GitVersionCore/VersionCalculation/IMetaDataCalculator.cs b/src/GitVersionCore/VersionCalculation/IMetaDataCalculator.cs index 967baf8528..86352e3c12 100644 --- a/src/GitVersionCore/VersionCalculation/IMetaDataCalculator.cs +++ b/src/GitVersionCore/VersionCalculation/IMetaDataCalculator.cs @@ -1,9 +1,9 @@ -namespace GitVersion.VersionCalculation -{ - using LibGit2Sharp; +using GitVersion.VersionCalculation.BaseVersionCalculators; +namespace GitVersion.VersionCalculation +{ public interface IMetaDataCalculator { - SemanticVersionBuildMetaData Create(Commit baseVersionSource, GitVersionContext context); + SemanticVersionBuildMetaData Create(int commitCount, GitVersionContext context); } } \ No newline at end of file diff --git a/src/GitVersionCore/VersionCalculation/MainlineVersionCalculator.cs b/src/GitVersionCore/VersionCalculation/MainlineVersionCalculator.cs index 2c95be6016..07123eb164 100644 --- a/src/GitVersionCore/VersionCalculation/MainlineVersionCalculator.cs +++ b/src/GitVersionCore/VersionCalculation/MainlineVersionCalculator.cs @@ -1,4 +1,5 @@ -using GitVersion.VersionCalculation.BaseVersionCalculators; +using GitVersion.GitRepoInformation; +using GitVersion.VersionCalculation.BaseVersionCalculators; using LibGit2Sharp; using System; using System.Collections.Generic; @@ -40,15 +41,15 @@ public SemanticVersion FindMainlineModeVersion(BaseVersion baseVersion, GitVersi ExcludeReachableFrom = mainlineTip, SortBy = CommitSortStrategies.Reverse, FirstParentOnly = true - }).Where(c => c.Sha != baseVersion.BaseVersionSource.Sha && c.Parents.Count() == 1).ToList(); + }).Where(c => c.Sha != baseVersion.Source.Commit.Sha && c.Parents.Count() == 1).ToList(); var commitLog = context.Repository.Commits.QueryBy(new CommitFilter { IncludeReachableFrom = context.CurrentBranch, - ExcludeReachableFrom = baseVersion.BaseVersionSource, + ExcludeReachableFrom = context.Repository.Lookup(baseVersion.Source.Commit.Sha), SortBy = CommitSortStrategies.Reverse, FirstParentOnly = true }) - .Where(c => c.Sha != baseVersion.BaseVersionSource.Sha) + .Where(c => c.Sha != baseVersion.Source.Commit.Sha) .Except(commitsNotOnMainline) .ToList(); @@ -73,7 +74,7 @@ public SemanticVersion FindMainlineModeVersion(BaseVersion baseVersion, GitVersi var branchIncrement = FindMessageIncrement(context, null, mergedHead, findMergeBase, directCommits); // This will increment for any direct commits on master mainlineVersion = IncrementForEachCommit(context, directCommits, mainlineVersion, "master"); - mainlineVersion.BuildMetaData = metaDataCalculator.Create(findMergeBase, context); + mainlineVersion.BuildMetaData = metaDataCalculator.Create(context.RepositoryMetadataProvider.GetCommitCount(context.CurrentCommit, findMergeBase), context); // Don't increment if the merge commit is a merge into mainline // this ensures PR's and forward merges end up correct. if (mergedHead.Parents.Count() == 1 || mergedHead.Parents.First() != mainlineTip) @@ -86,7 +87,7 @@ public SemanticVersion FindMainlineModeVersion(BaseVersion baseVersion, GitVersi { // If we are on master, make sure no commits get left behind mainlineVersion = IncrementForEachCommit(context, directCommits, mainlineVersion); - mainlineVersion.BuildMetaData = metaDataCalculator.Create(baseVersion.BaseVersionSource, context); + mainlineVersion.BuildMetaData = metaDataCalculator.Create(baseVersion.Source.Commit.DistanceFromTip, context); } return mainlineVersion; @@ -198,7 +199,9 @@ private static VersionField TryFindIncrementFromMergeMessage(Commit mergeCommit, { if (mergeCommit != null) { - var mergeMessage = new MergeMessage(mergeCommit.Message, context.FullConfiguration); + var distance = context.RepositoryMetadataProvider.GetCommitCount(context.CurrentCommit, mergeCommit); + var mCommit = new MCommit(mergeCommit.Sha, mergeCommit.Committer.When.DateTime, mergeCommit.Message, new Lazy(() => distance)); + var mergeMessage = new MergeMessage(mCommit, context.FullConfiguration); if (mergeMessage.MergedBranch != null) { var config = context.FullConfiguration.GetConfigForBranch(mergeMessage.MergedBranch); diff --git a/src/GitVersionCore/VersionCalculation/MetaDataCalculator.cs b/src/GitVersionCore/VersionCalculation/MetaDataCalculator.cs index bc3a88959a..8b96bda5fd 100644 --- a/src/GitVersionCore/VersionCalculation/MetaDataCalculator.cs +++ b/src/GitVersionCore/VersionCalculation/MetaDataCalculator.cs @@ -1,25 +1,11 @@ namespace GitVersion.VersionCalculation { - using System.Linq; - using LibGit2Sharp; - public class MetaDataCalculator : IMetaDataCalculator { - public SemanticVersionBuildMetaData Create(Commit baseVersionSource, GitVersionContext context) + public SemanticVersionBuildMetaData Create(int commitCount, GitVersionContext context) { - var qf = new CommitFilter - { - IncludeReachableFrom = context.CurrentCommit, - ExcludeReachableFrom = baseVersionSource, - SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Time - }; - - var commitLog = context.Repository.Commits.QueryBy(qf); - var commitsSinceTag = commitLog.Count(); - Logger.WriteInfo(string.Format("{0} commits found between {1} and {2}", commitsSinceTag, baseVersionSource.Sha, context.CurrentCommit.Sha)); - return new SemanticVersionBuildMetaData( - commitsSinceTag, + commitCount, context.CurrentBranch.FriendlyName, context.CurrentCommit.Sha, context.CurrentCommit.When()); diff --git a/src/GitVersionCore/VersionCalculation/NextVersionCalculator.cs b/src/GitVersionCore/VersionCalculation/NextVersionCalculator.cs index 3cb2a5e145..f8079961c3 100644 --- a/src/GitVersionCore/VersionCalculation/NextVersionCalculator.cs +++ b/src/GitVersionCore/VersionCalculation/NextVersionCalculator.cs @@ -19,7 +19,7 @@ public NextVersionCalculator(IBaseVersionCalculator baseVersionCalculator = null new TaggedCommitVersionStrategy(), new MergeMessageBaseVersionStrategy(), new VersionInBranchNameBaseVersionStrategy(), - new TrackReleaseBranchesVersionStrategy()); + new TrackReleaseBranchesVersionStrategy(() => baseVersionFinder)); } public SemanticVersion FindVersion(GitVersionContext context) @@ -29,7 +29,7 @@ public SemanticVersion FindVersion(GitVersionContext context) if (context.IsCurrentCommitTagged) { // Will always be 0, don't bother with the +0 on tags - var semanticVersionBuildMetaData = metaDataCalculator.Create(context.CurrentCommit, context); + var semanticVersionBuildMetaData = metaDataCalculator.Create(0, context); semanticVersionBuildMetaData.CommitsSinceTag = null; var semanticVersion = new SemanticVersion(context.CurrentCommitTaggedVersion) @@ -49,7 +49,7 @@ public SemanticVersion FindVersion(GitVersionContext context) else { semver = PerformIncrement(context, baseVersion); - semver.BuildMetaData = metaDataCalculator.Create(baseVersion.BaseVersionSource, context); + semver.BuildMetaData = metaDataCalculator.Create(baseVersion.Source.Commit.DistanceFromTip, context); } var hasPreReleaseTag = semver.PreReleaseTag.HasTag(); @@ -72,14 +72,8 @@ public SemanticVersion FindVersion(GitVersionContext context) private static SemanticVersion PerformIncrement(GitVersionContext context, BaseVersion baseVersion) { - var semver = baseVersion.SemanticVersion; var increment = IncrementStrategyFinder.DetermineIncrementedField(context, baseVersion); - if (increment != null) - { - semver = semver.IncrementVersion(increment.Value); - } - else Logger.WriteInfo("Skipping version increment"); - return semver; + return baseVersion.SemanticVersion.IncrementVersion(increment); } void UpdatePreReleaseTag(GitVersionContext context, SemanticVersion semanticVersion, string branchNameOverride) diff --git a/src/GitVersionCore/VersionFilters/IVersionFilter.cs b/src/GitVersionCore/VersionFilters/IVersionFilter.cs index 3e9b5407f9..6461bd7c8e 100644 --- a/src/GitVersionCore/VersionFilters/IVersionFilter.cs +++ b/src/GitVersionCore/VersionFilters/IVersionFilter.cs @@ -1,9 +1,10 @@ using GitVersion.VersionCalculation.BaseVersionCalculators; +using LibGit2Sharp; namespace GitVersion.VersionFilters { public interface IVersionFilter { - bool Exclude(BaseVersion version, out string reason); + bool Exclude(BaseVersion version, IRepository repository, out string reason); } } diff --git a/src/GitVersionCore/VersionFilters/MinDateVersionFilter.cs b/src/GitVersionCore/VersionFilters/MinDateVersionFilter.cs index d8df5fce8f..083f53b3d4 100644 --- a/src/GitVersionCore/VersionFilters/MinDateVersionFilter.cs +++ b/src/GitVersionCore/VersionFilters/MinDateVersionFilter.cs @@ -1,8 +1,10 @@ using System; using GitVersion.VersionCalculation.BaseVersionCalculators; +using LibGit2Sharp; namespace GitVersion.VersionFilters { + // TODO Move filters to the metadata builder public class MinDateVersionFilter : IVersionFilter { private readonly DateTimeOffset minimum; @@ -12,14 +14,14 @@ public MinDateVersionFilter(DateTimeOffset minimum) this.minimum = minimum; } - public bool Exclude(BaseVersion version, out string reason) + public bool Exclude(BaseVersion version, IRepository repository, out string reason) { if (version == null) throw new ArgumentNullException("version"); reason = null; - if (version.BaseVersionSource != null && - version.BaseVersionSource.When() < minimum) + if (version.Source != null && + version.Source.Commit.When < minimum) { reason = "Source was ignored due to commit date being outside of configured range"; return true; diff --git a/src/GitVersionCore/VersionFilters/ShaVersionFilter.cs b/src/GitVersionCore/VersionFilters/ShaVersionFilter.cs index afa1ff5330..8433709bbd 100644 --- a/src/GitVersionCore/VersionFilters/ShaVersionFilter.cs +++ b/src/GitVersionCore/VersionFilters/ShaVersionFilter.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using GitVersion.VersionCalculation.BaseVersionCalculators; +using LibGit2Sharp; namespace GitVersion.VersionFilters { @@ -15,16 +16,16 @@ public ShaVersionFilter(IEnumerable shas) this.shas = shas; } - public bool Exclude(BaseVersion version, out string reason) + public bool Exclude(BaseVersion version, IRepository repository, out string reason) { if (version == null) throw new ArgumentNullException("version"); reason = null; - if (version.BaseVersionSource != null && - shas.Any(sha => version.BaseVersionSource.Sha.StartsWith(sha, StringComparison.OrdinalIgnoreCase))) + if (version.Source != null && + shas.Any(sha => version.Source.Commit.Sha.StartsWith(sha, StringComparison.OrdinalIgnoreCase))) { - reason = $"Sha {version.BaseVersionSource.Sha} was ignored due to commit having been excluded by configuration"; + reason = $"Sha {version.Source.Commit.Sha} was ignored due to commit having been excluded by configuration"; return true; } diff --git a/src/GitVersionExe.Tests/GitVersionExe.Tests.csproj b/src/GitVersionExe.Tests/GitVersionExe.Tests.csproj index 35845d9e0f..3f37f0a91f 100644 --- a/src/GitVersionExe.Tests/GitVersionExe.Tests.csproj +++ b/src/GitVersionExe.Tests/GitVersionExe.Tests.csproj @@ -1,5 +1,6 @@  + @@ -67,9 +68,8 @@ ..\packages\NSubstitute.1.10.0.0\lib\net45\NSubstitute.dll True - - ..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll - True + + ..\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll ..\packages\Shouldly.2.7.0\lib\net40\Shouldly.dll @@ -132,5 +132,6 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + \ No newline at end of file diff --git a/src/GitVersionExe.Tests/packages.config b/src/GitVersionExe.Tests/packages.config index 30641d4d15..22e547e4ae 100644 --- a/src/GitVersionExe.Tests/packages.config +++ b/src/GitVersionExe.Tests/packages.config @@ -6,7 +6,7 @@ - - + + \ No newline at end of file diff --git a/src/GitVersionTask.Tests/GitVersionTask.Tests.csproj b/src/GitVersionTask.Tests/GitVersionTask.Tests.csproj index 609219d570..3bd0334304 100644 --- a/src/GitVersionTask.Tests/GitVersionTask.Tests.csproj +++ b/src/GitVersionTask.Tests/GitVersionTask.Tests.csproj @@ -1,5 +1,6 @@  + Debug @@ -59,9 +60,8 @@ ..\packages\NSubstitute.1.10.0.0\lib\net45\NSubstitute.dll True - - ..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll - True + + ..\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll ..\packages\Shouldly.2.7.0\lib\net40\Shouldly.dll @@ -124,6 +124,7 @@ + \ No newline at end of file diff --git a/src/GitVersionTask.Tests/packages.config b/src/GitVersionTask.Tests/packages.config index ea2a6b4fc9..5be3b26ae3 100644 --- a/src/GitVersionTask.Tests/packages.config +++ b/src/GitVersionTask.Tests/packages.config @@ -7,7 +7,7 @@ - - + + \ No newline at end of file