Skip to content

Commit

Permalink
moved the retry mechanism out of LibGit2Sharp classlib f2b613
Browse files Browse the repository at this point in the history
  • Loading branch information
arturcic committed Feb 7, 2021
1 parent 13699b2 commit ddba821
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 80 deletions.
30 changes: 22 additions & 8 deletions src/GitVersion.Core/Core/GitPreparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ private void CloneRepository(string repositoryUrl, string gitDirectory, Authenti
{
using (log.IndentLog($"Cloning repository from url '{repositoryUrl}'"))
{
repository.Clone(repositoryUrl, gitDirectory, auth);
new OperationWithExponentialBackoff<LockedFileException>(new ThreadSleep(), log, () =>
{
repository.Clone(repositoryUrl, gitDirectory, auth);
}).ExecuteAsync().Wait();
}
}

Expand Down Expand Up @@ -179,7 +182,9 @@ private void NormalizeGitDirectory(bool noFetch, string currentBranchName, bool
{
var refSpecs = string.Join(", ", remote.FetchRefSpecs.Select(r => r.Specification));
log.Info($"Fetching from remote '{remote.Name}' using the following refspecs: {refSpecs}.");
repository.Fetch(remote.Name, Enumerable.Empty<string>(), authentication, null);
new OperationWithExponentialBackoff<LockedFileException>(new ThreadSleep(), log,
() => repository.Fetch(remote.Name, Enumerable.Empty<string>(), authentication, null))
.ExecuteAsync().Wait();
}

EnsureLocalBranchExistsForCurrentBranch(remote, currentBranchName);
Expand Down Expand Up @@ -221,7 +226,7 @@ private void NormalizeGitDirectory(bool noFetch, string currentBranchName, bool
if (matchingCurrentBranch != null)
{
log.Info($"Checking out local branch '{currentBranchName}'.");
repository.Checkout(matchingCurrentBranch.Name.Canonical);
Checkout(matchingCurrentBranch.Name.Canonical);
}
else if (localBranchesWhereCommitShaIsHead.Count > 1)
{
Expand All @@ -234,7 +239,7 @@ private void NormalizeGitDirectory(bool noFetch, string currentBranchName, bool
if (main != null)
{
log.Warning("Because one of the branches is 'main', will build main." + moveBranchMsg);
repository.Checkout(Config.MainBranchKey);
Checkout(Config.MainBranchKey);
}
else
{
Expand All @@ -243,7 +248,7 @@ private void NormalizeGitDirectory(bool noFetch, string currentBranchName, bool
{
var branchWithoutSeparator = branchesWithoutSeparators[0];
log.Warning($"Choosing {branchWithoutSeparator.Name.Canonical} as it is the only branch without / or - in it. " + moveBranchMsg);
repository.Checkout(branchWithoutSeparator.Name.Canonical);
Checkout(branchWithoutSeparator.Name.Canonical);
}
else
{
Expand All @@ -254,12 +259,15 @@ private void NormalizeGitDirectory(bool noFetch, string currentBranchName, bool
else if (localBranchesWhereCommitShaIsHead.Count == 0)
{
log.Info($"No local branch pointing at the commit '{headSha}'. Fake branch needs to be created.");
repository.CreateBranchForPullRequestBranch(authentication);
new OperationWithExponentialBackoff<LockedFileException>(new ThreadSleep(), log, () =>
{
repository.CreateBranchForPullRequestBranch(authentication);
}).ExecuteAsync().Wait();
}
else
{
log.Info($"Checking out local branch 'refs/heads/{localBranchesWhereCommitShaIsHead[0]}'.");
repository.Checkout(localBranchesWhereCommitShaIsHead[0].Name.Friendly);
Checkout(localBranchesWhereCommitShaIsHead[0].Name.Friendly);
}
}
finally
Expand Down Expand Up @@ -386,7 +394,13 @@ public void EnsureLocalBranchExistsForCurrentBranch(IRemote remote, string curre
new OperationWithExponentialBackoff<LockedFileException>(new ThreadSleep(), log, () => repository.Refs.UpdateTarget(localRef, repoTipId)).ExecuteAsync().Wait();
}

repository.Checkout(localCanonicalName);
Checkout(localCanonicalName);
}

private void Checkout(string commitOrBranchSpec)
{
new OperationWithExponentialBackoff<LockedFileException>(new ThreadSleep(), log, () =>
repository.Checkout(commitOrBranchSpec)).ExecuteAsync().Wait();
}
}
}
8 changes: 0 additions & 8 deletions src/GitVersion.Core/Git/IReferenceCollection.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using GitVersion.Logging;
using System;
using System.Collections.Generic;

namespace GitVersion
Expand All @@ -13,10 +11,4 @@ public interface IReferenceCollection : IEnumerable<IReference>
IEnumerable<IReference> FromGlob(string prefix);
}

public class LockedFileException : Exception
{
public LockedFileException(Exception inner) : base(inner.Message, inner)
{
}
}
}
11 changes: 11 additions & 0 deletions src/GitVersion.Core/Model/Exceptions/LockedFileException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace GitVersion
{
public class LockedFileException : Exception
{
public LockedFileException(Exception inner) : base(inner.Message, inner)
{
}
}
}
117 changes: 60 additions & 57 deletions src/GitVersion.LibGit2Sharp/Git/GitRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,77 +98,74 @@ private int GetNumberOfUncommittedChangesInternal()
}
public void CreateBranchForPullRequestBranch(AuthenticationInfo auth)
{
new OperationWithExponentialBackoff<LockedFileException>(new ThreadSleep(), log, () =>
RepositoryExtensions.RunSafe(() =>
{
CreateBranchForPullRequestBranchInternal(auth);
}).ExecuteAsync().Wait();
}
private void CreateBranchForPullRequestBranchInternal(AuthenticationInfo auth)
{
var network = repositoryInstance.Network;
var remote = network.Remotes.Single();
var network = repositoryInstance.Network;
var remote = network.Remotes.Single();
log.Info("Fetching remote refs to see if there is a pull request ref");
var credentialsProvider = GetCredentialsProvider(auth);
var remoteTips = (credentialsProvider != null
? network.ListReferences(remote, credentialsProvider)
: network.ListReferences(remote))
.Select(r => r.ResolveToDirectReference()).ToList();
log.Info("Fetching remote refs to see if there is a pull request ref");
var credentialsProvider = GetCredentialsProvider(auth);
var remoteTips = (credentialsProvider != null
? network.ListReferences(remote, credentialsProvider)
: network.ListReferences(remote))
.Select(r => r.ResolveToDirectReference()).ToList();
log.Info($"Remote Refs:{System.Environment.NewLine}" + string.Join(System.Environment.NewLine, remoteTips.Select(r => r.CanonicalName)));
log.Info($"Remote Refs:{System.Environment.NewLine}" + string.Join(System.Environment.NewLine, remoteTips.Select(r => r.CanonicalName)));
var headTipSha = Head.Tip?.Sha;
var headTipSha = Head.Tip?.Sha;
var refs = remoteTips.Where(r => r.TargetIdentifier == headTipSha).ToList();
var refs = remoteTips.Where(r => r.TargetIdentifier == headTipSha).ToList();
if (refs.Count == 0)
{
var message = $"Couldn't find any remote tips from remote '{remote.Url}' pointing at the commit '{headTipSha}'.";
throw new WarningException(message);
}
if (refs.Count == 0)
{
var message = $"Couldn't find any remote tips from remote '{remote.Url}' pointing at the commit '{headTipSha}'.";
throw new WarningException(message);
}
if (refs.Count > 1)
{
var names = string.Join(", ", refs.Select(r => r.CanonicalName));
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}).";
throw new WarningException(message);
}
if (refs.Count > 1)
{
var names = string.Join(", ", refs.Select(r => r.CanonicalName));
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}).";
throw new WarningException(message);
}
var reference = refs.First();
var canonicalName = reference.CanonicalName;
var referenceName = ReferenceName.Parse(reference.CanonicalName);
log.Info($"Found remote tip '{canonicalName}' pointing at the commit '{headTipSha}'.");
var reference = refs.First();
var canonicalName = reference.CanonicalName;
var referenceName = ReferenceName.Parse(reference.CanonicalName);
log.Info($"Found remote tip '{canonicalName}' pointing at the commit '{headTipSha}'.");
if (referenceName.IsTag)
{
log.Info($"Checking out tag '{canonicalName}'");
Checkout(reference.Target.Sha);
}
else if (referenceName.IsPullRequest)
{
var fakeBranchName = canonicalName.Replace("refs/pull/", "refs/heads/pull/").Replace("refs/pull-requests/", "refs/heads/pull-requests/");
if (referenceName.IsTag)
{
log.Info($"Checking out tag '{canonicalName}'");
Checkout(reference.Target.Sha);
}
else if (referenceName.IsPullRequest)
{
var fakeBranchName = canonicalName.Replace("refs/pull/", "refs/heads/pull/").Replace("refs/pull-requests/", "refs/heads/pull-requests/");
log.Info($"Creating fake local branch '{fakeBranchName}'.");
Refs.Add(fakeBranchName, headTipSha);
log.Info($"Creating fake local branch '{fakeBranchName}'.");
Refs.Add(fakeBranchName, headTipSha);
log.Info($"Checking local branch '{fakeBranchName}' out.");
Checkout(fakeBranchName);
}
else
{
var message = $"Remote tip '{canonicalName}' from remote '{remote.Url}' doesn't look like a valid pull request.";
throw new WarningException(message);
}
log.Info($"Checking local branch '{fakeBranchName}' out.");
Checkout(fakeBranchName);
}
else
{
var message = $"Remote tip '{canonicalName}' from remote '{remote.Url}' doesn't look like a valid pull request.";
throw new WarningException(message);
}
});
}
public void Clone(string sourceUrl, string workdirPath, AuthenticationInfo auth)
{
try
{
new OperationWithExponentialBackoff<LockedFileException>(new ThreadSleep(), log, () =>
{
var path = Repository.Clone(sourceUrl, workdirPath, GetCloneOptions(auth));
log.Info($"Returned path after repository clone: {path}");
}).ExecuteAsync().Wait();
var path = Repository.Clone(sourceUrl, workdirPath, GetCloneOptions(auth));
log.Info($"Returned path after repository clone: {path}");
}
catch (LibGit2Sharp.LockedFileException ex)
{
throw new LockedFileException(ex);
}
catch (LibGit2SharpException ex)
{
Expand All @@ -191,11 +188,17 @@ public void Clone(string sourceUrl, string workdirPath, AuthenticationInfo auth)
}
public void Checkout(string commitOrBranchSpec)
{
new OperationWithExponentialBackoff<LockedFileException>(new ThreadSleep(), log, () => Commands.Checkout(repositoryInstance, commitOrBranchSpec)).ExecuteAsync().Wait();
RepositoryExtensions.RunSafe(() =>
{
Commands.Checkout(repositoryInstance, commitOrBranchSpec);
});
}
public void Fetch(string remote, IEnumerable<string> refSpecs, AuthenticationInfo auth, string logMessage)
{
new OperationWithExponentialBackoff<LockedFileException>(new ThreadSleep(), log, () => Commands.Fetch((Repository)repositoryInstance, remote, refSpecs, GetFetchOptions(auth), logMessage)).ExecuteAsync().Wait();
RepositoryExtensions.RunSafe(() =>
{
Commands.Fetch((Repository)repositoryInstance, remote, refSpecs, GetFetchOptions(auth), logMessage);
});
}
internal static string Discover(string path) => Repository.Discover(path);

Expand Down
9 changes: 2 additions & 7 deletions src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,10 @@ public void Add(string name, string canonicalRefNameOrObjectish, bool allowOverw

public void UpdateTarget(IReference directRef, IObjectId targetId)
{
try
RepositoryExtensions.RunSafe(() =>
{
innerCollection.UpdateTarget((Reference)directRef, (ObjectId)targetId);
}
catch (LibGit2Sharp.LockedFileException ex)
{
// Wrap this exception so that callers that want to catch it don't need to take a dependency on LibGit2Sharp.
throw new LockedFileException(ex);
}
});
}

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
Expand Down
27 changes: 27 additions & 0 deletions src/GitVersion.LibGit2Sharp/RepositoryExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using LibGit2Sharp;
using Microsoft.Extensions.Options;

Expand All @@ -7,5 +8,31 @@ public static class RepositoryExtensions
{
public static IGitRepository ToGitRepository(this IRepository repository) => new GitRepository(repository);
public static IGitRepositoryInfo ToGitRepositoryInfo(IOptions<GitVersionOptions> options) => new GitRepositoryInfo(options);

public static void RunSafe(Action operation)
{
try
{
operation();
}
catch (LibGit2Sharp.LockedFileException ex)
{
// Wrap this exception so that callers that want to catch it don't need to take a dependency on LibGit2Sharp.
throw new LockedFileException(ex);
}
}

public static T RunSafe<T>(Func<T> operation)
{
try
{
return operation();
}
catch (LibGit2Sharp.LockedFileException ex)
{
// Wrap this exception so that callers that want to catch it don't need to take a dependency on LibGit2Sharp.
throw new LockedFileException(ex);
}
}
}
}

0 comments on commit ddba821

Please sign in to comment.