diff --git a/src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs b/src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs index 803b9a123c..042cb37c1a 100644 --- a/src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs +++ b/src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs @@ -5,6 +5,11 @@ namespace GitVersion.Common; public interface IRepositoryStore { + int UncommittedChangesCount { get; } + IBranch Head { get; } + IBranchCollection Branches { get; } + ITagCollection Tags { get; } + /// /// Find the merge base of the two branches, i.e. the best common ancestor of the two branches' tips. /// @@ -13,12 +18,14 @@ public interface IRepositoryStore ICommit? FindMergeBase(ICommit commit, ICommit mainlineTip); ICommit? GetCurrentCommit(IBranch currentBranch, string? commitId, IIgnoreConfiguration ignore); + ICommit? GetForwardMerge(ICommit? commitToFindCommonBase, ICommit? findMergeBase); IReadOnlyList GetCommitLog(ICommit? baseVersionSource, ICommit currentCommit, IIgnoreConfiguration ignore); + IReadOnlyList GetCommitsReacheableFromHead(ICommit? headCommit, IIgnoreConfiguration ignore); + IReadOnlyList GetCommitsReacheableFrom(IGitObject commit, IBranch branch); IBranch GetTargetBranch(string? targetBranchName); IBranch? FindBranch(ReferenceName branchName); - IBranch? FindBranch(string branchName); IEnumerable ExcludingBranches(IEnumerable branchesToExclude); IEnumerable GetBranchesContainingCommit(ICommit commit, IEnumerable? branches = null, bool onlyTrackedBranches = false); @@ -31,13 +38,9 @@ public interface IRepositoryStore IEnumerable FindCommitBranchesBranchedFrom(IBranch branch, IGitVersionConfiguration configuration, params IBranch[] excludedBranches); - IEnumerable FindCommitBranchesBranchedFrom(IBranch branch, IGitVersionConfiguration configuration, IEnumerable excludedBranches); - IEnumerable GetSourceBranches(IBranch branch, IGitVersionConfiguration configuration, params IBranch[] excludedBranches); IEnumerable GetSourceBranches(IBranch branch, IGitVersionConfiguration configuration, IEnumerable excludedBranches); bool IsCommitOnBranch(ICommit? baseVersionSource, IBranch branch, ICommit firstMatchingCommit); - - int GetNumberOfUncommittedChanges(); } diff --git a/src/GitVersion.Core/Core/BranchRepository.cs b/src/GitVersion.Core/Core/BranchRepository.cs index 731e12fe23..a92236d3e1 100644 --- a/src/GitVersion.Core/Core/BranchRepository.cs +++ b/src/GitVersion.Core/Core/BranchRepository.cs @@ -1,12 +1,13 @@ +using GitVersion.Common; using GitVersion.Configuration; using GitVersion.Extensions; using GitVersion.Git; namespace GitVersion.Core; -internal sealed class BranchRepository(IGitRepository gitRepository) : IBranchRepository +internal sealed class BranchRepository(IRepositoryStore repositoryStore) : IBranchRepository { - private readonly IGitRepository gitRepository = gitRepository.NotNull(); + private readonly IRepositoryStore repositoryStore = repositoryStore.NotNull(); public IEnumerable GetMainBranches(IGitVersionConfiguration configuration, params IBranch[] excludeBranches) => GetBranches(configuration, [.. excludeBranches], branchConfiguration => branchConfiguration.IsMainBranch == true); @@ -19,7 +20,7 @@ private IEnumerable GetBranches( { predicate.NotNull(); - foreach (var branch in this.gitRepository.Branches) + foreach (var branch in this.repositoryStore.Branches) { if (!excludeBranches.Contains(branch)) { diff --git a/src/GitVersion.Core/Core/BranchesContainingCommitFinder.cs b/src/GitVersion.Core/Core/BranchesContainingCommitFinder.cs index bc2934fa2b..973a20060c 100644 --- a/src/GitVersion.Core/Core/BranchesContainingCommitFinder.cs +++ b/src/GitVersion.Core/Core/BranchesContainingCommitFinder.cs @@ -1,18 +1,19 @@ +using GitVersion.Common; using GitVersion.Extensions; using GitVersion.Git; using GitVersion.Logging; namespace GitVersion; -internal class BranchesContainingCommitFinder(IGitRepository repository, ILog log) +internal class BranchesContainingCommitFinder(IRepositoryStore repositoryStore, ILog log) { private readonly ILog log = log.NotNull(); - private readonly IGitRepository repository = repository.NotNull(); + private readonly IRepositoryStore repositoryStore = repositoryStore.NotNull(); public IEnumerable GetBranchesContainingCommit(ICommit commit, IEnumerable? branches = null, bool onlyTrackedBranches = false) { commit.NotNull(); - branches ??= [.. this.repository.Branches]; + branches ??= [.. this.repositoryStore.Branches]; // TODO Should we cache this? // Yielding part is split from the main part of the method to avoid having the exception check performed lazily. @@ -45,7 +46,7 @@ private IEnumerable InnerGetBranchesContainingCommit(IGitObject commit, { log.Info($"Searching for commits reachable from '{branch}'."); - var commits = GetCommitsReacheableFrom(commit, branch); + var commits = this.repositoryStore.GetCommitsReacheableFrom(commit, branch); if (!commits.Any()) { @@ -59,14 +60,6 @@ private IEnumerable InnerGetBranchesContainingCommit(IGitObject commit, } } - private IEnumerable GetCommitsReacheableFrom(IGitObject commit, IBranch branch) - { - var filter = new CommitFilter { IncludeReachableFrom = branch }; - var commitCollection = this.repository.Commits.QueryBy(filter); - - return commitCollection.Where(c => c.Sha == commit.Sha); - } - private static bool IncludeTrackedBranches(IBranch branch, bool includeOnlyTracked) => (includeOnlyTracked && branch.IsTracking) || !includeOnlyTracked; diff --git a/src/GitVersion.Core/Core/GitVersionContextFactory.cs b/src/GitVersion.Core/Core/GitVersionContextFactory.cs index 537c6145b9..a306e5c045 100644 --- a/src/GitVersion.Core/Core/GitVersionContextFactory.cs +++ b/src/GitVersion.Core/Core/GitVersionContextFactory.cs @@ -27,11 +27,7 @@ public GitVersionContext Create(GitVersionOptions gitVersionOptions) ?? throw new InvalidOperationException("Need a branch to operate on"); var currentCommit = this.repositoryStore.GetCurrentCommit( currentBranch, gitVersionOptions.RepositoryInfo.CommitId, configuration.Ignore - ); - - if (currentCommit is null) - throw new GitVersionException("No commits found on the current branch."); - + ) ?? throw new GitVersionException("No commits found on the current branch."); if (currentBranch.IsDetachedHead) { var branchForCommit = this.repositoryStore.GetBranchesContainingCommit( @@ -45,7 +41,7 @@ public GitVersionContext Create(GitVersionOptions gitVersionOptions) format: configuration.SemanticVersionFormat, ignore: configuration.Ignore ).Contains(currentCommit); - var numberOfUncommittedChanges = this.repositoryStore.GetNumberOfUncommittedChanges(); + var numberOfUncommittedChanges = this.repositoryStore.UncommittedChangesCount; return new(currentBranch, currentCommit, configuration, isCurrentCommitTagged, numberOfUncommittedChanges); } diff --git a/src/GitVersion.Core/Core/MainlineBranchFinder.cs b/src/GitVersion.Core/Core/MainlineBranchFinder.cs deleted file mode 100644 index 8f818cf303..0000000000 --- a/src/GitVersion.Core/Core/MainlineBranchFinder.cs +++ /dev/null @@ -1,97 +0,0 @@ -using GitVersion.Common; -using GitVersion.Configuration; -using GitVersion.Core; -using GitVersion.Extensions; -using GitVersion.Git; -using GitVersion.Logging; - -namespace GitVersion; - -internal class MainlineBranchFinder( - IRepositoryStore repositoryStore, - IGitRepository repository, - IGitVersionConfiguration configuration, - ILog log) -{ - private readonly IGitVersionConfiguration configuration = configuration.NotNull(); - private readonly ILog log = log.NotNull(); - private readonly IGitRepository repository = repository.NotNull(); - private readonly IRepositoryStore repositoryStore = repositoryStore.NotNull(); - private readonly List mainlineBranchConfigurations = - configuration.Branches.Select(e => e.Value).Where(b => b.IsMainBranch == true).ToList(); - - public IDictionary> FindMainlineBranches(ICommit commit) - { - var branchOriginFinder = new BranchOriginFinder(commit, this.repositoryStore, this.configuration, this.log); - return this.repository.Branches - .Where(IsMainBranch) - .Select(branchOriginFinder.BranchOrigin) - .Where(bc => bc != BranchCommit.Empty) - .GroupBy(bc => bc.Commit.Sha, bc => bc.Branch) - .ToDictionary(group => group.Key, x => x.ToList()); - } - - private bool IsMainBranch(INamedReference branch) - { - var matcher = new MainlineConfigBranchMatcher(branch, this.log); - return this.mainlineBranchConfigurations.Any(matcher.IsMainBranch); - } - - private class MainlineConfigBranchMatcher(INamedReference branch, ILog log) - { - private readonly INamedReference branch = branch.NotNull(); - private readonly ILog log = log.NotNull(); - - public bool IsMainBranch(IBranchConfiguration value) - { - if (value.RegularExpression == null) - return false; - - var regex = RegexPatterns.Cache.GetOrAdd(value.RegularExpression); - var branchName = this.branch.Name.WithoutOrigin; - var match = regex.IsMatch(branchName); - this.log.Info($"'{value.RegularExpression}' {(match ? "matches" : "does not match")} '{branchName}'."); - return match; - } - } - - private class BranchOriginFinder(ICommit commit, IRepositoryStore repositoryStore, IGitVersionConfiguration configuration, ILog log) - { - private readonly ICommit commit = commit.NotNull(); - private readonly IGitVersionConfiguration configuration = configuration.NotNull(); - private readonly ILog log = log.NotNull(); - private readonly IRepositoryStore repositoryStore = repositoryStore.NotNull(); - - public BranchCommit BranchOrigin(IBranch branch) - { - var branchOrigin = FindBranchOrigin(branch); - return branchOrigin == null - ? BranchCommit.Empty - : new(branchOrigin, branch); - } - - private ICommit? FindBranchOrigin(IBranch branch) - { - if (branch.Tip == null) - return null; - - var branchName = branch.Name.Friendly; - var mergeBase = this.repositoryStore.FindMergeBase(branch.Tip, this.commit); - if (mergeBase is not null) - { - this.log.Info($"Found merge base {mergeBase.Sha} for '{branchName}'."); - return mergeBase; - } - - var branchCommit = this.repositoryStore.FindCommitBranchBranchedFrom(branch, this.configuration); - if (branchCommit != BranchCommit.Empty) - { - this.log.Info($"Found parent commit {branchCommit.Commit.Sha} for '{branchName}'."); - return branchCommit.Commit; - } - - this.log.Info($"Found no merge base or parent commit for '{branchName}'."); - return null; - } - } -} diff --git a/src/GitVersion.Core/Core/MergeBaseFinder.cs b/src/GitVersion.Core/Core/MergeBaseFinder.cs index 28ad16fc9a..f4ec183efe 100644 --- a/src/GitVersion.Core/Core/MergeBaseFinder.cs +++ b/src/GitVersion.Core/Core/MergeBaseFinder.cs @@ -5,10 +5,9 @@ namespace GitVersion; -internal class MergeBaseFinder(IRepositoryStore repositoryStore, IGitRepository gitRepository, ILog log) +internal class MergeBaseFinder(IRepositoryStore repositoryStore, ILog log) { private readonly ILog log = log.NotNull(); - private readonly IGitRepository repository = gitRepository.NotNull(); private readonly IRepositoryStore repositoryStore = repositoryStore.NotNull(); private readonly Dictionary, ICommit> mergeBaseCache = []; @@ -71,7 +70,7 @@ internal class MergeBaseFinder(IRepositoryStore repositoryStore, IGitRepository do { // Now make sure that the merge base is not a forward merge - forwardMerge = GetForwardMerge(commitToFindCommonBase, findMergeBase); + forwardMerge = this.repositoryStore.GetForwardMerge(commitToFindCommonBase, findMergeBase); if (forwardMerge == null) continue; @@ -102,16 +101,4 @@ internal class MergeBaseFinder(IRepositoryStore repositoryStore, IGitRepository return findMergeBase; } - - private ICommit? GetForwardMerge(ICommit? commitToFindCommonBase, ICommit? findMergeBase) - { - var filter = new CommitFilter - { - IncludeReachableFrom = commitToFindCommonBase, - ExcludeReachableFrom = findMergeBase - }; - var commitCollection = this.repository.Commits.QueryBy(filter); - - return commitCollection.FirstOrDefault(c => c.Parents.Contains(findMergeBase)); - } } diff --git a/src/GitVersion.Core/Core/MergeCommitFinder.cs b/src/GitVersion.Core/Core/MergeCommitFinder.cs index 1a5a42e3c8..c38da050af 100644 --- a/src/GitVersion.Core/Core/MergeCommitFinder.cs +++ b/src/GitVersion.Core/Core/MergeCommitFinder.cs @@ -1,3 +1,4 @@ +using GitVersion.Common; using GitVersion.Configuration; using GitVersion.Extensions; using GitVersion.Git; @@ -5,11 +6,11 @@ namespace GitVersion; -internal class MergeCommitFinder(RepositoryStore repositoryStore, IGitVersionConfiguration configuration, IEnumerable excludedBranches, ILog log) +internal class MergeCommitFinder(IRepositoryStore repositoryStore, IGitVersionConfiguration configuration, IEnumerable excludedBranches, ILog log) { private readonly ILog log = log.NotNull(); private readonly IEnumerable branches = repositoryStore.ExcludingBranches(excludedBranches.NotNull()); - private readonly RepositoryStore repositoryStore = repositoryStore.NotNull(); + private readonly IRepositoryStore repositoryStore = repositoryStore.NotNull(); private readonly IGitVersionConfiguration configuration = configuration.NotNull(); private readonly Dictionary> mergeBaseCommitsCache = []; diff --git a/src/GitVersion.Core/Core/RepositoryStore.cs b/src/GitVersion.Core/Core/RepositoryStore.cs index 6aa023bdfa..d0fe0d9151 100644 --- a/src/GitVersion.Core/Core/RepositoryStore.cs +++ b/src/GitVersion.Core/Core/RepositoryStore.cs @@ -7,25 +7,27 @@ namespace GitVersion; -internal class RepositoryStore : IRepositoryStore +internal class RepositoryStore(ILog log, IGitRepository repository) : IRepositoryStore { - private readonly ILog log; - private readonly IGitRepository repository; + private readonly ILog log = log.NotNull(); + private readonly IGitRepository repository = repository.NotNull(); - private readonly MergeBaseFinder mergeBaseFinder; + public int UncommittedChangesCount => this.repository.UncommittedChangesCount(); - public RepositoryStore(ILog log, IGitRepository repository) - { - this.log = log.NotNull(); - this.repository = repository.NotNull(); - this.mergeBaseFinder = new(this, repository, log); - } + public IBranch Head => this.repository.Head; + + public IBranchCollection Branches => this.repository.Branches; + + public ITagCollection Tags => this.repository.Tags; /// /// Find the merge base of the two branches, i.e. the best common ancestor of the two branches' tips. /// public ICommit? FindMergeBase(IBranch? branch, IBranch? otherBranch) - => this.mergeBaseFinder.FindMergeBaseOf(branch, otherBranch); + { + var mergeBaseFinder = new MergeBaseFinder(this, log); + return mergeBaseFinder.FindMergeBaseOf(branch, otherBranch); + } public ICommit? GetCurrentCommit(IBranch currentBranch, string? commitId, IIgnoreConfiguration ignore) { @@ -90,15 +92,13 @@ public IBranch GetTargetBranch(string? targetBranchName) public IBranch? FindBranch(ReferenceName branchName) => this.repository.Branches.FirstOrDefault(x => x.Name.Equals(branchName)); - public IBranch? FindBranch(string branchName) => this.repository.Branches.FirstOrDefault(x => x.Name.EquivalentTo(branchName)); - public IEnumerable ExcludingBranches(IEnumerable branchesToExclude) => this.repository.Branches.ExcludeBranches(branchesToExclude); public IEnumerable GetBranchesContainingCommit(ICommit commit, IEnumerable? branches = null, bool onlyTrackedBranches = false) { commit.NotNull(); - var branchesContainingCommitFinder = new BranchesContainingCommitFinder(this.repository, this.log); + var branchesContainingCommitFinder = new BranchesContainingCommitFinder(this, this.log); return branchesContainingCommitFinder.GetBranchesContainingCommit(commit, branches, onlyTrackedBranches); } @@ -207,21 +207,6 @@ public IEnumerable FindCommitBranchesBranchedFrom( IBranch branch, IGitVersionConfiguration configuration, params IBranch[] excludedBranches) => FindCommitBranchesBranchedFrom(branch, configuration, (IEnumerable)excludedBranches); - public IEnumerable FindCommitBranchesBranchedFrom( - IBranch branch, IGitVersionConfiguration configuration, IEnumerable excludedBranches) - { - using (this.log.IndentLog($"Finding branches source of '{branch}'")) - { - if (branch.Tip == null) - { - this.log.Warning($"{branch} has no tip."); - return []; - } - - return new MergeCommitFinder(this, configuration, excludedBranches, this.log).FindMergeCommitsFor(branch).ToList(); - } - } - public IReadOnlyList GetCommitLog(ICommit? baseVersionSource, ICommit currentCommit, IIgnoreConfiguration ignore) { currentCommit.NotNull(); @@ -239,6 +224,38 @@ public IReadOnlyList GetCommitLog(ICommit? baseVersionSource, ICommit c return ignore.Filter(commits).ToList(); } + public IReadOnlyList GetCommitsReacheableFromHead(ICommit? headCommit, IIgnoreConfiguration ignore) + { + var filter = new CommitFilter + { + IncludeReachableFrom = headCommit, + SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Reverse + }; + + var commits = this.repository.Commits.QueryBy(filter); + return ignore.Filter(commits).ToList(); + } + + public IReadOnlyList GetCommitsReacheableFrom(IGitObject commit, IBranch branch) + { + var filter = new CommitFilter { IncludeReachableFrom = branch }; + var commitCollection = this.repository.Commits.QueryBy(filter); + + return commitCollection.Where(c => c.Sha == commit.Sha).ToList(); + } + + public ICommit? GetForwardMerge(ICommit? commitToFindCommonBase, ICommit? findMergeBase) + { + var filter = new CommitFilter + { + IncludeReachableFrom = commitToFindCommonBase, + ExcludeReachableFrom = findMergeBase + }; + var commitCollection = this.repository.Commits.QueryBy(filter); + + return commitCollection.FirstOrDefault(c => c.Parents.Contains(findMergeBase)); + } + public bool IsCommitOnBranch(ICommit? baseVersionSource, IBranch branch, ICommit firstMatchingCommit) { var filter = new CommitFilter { IncludeReachableFrom = branch, ExcludeReachableFrom = baseVersionSource, FirstParentOnly = true }; @@ -248,5 +265,20 @@ public bool IsCommitOnBranch(ICommit? baseVersionSource, IBranch branch, ICommit public ICommit? FindMergeBase(ICommit commit, ICommit mainlineTip) => this.repository.FindMergeBase(commit, mainlineTip); - public int GetNumberOfUncommittedChanges() => this.repository.GetNumberOfUncommittedChanges(); + private IBranch? FindBranch(string branchName) => this.repository.Branches.FirstOrDefault(x => x.Name.EquivalentTo(branchName)); + + private IEnumerable FindCommitBranchesBranchedFrom( + IBranch branch, IGitVersionConfiguration configuration, IEnumerable excludedBranches) + { + using (this.log.IndentLog($"Finding branches source of '{branch}'")) + { + if (branch.Tip == null) + { + this.log.Warning($"{branch} has no tip."); + return []; + } + + return new MergeCommitFinder(this, configuration, excludedBranches, this.log).FindMergeCommitsFor(branch).ToList(); + } + } } diff --git a/src/GitVersion.Core/Core/TaggedSemanticVersionRepository.cs b/src/GitVersion.Core/Core/TaggedSemanticVersionRepository.cs index 78ec16c8ce..24649b9687 100644 --- a/src/GitVersion.Core/Core/TaggedSemanticVersionRepository.cs +++ b/src/GitVersion.Core/Core/TaggedSemanticVersionRepository.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using GitVersion.Common; using GitVersion.Configuration; using GitVersion.Extensions; using GitVersion.Git; @@ -6,7 +7,7 @@ namespace GitVersion.Core; -internal sealed class TaggedSemanticVersionRepository(ILog log, IGitRepository gitRepository) : ITaggedSemanticVersionRepository +internal sealed class TaggedSemanticVersionRepository(ILog log, IRepositoryStore repositoryStore) : ITaggedSemanticVersionRepository { private readonly ConcurrentDictionary<(IBranch, string, SemanticVersionFormat), IReadOnlyList> taggedSemanticVersionsOfBranchCache = new(); @@ -16,7 +17,7 @@ internal sealed class TaggedSemanticVersionRepository(ILog log, IGitRepository g taggedSemanticVersionsCache = new(); private readonly ILog log = log.NotNull(); - private readonly IGitRepository gitRepository = gitRepository.NotNull(); + private readonly IRepositoryStore repositoryStore = repositoryStore.NotNull(); public ILookup GetTaggedSemanticVersionsOfBranch( IBranch branch, string? tagPrefix, SemanticVersionFormat format, IIgnoreConfiguration ignore) @@ -28,7 +29,7 @@ public ILookup GetTaggedSemanticVersionsOfBranc var result = taggedSemanticVersionsOfBranchCache.GetOrAdd(new(branch, tagPrefix, format), _ => { isCached = false; - return GetElements().Distinct().OrderByDescending(element => element.Tag.Commit.When).ToList(); + return [.. GetElements().Distinct().OrderByDescending(element => element.Tag.Commit.When)]; }); if (isCached) @@ -123,7 +124,7 @@ IEnumerable GetElements() { this.log.Info($"Getting tagged semantic versions. TagPrefix: {tagPrefix} and Format: {format}"); - foreach (var tag in ignore.Filter(this.gitRepository.Tags)) + foreach (var tag in ignore.Filter(this.repositoryStore.Tags)) { if (SemanticVersion.TryParse(tag.Name.Friendly, tagPrefix, out var semanticVersion, format)) { diff --git a/src/GitVersion.Core/Core/TaggedSemanticVersionService.cs b/src/GitVersion.Core/Core/TaggedSemanticVersionService.cs index 86a99c8849..19efb54071 100644 --- a/src/GitVersion.Core/Core/TaggedSemanticVersionService.cs +++ b/src/GitVersion.Core/Core/TaggedSemanticVersionService.cs @@ -5,12 +5,12 @@ namespace GitVersion.Core; internal sealed class TaggedSemanticVersionService( - ITaggedSemanticVersionRepository Repository, IBranchRepository BranchRepository) + ITaggedSemanticVersionRepository repository, IBranchRepository branchRepository) : ITaggedSemanticVersionService { - private ITaggedSemanticVersionRepository Repository { get; } = Repository.NotNull(); + private readonly ITaggedSemanticVersionRepository repository = repository.NotNull(); - private IBranchRepository BranchRepository { get; } = BranchRepository.NotNull(); + private readonly IBranchRepository branchRepository = branchRepository.NotNull(); public ILookup GetTaggedSemanticVersions( IBranch branch, @@ -99,7 +99,7 @@ private IEnumerable> GetTaggedSema string? label, DateTimeOffset? notOlderThan) { - var semanticVersionsOfBranch = Repository.GetTaggedSemanticVersionsOfBranch( + var semanticVersionsOfBranch = this.repository.GetTaggedSemanticVersionsOfBranch( branch: branch, tagPrefix: tagPrefix, format: format, ignore: ignore ); foreach (var grouping in semanticVersionsOfBranch) @@ -145,7 +145,7 @@ private IEnumerable> GetTaggedSema string? label, DateTimeOffset? notOlderThan) { - var semanticVersionsOfMergeTarget = Repository.GetTaggedSemanticVersionsOfMergeTarget( + var semanticVersionsOfMergeTarget = this.repository.GetTaggedSemanticVersionsOfMergeTarget( branch: branch, tagPrefix: tagPrefix, format: format, @@ -188,7 +188,7 @@ private IEnumerable> GetTaggedSema string? label, params IBranch[] excludeBranches) { - foreach (var releaseBranch in BranchRepository.GetMainBranches(configuration, excludeBranches)) + foreach (var releaseBranch in this.branchRepository.GetMainBranches(configuration, excludeBranches)) { var taggedSemanticVersions = GetTaggedSemanticVersionsOfBranchInternal( branch: releaseBranch, @@ -228,7 +228,7 @@ private IEnumerable> GetTaggedSema string? label, params IBranch[] excludeBranches) { - foreach (var releaseBranch in BranchRepository.GetReleaseBranches(configuration, excludeBranches)) + foreach (var releaseBranch in this.branchRepository.GetReleaseBranches(configuration, excludeBranches)) { var taggedSemanticVersions = GetTaggedSemanticVersionsOfBranchInternal( branch: releaseBranch, diff --git a/src/GitVersion.Core/Git/IGitRepository.cs b/src/GitVersion.Core/Git/IGitRepository.cs index 9f25193b0d..bfad989068 100644 --- a/src/GitVersion.Core/Git/IGitRepository.cs +++ b/src/GitVersion.Core/Git/IGitRepository.cs @@ -6,7 +6,9 @@ public interface IGitRepository : IDisposable string WorkingDirectory { get; } bool IsHeadDetached { get; } bool IsShallow { get; } + IBranch Head { get; } + ITagCollection Tags { get; } IReferenceCollection Refs { get; } IBranchCollection Branches { get; } @@ -14,6 +16,6 @@ public interface IGitRepository : IDisposable IRemoteCollection Remotes { get; } ICommit? FindMergeBase(ICommit commit, ICommit otherCommit); - int GetNumberOfUncommittedChanges(); + int UncommittedChangesCount(); void DiscoverRepository(string? gitDirectory); } diff --git a/src/GitVersion.Core/PublicAPI.Shipped.txt b/src/GitVersion.Core/PublicAPI.Shipped.txt index 143462941c..fc22f7ec1c 100644 --- a/src/GitVersion.Core/PublicAPI.Shipped.txt +++ b/src/GitVersion.Core/PublicAPI.Shipped.txt @@ -22,16 +22,13 @@ GitVersion.BugException.BugException(string? message, System.Exception? innerExc GitVersion.Common.IRepositoryStore GitVersion.Common.IRepositoryStore.ExcludingBranches(System.Collections.Generic.IEnumerable! branchesToExclude) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.FindBranch(GitVersion.Git.ReferenceName! branchName) -> GitVersion.Git.IBranch? -GitVersion.Common.IRepositoryStore.FindBranch(string! branchName) -> GitVersion.Git.IBranch? GitVersion.Common.IRepositoryStore.FindCommitBranchBranchedFrom(GitVersion.Git.IBranch? branch, GitVersion.Configuration.IGitVersionConfiguration! configuration, params GitVersion.Git.IBranch![]! excludedBranches) -> GitVersion.Git.BranchCommit GitVersion.Common.IRepositoryStore.FindCommitBranchesBranchedFrom(GitVersion.Git.IBranch! branch, GitVersion.Configuration.IGitVersionConfiguration! configuration, params GitVersion.Git.IBranch![]! excludedBranches) -> System.Collections.Generic.IEnumerable! -GitVersion.Common.IRepositoryStore.FindCommitBranchesBranchedFrom(GitVersion.Git.IBranch! branch, GitVersion.Configuration.IGitVersionConfiguration! configuration, System.Collections.Generic.IEnumerable! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.FindMergeBase(GitVersion.Git.IBranch? branch, GitVersion.Git.IBranch? otherBranch) -> GitVersion.Git.ICommit? GitVersion.Common.IRepositoryStore.FindMergeBase(GitVersion.Git.ICommit! commit, GitVersion.Git.ICommit! mainlineTip) -> GitVersion.Git.ICommit? GitVersion.Common.IRepositoryStore.GetBranchesContainingCommit(GitVersion.Git.ICommit! commit, System.Collections.Generic.IEnumerable? branches = null, bool onlyTrackedBranches = false) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.GetCommitLog(GitVersion.Git.ICommit? baseVersionSource, GitVersion.Git.ICommit! currentCommit, GitVersion.Configuration.IIgnoreConfiguration! ignore) -> System.Collections.Generic.IReadOnlyList! GitVersion.Common.IRepositoryStore.GetCurrentCommit(GitVersion.Git.IBranch! currentBranch, string? commitId, GitVersion.Configuration.IIgnoreConfiguration! ignore) -> GitVersion.Git.ICommit? -GitVersion.Common.IRepositoryStore.GetNumberOfUncommittedChanges() -> int GitVersion.Common.IRepositoryStore.GetSourceBranches(GitVersion.Git.IBranch! branch, GitVersion.Configuration.IGitVersionConfiguration! configuration, params GitVersion.Git.IBranch![]! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.GetSourceBranches(GitVersion.Git.IBranch! branch, GitVersion.Configuration.IGitVersionConfiguration! configuration, System.Collections.Generic.IEnumerable! excludedBranches) -> System.Collections.Generic.IEnumerable! GitVersion.Common.IRepositoryStore.GetTargetBranch(string? targetBranchName) -> GitVersion.Git.IBranch! @@ -219,7 +216,6 @@ GitVersion.Git.IGitRepository.Branches.get -> GitVersion.Git.IBranchCollection! GitVersion.Git.IGitRepository.Commits.get -> GitVersion.Git.ICommitCollection! GitVersion.Git.IGitRepository.DiscoverRepository(string? gitDirectory) -> void GitVersion.Git.IGitRepository.FindMergeBase(GitVersion.Git.ICommit! commit, GitVersion.Git.ICommit! otherCommit) -> GitVersion.Git.ICommit? -GitVersion.Git.IGitRepository.GetNumberOfUncommittedChanges() -> int GitVersion.Git.IGitRepository.Head.get -> GitVersion.Git.IBranch! GitVersion.Git.IGitRepository.IsHeadDetached.get -> bool GitVersion.Git.IGitRepository.IsShallow.get -> bool diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt index 439fac159f..0d2367b54f 100644 --- a/src/GitVersion.Core/PublicAPI.Unshipped.txt +++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt @@ -1,6 +1,14 @@ #nullable enable +GitVersion.Common.IRepositoryStore.Branches.get -> GitVersion.Git.IBranchCollection! +GitVersion.Common.IRepositoryStore.GetCommitsReacheableFrom(GitVersion.Git.IGitObject! commit, GitVersion.Git.IBranch! branch) -> System.Collections.Generic.IReadOnlyList! +GitVersion.Common.IRepositoryStore.GetCommitsReacheableFromHead(GitVersion.Git.ICommit? headCommit, GitVersion.Configuration.IIgnoreConfiguration! ignore) -> System.Collections.Generic.IReadOnlyList! +GitVersion.Common.IRepositoryStore.GetForwardMerge(GitVersion.Git.ICommit? commitToFindCommonBase, GitVersion.Git.ICommit? findMergeBase) -> GitVersion.Git.ICommit? +GitVersion.Common.IRepositoryStore.Head.get -> GitVersion.Git.IBranch! +GitVersion.Common.IRepositoryStore.Tags.get -> GitVersion.Git.ITagCollection! +GitVersion.Common.IRepositoryStore.UncommittedChangesCount.get -> int GitVersion.Configuration.EffectiveConfiguration.VersionInBranchPattern.get -> string? GitVersion.Configuration.IGitVersionConfiguration.TagPrefixPattern.get -> string? +GitVersion.Git.IGitRepository.UncommittedChangesCount() -> int static GitVersion.Configuration.ReferenceNameExtensions.TryGetSemanticVersion(this GitVersion.Git.ReferenceName! source, out (GitVersion.SemanticVersion! Value, string? Name) result, GitVersion.Configuration.IGitVersionConfiguration! configuration) -> bool static GitVersion.Extensions.DictionaryExtensions.GetOrAdd(this System.Collections.Concurrent.ConcurrentDictionary! dict, string! pattern) -> System.Text.RegularExpressions.Regex! static GitVersion.Extensions.DictionaryExtensions.GetOrAdd(this System.Collections.Generic.Dictionary! dict, TKey key, System.Func! getValue) -> TValue diff --git a/src/GitVersion.Core/VersionCalculation/Caching/GitVersionCacheKeyFactory.cs b/src/GitVersion.Core/VersionCalculation/Caching/GitVersionCacheKeyFactory.cs index 429071f0bd..f2cd6919a1 100644 --- a/src/GitVersion.Core/VersionCalculation/Caching/GitVersionCacheKeyFactory.cs +++ b/src/GitVersion.Core/VersionCalculation/Caching/GitVersionCacheKeyFactory.cs @@ -1,4 +1,5 @@ using System.Security.Cryptography; +using GitVersion.Common; using GitVersion.Configuration; using GitVersion.Extensions; using GitVersion.Git; @@ -14,7 +15,7 @@ internal class GitVersionCacheKeyFactory( IOptions options, IConfigurationFileLocator configFileLocator, IConfigurationSerializer configurationSerializer, - IGitRepository gitRepository, + IRepositoryStore repositoryStore, IGitRepositoryInfo repositoryInfo) : IGitVersionCacheKeyFactory { @@ -23,7 +24,7 @@ internal class GitVersionCacheKeyFactory( private readonly IOptions options = options.NotNull(); private readonly IConfigurationFileLocator configFileLocator = configFileLocator.NotNull(); private readonly IConfigurationSerializer configurationSerializer = configurationSerializer.NotNull(); - private readonly IGitRepository gitRepository = gitRepository.NotNull(); + private readonly IRepositoryStore repositoryStore = repositoryStore.NotNull(); private readonly IGitRepositoryInfo repositoryInfo = repositoryInfo.NotNull(); public GitVersionCacheKey Create(IReadOnlyDictionary? overrideConfiguration) @@ -44,7 +45,7 @@ private string GetGitSystemHash() // traverse the directory and get a list of files, use that for GetHash var contents = CalculateDirectoryContents(PathHelper.Combine(dotGitDirectory, "refs")); - return GetHash(contents.ToArray()); + return GetHash([.. contents]); } // based on https://msdn.microsoft.com/en-us/library/bb513869.aspx @@ -139,7 +140,7 @@ private List CalculateDirectoryContents(string root) private string GetRepositorySnapshotHash() { - var head = this.gitRepository.Head; + var head = this.repositoryStore.Head; if (head.Tip == null) { return head.Name.Canonical; diff --git a/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs b/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs index 26ebccda50..41f75a8b34 100644 --- a/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs +++ b/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs @@ -1,4 +1,5 @@ using System.Text.RegularExpressions; +using GitVersion.Common; using GitVersion.Configuration; using GitVersion.Core; using GitVersion.Extensions; @@ -6,14 +7,14 @@ namespace GitVersion.VersionCalculation; -internal class IncrementStrategyFinder(IGitRepository repository, ITaggedSemanticVersionRepository taggedSemanticVersionRepository) +internal class IncrementStrategyFinder(IRepositoryStore repositoryStore, ITaggedSemanticVersionRepository taggedSemanticVersionRepository) : IIncrementStrategyFinder { private readonly Dictionary commitIncrementCache = []; private readonly Dictionary> headCommitsMapCache = []; private readonly Dictionary headCommitsCache = []; - private readonly IGitRepository repository = repository.NotNull(); + private readonly IRepositoryStore repositoryStore = repositoryStore.NotNull(); private readonly ITaggedSemanticVersionRepository taggedSemanticVersionRepository = taggedSemanticVersionRepository.NotNull(); public VersionField DetermineIncrementedField( @@ -166,7 +167,7 @@ private Dictionary GetHeadCommitsMap(ICommit? headCommit, IIgnoreCo /// private ICommit[] GetHeadCommits(ICommit? headCommit, IIgnoreConfiguration ignore) => this.headCommitsCache.GetOrAdd(headCommit?.Sha ?? "NULL", () => - GetCommitsReacheableFromHead(headCommit, ignore).ToArray()); + [.. this.repositoryStore.GetCommitsReacheableFromHead(headCommit, ignore)]); private VersionField? GetIncrementFromCommit(ICommit commit, Regex majorRegex, Regex minorRegex, Regex patchRegex, Regex noBumpRegex) => this.commitIncrementCache.GetOrAdd(commit.Sha, () => @@ -181,18 +182,6 @@ private ICommit[] GetHeadCommits(ICommit? headCommit, IIgnoreConfiguration ignor return null; } - private IEnumerable GetCommitsReacheableFromHead(ICommit? headCommit, IIgnoreConfiguration ignore) - { - var filter = new CommitFilter - { - IncludeReachableFrom = headCommit, - SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Reverse - }; - - var commits = repository.Commits.QueryBy(filter); - return ignore.Filter(commits); - } - public IEnumerable GetMergedCommits(ICommit mergeCommit, int index, IIgnoreConfiguration ignore) { mergeCommit.NotNull(); @@ -202,11 +191,11 @@ public IEnumerable GetMergedCommits(ICommit mergeCommit, int index, IIg throw new ArgumentException("The parameter is not a merge commit.", nameof(mergeCommit)); } - ICommit baseCommit = mergeCommit.Parents.First(); + ICommit baseCommit = mergeCommit.Parents[0]; ICommit mergedCommit = GetMergedHead(mergeCommit); if (index == 0) (mergedCommit, baseCommit) = (baseCommit, mergedCommit); - ICommit findMergeBase = this.repository.FindMergeBase(baseCommit, mergedCommit) + ICommit findMergeBase = this.repositoryStore.FindMergeBase(baseCommit, mergedCommit) ?? throw new InvalidOperationException("Cannot find the base commit of merged branch."); return GetIntermediateCommits(findMergeBase, mergedCommit, ignore); diff --git a/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs b/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs index b543161bd8..447ca4fbe8 100644 --- a/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs +++ b/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs @@ -29,19 +29,20 @@ public IEnumerable ExcludeBranches(IEnumerable branchesToExclu { branchesToExclude = branchesToExclude.NotNull(); + return this.Where(BranchIsNotExcluded); + bool BranchIsNotExcluded(IBranch branch) => branchesToExclude.All(branchToExclude => !branch.Equals(branchToExclude)); - - return this.Where(BranchIsNotExcluded); } public void UpdateTrackedBranch(IBranch branch, string remoteTrackingReferenceName) { var branchToUpdate = (Branch)branch.NotNull(); + this.innerCollection.Update(branchToUpdate, Updater); + return; + void Updater(BranchUpdater branchUpdater) => branchUpdater.TrackedBranch = remoteTrackingReferenceName; - - this.innerCollection.Update(branchToUpdate, Updater); } } diff --git a/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs b/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs index 08ebb91393..e6dcee288c 100644 --- a/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs +++ b/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs @@ -19,6 +19,12 @@ public IEnumerable GetCommitsPriorTo(DateTimeOffset olderThan) public IEnumerable QueryBy(CommitFilter commitFilter) { + var includeReachableFrom = GetReacheableFrom(commitFilter.IncludeReachableFrom); + var excludeReachableFrom = GetReacheableFrom(commitFilter.ExcludeReachableFrom); + var filter = new LibGit2Sharp.CommitFilter { IncludeReachableFrom = includeReachableFrom, ExcludeReachableFrom = excludeReachableFrom, FirstParentOnly = commitFilter.FirstParentOnly, SortBy = (LibGit2Sharp.CommitSortStrategies)commitFilter.SortBy }; + var commitLog = ((IQueryableCommitLog)this.innerCollection).QueryBy(filter); + return new CommitCollection(commitLog); + static object? GetReacheableFrom(object? item) => item switch { @@ -26,11 +32,5 @@ public IEnumerable QueryBy(CommitFilter commitFilter) Branch b => (LibGit2Sharp.Branch)b, _ => null }; - - var includeReachableFrom = GetReacheableFrom(commitFilter.IncludeReachableFrom); - var excludeReachableFrom = GetReacheableFrom(commitFilter.ExcludeReachableFrom); - var filter = new LibGit2Sharp.CommitFilter { IncludeReachableFrom = includeReachableFrom, ExcludeReachableFrom = excludeReachableFrom, FirstParentOnly = commitFilter.FirstParentOnly, SortBy = (LibGit2Sharp.CommitSortStrategies)commitFilter.SortBy }; - var commitLog = ((IQueryableCommitLog)this.innerCollection).QueryBy(filter); - return new CommitCollection(commitLog); } } diff --git a/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs b/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs index 683a6571ee..aea0217adc 100644 --- a/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs +++ b/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs @@ -22,6 +22,7 @@ private IRepository RepositoryInstance public bool IsHeadDetached => RepositoryInstance.Info.IsHeadDetached; public bool IsShallow => RepositoryInstance.Info.IsShallow; public IBranch Head => new Branch(RepositoryInstance.Head); + public ITagCollection Tags => new TagCollection(RepositoryInstance.Tags); public IReferenceCollection Refs => new ReferenceCollection(RepositoryInstance.Refs); public IBranchCollection Branches => new BranchCollection(RepositoryInstance.Branches); @@ -52,10 +53,10 @@ public void DiscoverRepository(string? gitDirectory) }); } - public int GetNumberOfUncommittedChanges() + public int UncommittedChangesCount() { var retryAction = new RetryAction(); - return retryAction.Execute(GetNumberOfUncommittedChangesInternal); + return retryAction.Execute(GetUncommittedChangesCountInternal); } public void Dispose() @@ -63,7 +64,7 @@ public void Dispose() if (this.repositoryLazy is { IsValueCreated: true }) RepositoryInstance.Dispose(); } - private int GetNumberOfUncommittedChangesInternal() + private int GetUncommittedChangesCountInternal() { // check if we have a branch tip at all to behave properly with empty repos // => return that we have actually un-committed changes because we are apparently diff --git a/src/GitVersion.LibGit2Sharp/Git/GitRepository.extended.cs b/src/GitVersion.LibGit2Sharp/Git/GitRepository.mutating.cs similarity index 100% rename from src/GitVersion.LibGit2Sharp/Git/GitRepository.extended.cs rename to src/GitVersion.LibGit2Sharp/Git/GitRepository.mutating.cs