Skip to content

Commit f7bcc26

Browse files
committed
Refactor RepositoryStore.GetMainlineBranches
Refactor `RepositoryStore.GetMainlineBranches into the `MainlineBranchFinder` class to improve readability, provide better stack traces if an exception occurs and provide better protection against `null`.
1 parent 27e2f67 commit f7bcc26

File tree

4 files changed

+129
-53
lines changed

4 files changed

+129
-53
lines changed

src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public interface IRepositoryStore
2424
IEnumerable<IBranch> GetReleaseBranches(IEnumerable<KeyValuePair<string, BranchConfig>> releaseBranchConfig);
2525
IEnumerable<IBranch> ExcludingBranches(IEnumerable<IBranch> branchesToExclude);
2626
IEnumerable<IBranch> GetBranchesContainingCommit(ICommit? commit, IEnumerable<IBranch>? branches = null, bool onlyTrackedBranches = false);
27-
Dictionary<string, List<IBranch>> GetMainlineBranches(ICommit commit, Config configuration, IEnumerable<KeyValuePair<string, BranchConfig>>? mainlineBranchConfigs);
27+
IDictionary<string, List<IBranch>> GetMainlineBranches(ICommit commit, Config configuration, IEnumerable<KeyValuePair<string, BranchConfig>>? mainlineBranchConfigs);
2828

2929
/// <summary>
3030
/// Find the commit where the given branch was branched from another branch.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using System.Text.RegularExpressions;
2+
using GitVersion.Common;
3+
using GitVersion.Extensions;
4+
using GitVersion.Logging;
5+
using GitVersion.Model.Configuration;
6+
7+
namespace GitVersion;
8+
9+
internal class MainlineBranchFinder
10+
{
11+
private readonly Config configuration;
12+
private readonly ILog log;
13+
private readonly IEnumerable<KeyValuePair<string, BranchConfig>>? mainlineBranchConfigs;
14+
private readonly IGitRepository repository;
15+
private readonly RepositoryStore repositoryStore;
16+
17+
18+
public MainlineBranchFinder(RepositoryStore repositoryStore,
19+
IGitRepository repository,
20+
Config configuration,
21+
IEnumerable<KeyValuePair<string, BranchConfig>>? mainlineBranchConfigs,
22+
ILog log)
23+
{
24+
this.repositoryStore = repositoryStore.NotNull();
25+
this.repository = repository.NotNull();
26+
this.configuration = configuration.NotNull();
27+
this.mainlineBranchConfigs = mainlineBranchConfigs;
28+
this.log = log.NotNull();
29+
}
30+
31+
32+
public IDictionary<string, List<IBranch>> FindMainlineBranches(ICommit commit)
33+
{
34+
var branchOriginFinder = new BranchOriginFinder(commit, this.repositoryStore, this.configuration, this.log);
35+
return this.repository.Branches
36+
.Where(BranchIsMainline)
37+
.Select(branchOriginFinder.BranchOrigin)
38+
.Where(bc => bc != BranchCommit.Empty)
39+
.GroupBy(bc => bc.Commit.Sha, bc => bc.Branch)
40+
.ToDictionary(group => group.Key, x => x.ToList());
41+
}
42+
43+
44+
private bool BranchIsMainline(INamedReference branch)
45+
{
46+
var matcher = new MainlineConfigBranchMatcher(branch, this.log);
47+
return this.mainlineBranchConfigs?.Any(matcher.IsMainline) == true;
48+
}
49+
50+
private class MainlineConfigBranchMatcher
51+
{
52+
private readonly INamedReference branch;
53+
private readonly ILog log;
54+
55+
public MainlineConfigBranchMatcher(INamedReference branch, ILog log)
56+
{
57+
this.branch = branch;
58+
this.log = log;
59+
}
60+
61+
public bool IsMainline(KeyValuePair<string, BranchConfig> mainlineBranchConfig)
62+
{
63+
var (_, value) = mainlineBranchConfig;
64+
if (value?.Regex == null)
65+
return false;
66+
67+
var mainlineRegex = value.Regex;
68+
var branchName = this.branch.Name.WithoutRemote;
69+
var match = Regex.IsMatch(branchName, mainlineRegex);
70+
this.log.Info($"'{mainlineRegex}' {(match ? "matches" : "does not match")} '{branchName}'.");
71+
return match;
72+
}
73+
}
74+
75+
76+
private class BranchOriginFinder
77+
{
78+
private readonly ICommit commit;
79+
private readonly Config configuration;
80+
private readonly ILog log;
81+
private readonly IRepositoryStore repositoryStore;
82+
83+
public BranchOriginFinder(ICommit commit, IRepositoryStore repositoryStore, Config configuration, ILog log)
84+
{
85+
this.repositoryStore = repositoryStore;
86+
this.commit = commit;
87+
this.configuration = configuration;
88+
this.log = log;
89+
}
90+
91+
public BranchCommit BranchOrigin(IBranch branch)
92+
{
93+
var branchOrigin = FindBranchOrigin(branch);
94+
return branchOrigin == null
95+
? BranchCommit.Empty
96+
: new BranchCommit(branchOrigin, branch);
97+
}
98+
99+
100+
private ICommit? FindBranchOrigin(IBranch branch)
101+
{
102+
if (branch.Tip == null)
103+
return null;
104+
105+
var branchName = branch.Name.Friendly;
106+
var mergeBase = this.repositoryStore.FindMergeBase(branch.Tip, this.commit);
107+
if (mergeBase is not null)
108+
{
109+
this.log.Info($"Found merge base {mergeBase.Sha} for '{branchName}'.");
110+
return mergeBase;
111+
}
112+
113+
var branchCommit = this.repositoryStore.FindCommitBranchWasBranchedFrom(branch, this.configuration);
114+
if (branchCommit != BranchCommit.Empty)
115+
{
116+
this.log.Info($"Found parent commit {branchCommit.Commit.Sha} for '{branchName}'.");
117+
return branchCommit.Commit;
118+
}
119+
120+
this.log.Info($"Found no merge base or parent commit for '{branchName}'.");
121+
return null;
122+
}
123+
}
124+
}

src/GitVersion.Core/Core/RepositoryStore.cs

Lines changed: 3 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -157,17 +157,10 @@ public IEnumerable<IBranch> GetReleaseBranches(IEnumerable<KeyValuePair<string,
157157
public IEnumerable<IBranch> GetBranchesContainingCommit(ICommit? commit, IEnumerable<IBranch>? branches = null, bool onlyTrackedBranches = false)
158158
=> new BranchesContainingCommitFinder(this.repository, this.log).GetBranchesContainingCommit(commit, branches, onlyTrackedBranches);
159159

160-
public Dictionary<string, List<IBranch>> GetMainlineBranches(ICommit commit, Config configuration, IEnumerable<KeyValuePair<string, BranchConfig>>? mainlineBranchConfigs)
160+
public IDictionary<string, List<IBranch>> GetMainlineBranches(ICommit commit, Config configuration, IEnumerable<KeyValuePair<string, BranchConfig>>? mainlineBranchConfigs)
161161
{
162-
var origins = from branch in this.repository.Branches
163-
where BranchIsMainline(branch, mainlineBranchConfigs)
164-
let branchOrigin = FindBranchOrigin(branch, commit, configuration)
165-
where branchOrigin != null
166-
select (branchOrigin, branch);
167-
168-
return origins
169-
.GroupBy(x => x.branchOrigin.Sha, a => a.branch)
170-
.ToDictionary(x => x.Key, x => x.ToList());
162+
var mainlineBranchFinder = new MainlineBranchFinder(this, this.repository, configuration, mainlineBranchConfigs, this.log);
163+
return mainlineBranchFinder.FindMainlineBranches(commit);
171164
}
172165

173166

@@ -292,45 +285,4 @@ private static IEnumerable<SemanticVersion> GetCurrentCommitSemanticVersions(ICo
292285
? new[] { version }
293286
: Array.Empty<SemanticVersion>();
294287
}
295-
296-
private bool BranchIsMainline(INamedReference branch, IEnumerable<KeyValuePair<string, BranchConfig>>? mainlineBranchConfigs) =>
297-
mainlineBranchConfigs?.Any(c => BranchMatchesMainlineConfig(branch, c)) == true;
298-
299-
private bool BranchMatchesMainlineConfig(INamedReference branch, KeyValuePair<string, BranchConfig> mainlineBranchConfig)
300-
{
301-
if (mainlineBranchConfig.Value?.Regex == null)
302-
{
303-
return false;
304-
}
305-
306-
var mainlineRegex = mainlineBranchConfig.Value.Regex;
307-
var branchName = branch.Name.WithoutRemote;
308-
var match = Regex.IsMatch(branchName, mainlineRegex);
309-
this.log.Info($"'{mainlineRegex}' {(match ? "matches" : "does not match")} '{branchName}'.");
310-
return match;
311-
}
312-
313-
private ICommit? FindBranchOrigin(IBranch branch, ICommit commit, Config configuration)
314-
{
315-
if (branch.Tip == null)
316-
return null;
317-
318-
var branchName = branch.Name.Friendly;
319-
var mergeBase = FindMergeBase(branch.Tip, commit);
320-
if (mergeBase is not null)
321-
{
322-
this.log.Info($"Found merge base {mergeBase.Sha} for '{branchName}'.");
323-
return mergeBase;
324-
}
325-
326-
var branchCommit = FindCommitBranchWasBranchedFrom(branch, configuration);
327-
if (branchCommit != BranchCommit.Empty)
328-
{
329-
this.log.Info($"Found parent commit {branchCommit.Commit.Sha} for '{branchName}'.");
330-
return branchCommit.Commit;
331-
}
332-
333-
this.log.Info($"Found no merge base or parent commit for '{branchName}'.");
334-
return null;
335-
}
336288
}

src/GitVersion.Core/VersionCalculation/MainlineVersionCalculator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ private IBranch GetMainline(ICommit? baseVersionSource)
125125
{
126126
var mainlineBranchConfigs = context.FullConfiguration.Branches.Where(b => b.Value?.IsMainline == true).ToList();
127127

128-
Dictionary<string, List<IBranch>> mainlineBranches = new Dictionary<string, List<IBranch>>();
128+
IDictionary<string, List<IBranch>> mainlineBranches = new Dictionary<string, List<IBranch>>();
129129
if (context.CurrentCommit != null)
130130
{
131131
mainlineBranches = this.repositoryStore.GetMainlineBranches(context.CurrentCommit, context.FullConfiguration, mainlineBranchConfigs);

0 commit comments

Comments
 (0)