From ddba821eb9d2b75aa81d22dc4cea1199052e1b69 Mon Sep 17 00:00:00 2001 From: Artur Date: Sun, 7 Feb 2021 13:51:34 +0100 Subject: [PATCH] moved the retry mechanism out of LibGit2Sharp classlib f2b613 --- src/GitVersion.Core/Core/GitPreparer.cs | 30 +++-- .../Git/IReferenceCollection.cs | 8 -- .../Model/Exceptions/LockedFileException.cs | 11 ++ .../Git/GitRepository.cs | 117 +++++++++--------- .../Git/ReferenceCollection.cs | 9 +- .../RepositoryExtensions.cs | 27 ++++ 6 files changed, 122 insertions(+), 80 deletions(-) create mode 100644 src/GitVersion.Core/Model/Exceptions/LockedFileException.cs diff --git a/src/GitVersion.Core/Core/GitPreparer.cs b/src/GitVersion.Core/Core/GitPreparer.cs index bd4ea4d36e..9e16df1438 100644 --- a/src/GitVersion.Core/Core/GitPreparer.cs +++ b/src/GitVersion.Core/Core/GitPreparer.cs @@ -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(new ThreadSleep(), log, () => + { + repository.Clone(repositoryUrl, gitDirectory, auth); + }).ExecuteAsync().Wait(); } } @@ -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(), authentication, null); + new OperationWithExponentialBackoff(new ThreadSleep(), log, + () => repository.Fetch(remote.Name, Enumerable.Empty(), authentication, null)) + .ExecuteAsync().Wait(); } EnsureLocalBranchExistsForCurrentBranch(remote, currentBranchName); @@ -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) { @@ -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 { @@ -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 { @@ -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(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 @@ -386,7 +394,13 @@ public void EnsureLocalBranchExistsForCurrentBranch(IRemote remote, string curre new OperationWithExponentialBackoff(new ThreadSleep(), log, () => repository.Refs.UpdateTarget(localRef, repoTipId)).ExecuteAsync().Wait(); } - repository.Checkout(localCanonicalName); + Checkout(localCanonicalName); + } + + private void Checkout(string commitOrBranchSpec) + { + new OperationWithExponentialBackoff(new ThreadSleep(), log, () => + repository.Checkout(commitOrBranchSpec)).ExecuteAsync().Wait(); } } } diff --git a/src/GitVersion.Core/Git/IReferenceCollection.cs b/src/GitVersion.Core/Git/IReferenceCollection.cs index 9a7cf69d45..0a0a15a306 100644 --- a/src/GitVersion.Core/Git/IReferenceCollection.cs +++ b/src/GitVersion.Core/Git/IReferenceCollection.cs @@ -1,5 +1,3 @@ -using GitVersion.Logging; -using System; using System.Collections.Generic; namespace GitVersion @@ -13,10 +11,4 @@ public interface IReferenceCollection : IEnumerable IEnumerable FromGlob(string prefix); } - public class LockedFileException : Exception - { - public LockedFileException(Exception inner) : base(inner.Message, inner) - { - } - } } diff --git a/src/GitVersion.Core/Model/Exceptions/LockedFileException.cs b/src/GitVersion.Core/Model/Exceptions/LockedFileException.cs new file mode 100644 index 0000000000..f53226812e --- /dev/null +++ b/src/GitVersion.Core/Model/Exceptions/LockedFileException.cs @@ -0,0 +1,11 @@ +using System; + +namespace GitVersion +{ + public class LockedFileException : Exception + { + public LockedFileException(Exception inner) : base(inner.Message, inner) + { + } + } +} diff --git a/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs b/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs index 4737d11884..95eb657ee6 100644 --- a/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs +++ b/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs @@ -98,77 +98,74 @@ private int GetNumberOfUncommittedChangesInternal() } public void CreateBranchForPullRequestBranch(AuthenticationInfo auth) { - new OperationWithExponentialBackoff(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(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) { @@ -191,11 +188,17 @@ public void Clone(string sourceUrl, string workdirPath, AuthenticationInfo auth) } public void Checkout(string commitOrBranchSpec) { - new OperationWithExponentialBackoff(new ThreadSleep(), log, () => Commands.Checkout(repositoryInstance, commitOrBranchSpec)).ExecuteAsync().Wait(); + RepositoryExtensions.RunSafe(() => + { + Commands.Checkout(repositoryInstance, commitOrBranchSpec); + }); } public void Fetch(string remote, IEnumerable refSpecs, AuthenticationInfo auth, string logMessage) { - new OperationWithExponentialBackoff(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); diff --git a/src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs b/src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs index e77e2b9b1a..ba03760e91 100644 --- a/src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs +++ b/src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs @@ -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(); diff --git a/src/GitVersion.LibGit2Sharp/RepositoryExtensions.cs b/src/GitVersion.LibGit2Sharp/RepositoryExtensions.cs index c4f25e845b..790139a5c6 100644 --- a/src/GitVersion.LibGit2Sharp/RepositoryExtensions.cs +++ b/src/GitVersion.LibGit2Sharp/RepositoryExtensions.cs @@ -1,3 +1,4 @@ +using System; using LibGit2Sharp; using Microsoft.Extensions.Options; @@ -7,5 +8,31 @@ public static class RepositoryExtensions { public static IGitRepository ToGitRepository(this IRepository repository) => new GitRepository(repository); public static IGitRepositoryInfo ToGitRepositoryInfo(IOptions 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(Func 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); + } + } } }