Skip to content

Commit 16c625c

Browse files
committed
Add null check to GitRepository
- Add null check to GitRepository - Also refactor the code a bit for readability
1 parent 81dabba commit 16c625c

File tree

1 file changed

+121
-122
lines changed

1 file changed

+121
-122
lines changed

src/GitVersion.LibGit2Sharp/Git/GitRepository.cs

Lines changed: 121 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ internal sealed class GitRepository : IMutatingGitRepository
1010
{
1111
private readonly ILog log;
1212
private readonly Lazy<IRepository> repositoryLazy;
13-
private IRepository repositoryInstance => this.repositoryLazy.Value;
1413

1514
public GitRepository(ILog log, IGitRepositoryInfo repositoryInfo)
1615
: this(log, () => repositoryInfo.GitRootPath)
@@ -24,6 +23,7 @@ internal GitRepository(string gitRootDirectory)
2423

2524
internal GitRepository(IRepository repository)
2625
{
26+
repository = repository.NotNull();
2727
this.log = new NullLog();
2828
this.repositoryLazy = new Lazy<IRepository>(() => repository);
2929
}
@@ -34,133 +34,74 @@ private GitRepository(ILog log, Func<string?> getGitRootDirectory)
3434
this.repositoryLazy = new Lazy<IRepository>(() => new Repository(getGitRootDirectory()));
3535
}
3636

37-
public void Dispose()
38-
{
39-
if (this.repositoryLazy.IsValueCreated) repositoryInstance.Dispose();
40-
}
41-
42-
public string Path => repositoryInstance.Info.Path;
43-
public string WorkingDirectory => repositoryInstance.Info.WorkingDirectory;
44-
public bool IsHeadDetached => repositoryInstance.Info.IsHeadDetached;
45-
46-
public IBranch Head => new Branch(repositoryInstance.Head);
47-
public ITagCollection Tags => new TagCollection(repositoryInstance.Tags);
48-
public IReferenceCollection Refs => new ReferenceCollection(repositoryInstance.Refs);
49-
public IBranchCollection Branches => new BranchCollection(repositoryInstance.Branches);
50-
public ICommitCollection Commits => new CommitCollection(repositoryInstance.Commits);
51-
public IRemoteCollection Remotes => new RemoteCollection(repositoryInstance.Network.Remotes);
37+
private IRepository RepositoryInstance => this.repositoryLazy.Value;
38+
public string Path => RepositoryInstance.Info.Path;
39+
public string WorkingDirectory => RepositoryInstance.Info.WorkingDirectory;
40+
public bool IsHeadDetached => RepositoryInstance.Info.IsHeadDetached;
41+
public IBranch Head => new Branch(RepositoryInstance.Head);
42+
public ITagCollection Tags => new TagCollection(RepositoryInstance.Tags);
43+
public IReferenceCollection Refs => new ReferenceCollection(RepositoryInstance.Refs);
44+
public IBranchCollection Branches => new BranchCollection(RepositoryInstance.Branches);
45+
public ICommitCollection Commits => new CommitCollection(RepositoryInstance.Commits);
46+
public IRemoteCollection Remotes => new RemoteCollection(RepositoryInstance.Network.Remotes);
5247

5348
public ICommit? FindMergeBase(ICommit commit, ICommit otherCommit)
5449
{
55-
_ = commit.NotNull();
56-
_ = otherCommit.NotNull();
50+
commit = commit.NotNull();
51+
otherCommit = otherCommit.NotNull();
5752

5853
var retryAction = new RetryAction<LockedFileException, ICommit?>();
5954
return retryAction.Execute(() =>
6055
{
61-
var mergeBase = repositoryInstance.ObjectDatabase.FindMergeBase((Commit)commit, (Commit)otherCommit);
56+
var first = (Commit)commit;
57+
var second = (Commit)otherCommit;
58+
var mergeBase = RepositoryInstance.ObjectDatabase.FindMergeBase(first, second);
6259
return mergeBase == null ? null : new Commit(mergeBase);
6360
});
6461
}
62+
6563
public int GetNumberOfUncommittedChanges()
6664
{
6765
var retryAction = new RetryAction<LibGit2Sharp.LockedFileException, int>();
6866
return retryAction.Execute(GetNumberOfUncommittedChangesInternal);
6967
}
70-
private int GetNumberOfUncommittedChangesInternal()
68+
69+
public void CreateBranchForPullRequestBranch(AuthenticationInfo auth) => RepositoryExtensions.RunSafe(() =>
7170
{
72-
// check if we have a branch tip at all to behave properly with empty repos
73-
// => return that we have actually un-committed changes because we are apparently
74-
// running GitVersion on something which lives inside this brand new repo _/\Ö/\_
75-
if (repositoryInstance.Head?.Tip == null || repositoryInstance.Diff == null)
76-
{
77-
// this is a somewhat cumbersome way of figuring out the number of changes in the repo
78-
// which is more expensive than to use the Diff as it gathers more info, but
79-
// we can't use the other method when we are dealing with a new/empty repo
80-
try
81-
{
82-
var status = repositoryInstance.RetrieveStatus();
83-
return status.Untracked.Count() + status.Staged.Count();
84-
}
85-
catch (Exception)
86-
{
87-
return int.MaxValue; // this should be somewhat puzzling to see,
88-
// so we may have reached our goal to show that
89-
// that repo is really "Dirty"...
90-
}
91-
}
71+
this.log.Info("Fetching remote refs to see if there is a pull request ref");
9272

93-
// gets all changes of the last commit vs Staging area and WT
94-
var changes = repositoryInstance.Diff.Compare<TreeChanges>(repositoryInstance.Head.Tip.Tree,
95-
DiffTargets.Index | DiffTargets.WorkingDirectory);
73+
// FIX ME: What to do when Tip is null?
74+
if (Head.Tip == null)
75+
return;
9676

97-
return changes.Count;
98-
}
77+
var headTipSha = Head.Tip.Sha;
78+
var remote = RepositoryInstance.Network.Remotes.Single();
79+
var reference = GetPullRequestReference(auth, remote, headTipSha);
80+
var canonicalName = reference.CanonicalName;
81+
var referenceName = ReferenceName.Parse(reference.CanonicalName);
82+
this.log.Info($"Found remote tip '{canonicalName}' pointing at the commit '{headTipSha}'.");
9983

100-
public void CreateBranchForPullRequestBranch(AuthenticationInfo auth) =>
101-
RepositoryExtensions.RunSafe(() =>
84+
if (referenceName.IsTag)
10285
{
103-
var network = repositoryInstance.Network;
104-
var remote = network.Remotes.Single();
105-
106-
this.log.Info("Fetching remote refs to see if there is a pull request ref");
107-
var credentialsProvider = GetCredentialsProvider(auth);
108-
var remoteTips = (credentialsProvider != null
109-
? network.ListReferences(remote, credentialsProvider)
110-
: network.ListReferences(remote))
111-
.Select(r => r.ResolveToDirectReference()).ToList();
112-
113-
this.log.Info($"Remote Refs:{System.Environment.NewLine}" + string.Join(System.Environment.NewLine, remoteTips.Select(r => r.CanonicalName)));
114-
115-
// FIX ME: What to do when Tip is null?
116-
if (Head.Tip != null)
117-
{
118-
var headTipSha = Head.Tip.Sha;
119-
120-
var refs = remoteTips.Where(r => r.TargetIdentifier == headTipSha).ToList();
121-
122-
switch (refs.Count)
123-
{
124-
case 0:
125-
{
126-
var message = $"Couldn't find any remote tips from remote '{remote.Url}' pointing at the commit '{headTipSha}'.";
127-
throw new WarningException(message);
128-
}
129-
case > 1:
130-
{
131-
var names = string.Join(", ", refs.Select(r => r.CanonicalName));
132-
var message = $"Found more than one remote tip from remote '{remote.Url}' pointing at the commit '{headTipSha}'. Unable to determine which one to use ({names}).";
133-
throw new WarningException(message);
134-
}
135-
}
136-
137-
var reference = refs.First();
138-
var canonicalName = reference.CanonicalName;
139-
var referenceName = ReferenceName.Parse(reference.CanonicalName);
140-
this.log.Info($"Found remote tip '{canonicalName}' pointing at the commit '{headTipSha}'.");
141-
142-
if (referenceName.IsTag)
143-
{
144-
this.log.Info($"Checking out tag '{canonicalName}'");
145-
Checkout(reference.Target.Sha);
146-
}
147-
else if (referenceName.IsPullRequest)
148-
{
149-
var fakeBranchName = canonicalName.Replace("refs/pull/", "refs/heads/pull/").Replace("refs/pull-requests/", "refs/heads/pull-requests/");
86+
this.log.Info($"Checking out tag '{canonicalName}'");
87+
Checkout(reference.Target.Sha);
88+
}
89+
else if (referenceName.IsPullRequest)
90+
{
91+
var fakeBranchName = canonicalName.Replace("refs/pull/", "refs/heads/pull/").Replace("refs/pull-requests/", "refs/heads/pull-requests/");
15092

151-
this.log.Info($"Creating fake local branch '{fakeBranchName}'.");
152-
Refs.Add(fakeBranchName, headTipSha);
93+
this.log.Info($"Creating fake local branch '{fakeBranchName}'.");
94+
Refs.Add(fakeBranchName, headTipSha);
15395

154-
this.log.Info($"Checking local branch '{fakeBranchName}' out.");
155-
Checkout(fakeBranchName);
156-
}
157-
else
158-
{
159-
var message = $"Remote tip '{canonicalName}' from remote '{remote.Url}' doesn't look like a valid pull request.";
160-
throw new WarningException(message);
161-
}
162-
}
163-
});
96+
this.log.Info($"Checking local branch '{fakeBranchName}' out.");
97+
Checkout(fakeBranchName);
98+
}
99+
else
100+
{
101+
var message = $"Remote tip '{canonicalName}' from remote '{remote.Url}' doesn't look like a valid pull request.";
102+
throw new WarningException(message);
103+
}
104+
});
164105

165106
public void Clone(string? sourceUrl, string? workdirPath, AuthenticationInfo auth)
166107
{
@@ -180,10 +121,12 @@ public void Clone(string? sourceUrl, string? workdirPath, AuthenticationInfo aut
180121
{
181122
throw new Exception("Unauthorized: Incorrect username/password", ex);
182123
}
124+
183125
if (message.Contains("403"))
184126
{
185127
throw new Exception("Forbidden: Possibly Incorrect username/password", ex);
186128
}
129+
187130
if (message.Contains("404"))
188131
{
189132
throw new Exception("Not found: The repository was not found", ex);
@@ -192,39 +135,95 @@ public void Clone(string? sourceUrl, string? workdirPath, AuthenticationInfo aut
192135
throw new Exception("There was an unknown problem with the Git repository you provided", ex);
193136
}
194137
}
138+
195139
public void Checkout(string commitOrBranchSpec) =>
196140
RepositoryExtensions.RunSafe(() =>
197-
Commands.Checkout(repositoryInstance, commitOrBranchSpec));
141+
Commands.Checkout(RepositoryInstance, commitOrBranchSpec));
198142

199143
public void Fetch(string remote, IEnumerable<string> refSpecs, AuthenticationInfo auth, string? logMessage) =>
200144
RepositoryExtensions.RunSafe(() =>
201-
Commands.Fetch((Repository)repositoryInstance, remote, refSpecs, GetFetchOptions(auth), logMessage));
145+
Commands.Fetch((Repository)RepositoryInstance, remote, refSpecs, GetFetchOptions(auth), logMessage));
146+
147+
private DirectReference GetPullRequestReference(AuthenticationInfo auth, LibGit2Sharp.Remote remote, string headTipSha)
148+
{
149+
var network = RepositoryInstance.Network;
150+
var credentialsProvider = GetCredentialsProvider(auth);
151+
var remoteTips = (credentialsProvider != null
152+
? network.ListReferences(remote, credentialsProvider)
153+
: network.ListReferences(remote))
154+
.Select(r => r.ResolveToDirectReference()).ToList();
155+
156+
this.log.Info($"Remote Refs:{System.Environment.NewLine}" + string.Join(System.Environment.NewLine, remoteTips.Select(r => r.CanonicalName)));
157+
var refs = remoteTips.Where(r => r.TargetIdentifier == headTipSha).ToList();
158+
159+
switch (refs.Count)
160+
{
161+
case 0:
162+
{
163+
var message = $"Couldn't find any remote tips from remote '{remote.Url}' pointing at the commit '{headTipSha}'.";
164+
throw new WarningException(message);
165+
}
166+
case > 1:
167+
{
168+
var names = string.Join(", ", refs.Select(r => r.CanonicalName));
169+
var message = $"Found more than one remote tip from remote '{remote.Url}' pointing at the commit '{headTipSha}'. Unable to determine which one to use ({names}).";
170+
throw new WarningException(message);
171+
}
172+
}
173+
174+
return refs.First();
175+
}
176+
177+
public void Dispose()
178+
{
179+
if (this.repositoryLazy.IsValueCreated) RepositoryInstance.Dispose();
180+
}
181+
182+
private int GetNumberOfUncommittedChangesInternal()
183+
{
184+
// check if we have a branch tip at all to behave properly with empty repos
185+
// => return that we have actually un-committed changes because we are apparently
186+
// running GitVersion on something which lives inside this brand new repo _/\Ö/\_
187+
if (RepositoryInstance.Head?.Tip == null || RepositoryInstance.Diff == null)
188+
{
189+
// this is a somewhat cumbersome way of figuring out the number of changes in the repo
190+
// which is more expensive than to use the Diff as it gathers more info, but
191+
// we can't use the other method when we are dealing with a new/empty repo
192+
try
193+
{
194+
var status = RepositoryInstance.RetrieveStatus();
195+
return status.Untracked.Count() + status.Staged.Count();
196+
}
197+
catch (Exception)
198+
{
199+
return int.MaxValue; // this should be somewhat puzzling to see,
200+
// so we may have reached our goal to show that
201+
// that repo is really "Dirty"...
202+
}
203+
}
204+
205+
// gets all changes of the last commit vs Staging area and WT
206+
var changes = RepositoryInstance.Diff.Compare<TreeChanges>(RepositoryInstance.Head.Tip.Tree,
207+
DiffTargets.Index | DiffTargets.WorkingDirectory);
208+
209+
return changes.Count;
210+
}
202211

203212
internal static string? Discover(string? path) => Repository.Discover(path);
204213

205214
private static FetchOptions GetFetchOptions(AuthenticationInfo auth) =>
206-
new()
207-
{
208-
CredentialsProvider = GetCredentialsProvider(auth)
209-
};
215+
new() { CredentialsProvider = GetCredentialsProvider(auth) };
210216

211217
private static CloneOptions GetCloneOptions(AuthenticationInfo auth) =>
212-
new()
213-
{
214-
Checkout = false,
215-
CredentialsProvider = GetCredentialsProvider(auth)
216-
};
218+
new() { Checkout = false, CredentialsProvider = GetCredentialsProvider(auth) };
217219

218220
private static CredentialsHandler? GetCredentialsProvider(AuthenticationInfo auth)
219221
{
220222
if (!auth.Username.IsNullOrWhiteSpace())
221223
{
222-
return (_, _, _) => new UsernamePasswordCredentials
223-
{
224-
Username = auth.Username,
225-
Password = auth.Password ?? string.Empty
226-
};
224+
return (_, _, _) => new UsernamePasswordCredentials { Username = auth.Username, Password = auth.Password ?? string.Empty };
227225
}
226+
228227
return null;
229228
}
230229
}

0 commit comments

Comments
 (0)