Skip to content

Commit 883f02d

Browse files
authored
Merge pull request #3070 from asbjornu/feature/gh-3068
More `null` protection
2 parents 6ef2aad + 95abafb commit 883f02d

12 files changed

+631
-281
lines changed

.editorconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ csharp_space_between_method_declaration_parameter_list_parentheses = false
155155
csharp_space_between_parentheses = false
156156
csharp_space_between_square_brackets = false
157157

158+
# Alignment
159+
align_multiline_parameter = true
160+
161+
# Qualify fields with "this."
162+
csharp_instance_members_qualify_members = field
163+
158164
# IDE0011: Add braces
159165
dotnet_diagnostic.IDE0011.severity = none
160166

.github/workflows/ci.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -322,48 +322,48 @@ jobs:
322322
dotnet-version: '6.0.x'
323323
-
324324
name: Login to DockerHub
325-
if: success() && github.event_name != 'pull_request'
325+
if: success() && github.event_name != 'pull_request' && github.repository_owner == 'GitTools'
326326
uses: docker/login-action@v1
327327
with:
328328
username: ${{ secrets.DOCKER_USERNAME }}
329329
password: ${{ secrets.DOCKER_PASSWORD }}
330330
-
331331
name: '[Docker Build/Test/Publish (amd64)] DockerHub'
332-
if: success() && github.event_name != 'pull_request'
332+
if: success() && github.event_name != 'pull_request' && github.repository_owner == 'GitTools'
333333
shell: pwsh
334334
run: dotnet run/docker.dll --target=DockerPublish --arch amd64 --docker_dotnetversion=${{ matrix.targetFramework }} --docker_distro=${{ matrix.distro }} --docker_registry dockerhub
335335
-
336336
name: '[Docker Build/Test/Publish (arm64)] DockerHub'
337-
if: success() && github.event_name != 'pull_request'
337+
if: success() && github.event_name != 'pull_request' && github.repository_owner == 'GitTools'
338338
shell: pwsh
339339
run: dotnet run/docker.dll --target=DockerPublish --arch arm64 --docker_dotnetversion=${{ matrix.targetFramework }} --docker_distro=${{ matrix.distro }} --docker_registry dockerhub
340340
-
341341
name: '[Docker Publish Manifest] DockerHub'
342-
if: success() && github.event_name != 'pull_request'
342+
if: success() && github.event_name != 'pull_request' && github.repository_owner == 'GitTools'
343343
shell: pwsh
344344
run: dotnet run/docker.dll --target=DockerManifest --docker_dotnetversion=${{ matrix.targetFramework }} --docker_distro=${{ matrix.distro }} --docker_registry dockerhub
345345

346346
-
347347
name: Login to GitHub Container Registry
348-
if: success() && github.event_name != 'pull_request' && github.repository == 'GitTools/GitVersion'
348+
if: success() && github.event_name != 'pull_request' && github.repository_owner == 'GitTools'
349349
uses: docker/login-action@v1
350350
with:
351351
registry: ghcr.io
352352
username: ${{ github.repository_owner }}
353353
password: ${{ secrets.DOCKER_GITHUB_TOKEN }}
354354
-
355355
name: '[Docker Build/Test/Publish (amd64)] GitHub Container Registry'
356-
if: success() && github.event_name != 'pull_request' && github.repository == 'GitTools/GitVersion'
356+
if: success() && github.event_name != 'pull_request' && github.repository_owner == 'GitTools'
357357
shell: pwsh
358358
run: dotnet run/docker.dll --target=DockerPublish --arch amd64 --docker_dotnetversion=${{ matrix.targetFramework }} --docker_distro=${{ matrix.distro }} --docker_registry github
359359
-
360360
name: '[Docker Build/Test/Publish (arm64)] GitHub Container Registry'
361-
if: success() && github.event_name != 'pull_request' && github.repository == 'GitTools/GitVersion'
361+
if: success() && github.event_name != 'pull_request' && github.repository_owner == 'GitTools'
362362
shell: pwsh
363363
run: dotnet run/docker.dll --target=DockerPublish --arch arm64 --docker_dotnetversion=${{ matrix.targetFramework }} --docker_distro=${{ matrix.distro }} --docker_registry github
364364
-
365365
name: '[Docker Publish Manifest] GitHub Container Registry'
366-
if: success() && github.event_name != 'pull_request' && github.repository == 'GitTools/GitVersion'
366+
if: success() && github.event_name != 'pull_request' && github.repository_owner == 'GitTools'
367367
shell: pwsh
368368
run: dotnet run/docker.dll --target=DockerManifest --docker_dotnetversion=${{ matrix.targetFramework }} --docker_distro=${{ matrix.distro }} --docker_registry github
369369

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: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using GitVersion.Extensions;
2+
using GitVersion.Logging;
3+
4+
namespace GitVersion;
5+
6+
internal class BranchesContainingCommitFinder
7+
{
8+
private readonly ILog log;
9+
private readonly IGitRepository repository;
10+
11+
public BranchesContainingCommitFinder(IGitRepository repository, ILog log)
12+
{
13+
this.repository = repository.NotNull();
14+
this.log = log.NotNull();
15+
}
16+
17+
public IEnumerable<IBranch> GetBranchesContainingCommit(ICommit? commit, IEnumerable<IBranch>? branches = null, bool onlyTrackedBranches = false)
18+
{
19+
commit = commit.NotNull();
20+
branches ??= this.repository.Branches.ToList();
21+
22+
// TODO Should we cache this?
23+
// Yielding part is split from the main part of the method to avoid having the exception check performed lazily.
24+
// Details at https://github.com/GitTools/GitVersion/issues/2755
25+
return InnerGetBranchesContainingCommit(commit, branches, onlyTrackedBranches);
26+
}
27+
28+
private IEnumerable<IBranch> InnerGetBranchesContainingCommit(IGitObject commit, IEnumerable<IBranch> branches, bool onlyTrackedBranches)
29+
{
30+
using (log.IndentLog($"Getting branches containing the commit '{commit.Id}'."))
31+
{
32+
var directBranchHasBeenFound = false;
33+
log.Info("Trying to find direct branches.");
34+
// TODO: It looks wasteful looping through the branches twice. Can't these loops be merged somehow? @asbjornu
35+
List<IBranch> branchList = branches.ToList();
36+
foreach (var branch in branchList.Where(branch => BranchTipIsNullOrCommit(branch, commit) && !IncludeTrackedBranches(branch, onlyTrackedBranches)))
37+
{
38+
directBranchHasBeenFound = true;
39+
log.Info($"Direct branch found: '{branch}'.");
40+
yield return branch;
41+
}
42+
43+
if (directBranchHasBeenFound)
44+
{
45+
yield break;
46+
}
47+
48+
log.Info($"No direct branches found, searching through {(onlyTrackedBranches ? "tracked" : "all")} branches.");
49+
foreach (IBranch branch in branchList.Where(b => IncludeTrackedBranches(b, onlyTrackedBranches)))
50+
{
51+
log.Info($"Searching for commits reachable from '{branch}'.");
52+
53+
var commits = GetCommitsReacheableFrom(commit, branch);
54+
55+
if (!commits.Any())
56+
{
57+
log.Info($"The branch '{branch}' has no matching commits.");
58+
continue;
59+
}
60+
61+
log.Info($"The branch '{branch}' has a matching commit.");
62+
yield return branch;
63+
}
64+
}
65+
}
66+
67+
private IEnumerable<ICommit> GetCommitsReacheableFrom(IGitObject commit, IBranch branch)
68+
{
69+
var filter = new CommitFilter { IncludeReachableFrom = branch };
70+
var commitCollection = this.repository.Commits.QueryBy(filter);
71+
72+
return commitCollection.Where(c => c.Sha == commit.Sha);
73+
}
74+
75+
private static bool IncludeTrackedBranches(IBranch branch, bool includeOnlyTracked)
76+
=> includeOnlyTracked && branch.IsTracking || !includeOnlyTracked;
77+
78+
private static bool BranchTipIsNullOrCommit(IBranch branch, IGitObject commit)
79+
=> branch.Tip == null || branch.Tip.Sha == commit.Sha;
80+
}
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 IRepositoryStore repositoryStore;
16+
17+
18+
public MainlineBranchFinder(IRepositoryStore 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+
}

0 commit comments

Comments
 (0)