/// <inheritdoc /> #pragma warning disable CA1506 // TODO: Decomplexify public async Task <bool?> AddTestMerge( TestMergeParameters testMergeParameters, string committerName, string committerEmail, string username, string password, Action <int> progressReporter, CancellationToken cancellationToken) { if (testMergeParameters == null) { throw new ArgumentNullException(nameof(testMergeParameters)); } if (committerName == null) { throw new ArgumentNullException(nameof(committerName)); } if (committerEmail == null) { throw new ArgumentNullException(nameof(committerEmail)); } if (progressReporter == null) { throw new ArgumentNullException(nameof(progressReporter)); } logger.LogDebug( "Begin AddTestMerge: #{0} at {1} ({2}) by <{3} ({4})>", testMergeParameters.Number, testMergeParameters.TargetCommitSha?.Substring(0, 7), testMergeParameters.Comment, committerName, committerEmail); if (RemoteGitProvider == Api.Models.RemoteGitProvider.Unknown) { throw new InvalidOperationException("Cannot test merge with an Unknown RemoteGitProvider!"); } var commitMessage = String.Format( CultureInfo.InvariantCulture, "TGS Test merge #{0}{1}{2}", testMergeParameters.Number, testMergeParameters.Comment != null ? Environment.NewLine : String.Empty, testMergeParameters.Comment ?? String.Empty); var testMergeBranchName = String.Format(CultureInfo.InvariantCulture, "tm-{0}", testMergeParameters.Number); var localBranchName = String.Format(CultureInfo.InvariantCulture, gitRemoteFeatures.TestMergeLocalBranchNameFormatter, testMergeParameters.Number, testMergeBranchName); var refSpec = String.Format(CultureInfo.InvariantCulture, gitRemoteFeatures.TestMergeRefSpecFormatter, testMergeParameters.Number, testMergeBranchName); var refSpecList = new List <string> { refSpec }; var logMessage = String.Format(CultureInfo.InvariantCulture, "Test merge #{0}", testMergeParameters.Number); var originalCommit = libGitRepo.Head; MergeResult result = null; var sig = new Signature(new Identity(committerName, committerEmail), DateTimeOffset.UtcNow); await Task.Factory.StartNew( () => { try { try { logger.LogTrace("Fetching refspec {0}...", refSpec); var remote = libGitRepo.Network.Remotes.First(); progressReporter(0); commands.Fetch( libGitRepo, refSpecList, remote, new FetchOptions { Prune = true, OnProgress = (a) => !cancellationToken.IsCancellationRequested, OnTransferProgress = (a) => { var percentage = 50 * (((float)a.IndexedObjects + a.ReceivedObjects) / (a.TotalObjects * 2)); progressReporter((int)percentage); return(!cancellationToken.IsCancellationRequested); }, OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password), }, logMessage); } catch (UserCancelledException) { } catch (LibGit2SharpException ex) { CheckBadCredentialsException(ex); } cancellationToken.ThrowIfCancellationRequested(); libGitRepo.RemoveUntrackedFiles(); cancellationToken.ThrowIfCancellationRequested(); testMergeParameters.TargetCommitSha = libGitRepo.Lookup(testMergeParameters.TargetCommitSha ?? localBranchName).Sha; cancellationToken.ThrowIfCancellationRequested(); logger.LogTrace("Merging {0} into {1}...", testMergeParameters.TargetCommitSha.Substring(0, 7), Reference); result = libGitRepo.Merge(testMergeParameters.TargetCommitSha, sig, new MergeOptions { CommitOnSuccess = commitMessage == null, FailOnConflict = true, FastForwardStrategy = FastForwardStrategy.NoFastForward, SkipReuc = true, OnCheckoutProgress = (a, completedSteps, totalSteps) => progressReporter(50 + ((int)(((float)completedSteps) / totalSteps * 50))), }); } finally { libGitRepo.Branches.Remove(localBranchName); } cancellationToken.ThrowIfCancellationRequested(); if (result.Status == MergeStatus.Conflicts) { var revertTo = originalCommit.CanonicalName ?? originalCommit.Tip.Sha; logger.LogDebug("Merge conflict, aborting and reverting to {0}", revertTo); RawCheckout(revertTo, progressReporter, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); } libGitRepo.RemoveUntrackedFiles(); }, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current) .ConfigureAwait(false); if (result.Status == MergeStatus.Conflicts) { await eventConsumer.HandleEvent( EventType.RepoMergeConflict, new List <string> { originalCommit.Tip.Sha, testMergeParameters.TargetCommitSha, originalCommit.FriendlyName ?? UnknownReference, testMergeBranchName, }, cancellationToken) .ConfigureAwait(false); return(null); } if (commitMessage != null && result.Status != MergeStatus.UpToDate) { logger.LogTrace("Committing merge: \"{0}\"...", commitMessage); await Task.Factory.StartNew( () => libGitRepo.Commit(commitMessage, sig, sig, new CommitOptions { PrettifyMessage = true, }), cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current) .ConfigureAwait(false); } await eventConsumer.HandleEvent( EventType.RepoAddTestMerge, new List <string> { testMergeParameters.Number.ToString(CultureInfo.InvariantCulture), testMergeParameters.TargetCommitSha, testMergeParameters.Comment, }, cancellationToken) .ConfigureAwait(false); return(result.Status != MergeStatus.NonFastForward); }
/// <inheritdoc /> #pragma warning disable CA1506 // TODO: Decomplexify public async Task <bool?> AddTestMerge(TestMergeParameters testMergeParameters, string committerName, string committerEmail, string username, string password, Action <int> progressReporter, CancellationToken cancellationToken) { if (testMergeParameters == null) { throw new ArgumentNullException(nameof(testMergeParameters)); } if (committerName == null) { throw new ArgumentNullException(nameof(committerName)); } if (committerEmail == null) { throw new ArgumentNullException(nameof(committerEmail)); } if (progressReporter == null) { throw new ArgumentNullException(nameof(progressReporter)); } logger.LogDebug("Begin AddTestMerge: #{0} at {1} ({4}) by <{2} ({3})>", testMergeParameters.Number, testMergeParameters.PullRequestRevision?.Substring(0, 7), committerName, committerEmail, testMergeParameters.Comment); if (!IsGitHubRepository) { throw new InvalidOperationException("Test merging is only available on GitHub hosted origin repositories!"); } var commitMessage = String.Format(CultureInfo.InvariantCulture, "Test merge of pull request #{0}{1}{2}", testMergeParameters.Number.Value, testMergeParameters.Comment != null ? Environment.NewLine : String.Empty, testMergeParameters.Comment ?? String.Empty); var prBranchName = String.Format(CultureInfo.InvariantCulture, "pr-{0}", testMergeParameters.Number); var localBranchName = String.Format(CultureInfo.InvariantCulture, "pull/{0}/headrefs/heads/{1}", testMergeParameters.Number, prBranchName); var refSpec = String.Format(CultureInfo.InvariantCulture, "pull/{0}/head:{1}", testMergeParameters.Number, prBranchName); var refSpecList = new List <string> { refSpec }; var logMessage = String.Format(CultureInfo.InvariantCulture, "Merge remote pull request #{0}", testMergeParameters.Number); var originalCommit = repository.Head; MergeResult result = null; var sig = new Signature(new Identity(committerName, committerEmail), DateTimeOffset.Now); await Task.Factory.StartNew(() => { try { try { logger.LogTrace("Fetching refspec {0}...", refSpec); var remote = repository.Network.Remotes.First(); progressReporter(0); Commands.Fetch((LibGit2Sharp.Repository)repository, remote.Name, refSpecList, new FetchOptions { Prune = true, OnProgress = (a) => !cancellationToken.IsCancellationRequested, OnTransferProgress = (a) => { var percentage = 50 * (((float)a.IndexedObjects + a.ReceivedObjects) / (a.TotalObjects * 2)); progressReporter((int)percentage); return(!cancellationToken.IsCancellationRequested); }, OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, CredentialsProvider = credentialsProvider.GenerateHandler(username, password) }, logMessage); } catch (UserCancelledException) { } cancellationToken.ThrowIfCancellationRequested(); repository.RemoveUntrackedFiles(); cancellationToken.ThrowIfCancellationRequested(); testMergeParameters.PullRequestRevision = repository.Lookup(testMergeParameters.PullRequestRevision ?? localBranchName).Sha; cancellationToken.ThrowIfCancellationRequested(); logger.LogTrace("Merging {0} into {1}...", testMergeParameters.PullRequestRevision.Substring(0, 7), Reference); result = repository.Merge(testMergeParameters.PullRequestRevision, sig, new MergeOptions { CommitOnSuccess = commitMessage == null, FailOnConflict = true, FastForwardStrategy = FastForwardStrategy.NoFastForward, SkipReuc = true, OnCheckoutProgress = (a, completedSteps, totalSteps) => progressReporter(50 + ((int)(((float)completedSteps) / totalSteps * 50))) }); } finally { repository.Branches.Remove(localBranchName); } cancellationToken.ThrowIfCancellationRequested(); if (result.Status == MergeStatus.Conflicts) { var revertTo = originalCommit.CanonicalName ?? originalCommit.Tip.Sha; logger.LogDebug("Merge conflict, aborting and reverting to {0}", revertTo); RawCheckout(revertTo, progressReporter, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); } repository.RemoveUntrackedFiles(); }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false); if (result.Status == MergeStatus.Conflicts) { await eventConsumer.HandleEvent(EventType.RepoMergeConflict, new List <string> { originalCommit.Tip.Sha, testMergeParameters.PullRequestRevision, originalCommit.FriendlyName ?? UnknownReference, prBranchName }, cancellationToken).ConfigureAwait(false); return(null); } if (commitMessage != null && result.Status != MergeStatus.UpToDate) { logger.LogTrace("Committing merge: \"{0}\"...", commitMessage); await Task.Factory.StartNew(() => repository.Commit(commitMessage, sig, sig, new CommitOptions { PrettifyMessage = true }), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false); } await eventConsumer.HandleEvent(EventType.RepoMergePullRequest, new List <string> { testMergeParameters.Number.ToString(), testMergeParameters.PullRequestRevision, testMergeParameters.Comment }, cancellationToken).ConfigureAwait(false); return(result.Status != MergeStatus.NonFastForward); }
/// <inheritdoc /> public async Task <bool?> AddTestMerge(TestMergeParameters testMergeParameters, string committerName, string committerEmail, string username, string password, Action <int> progressReporter, CancellationToken cancellationToken) { if (testMergeParameters == null) { throw new ArgumentNullException(nameof(testMergeParameters)); } if (committerName == null) { throw new ArgumentNullException(nameof(committerName)); } if (committerEmail == null) { throw new ArgumentNullException(nameof(committerEmail)); } if (!IsGitHubRepository) { throw new InvalidOperationException("Test merging is only available on GitHub hosted origin repositories!"); } var commitMessage = String.Format(CultureInfo.InvariantCulture, "Test merge of pull request #{0}{1}{2}", testMergeParameters.Number.Value, testMergeParameters.Comment != null ? Environment.NewLine : String.Empty, testMergeParameters.Comment ?? String.Empty); var prBranchName = String.Format(CultureInfo.InvariantCulture, "pr-{0}", testMergeParameters.Number); var localBranchName = String.Format(CultureInfo.InvariantCulture, "pull/{0}/headrefs/heads/{1}", testMergeParameters.Number, prBranchName); var Refspec = new List <string> { String.Format(CultureInfo.InvariantCulture, "pull/{0}/head:{1}", testMergeParameters.Number, prBranchName) }; var logMessage = String.Format(CultureInfo.InvariantCulture, "Merge remote pull request #{0}", testMergeParameters.Number); var originalCommit = repository.Head; MergeResult result = null; var sig = new Signature(new Identity(committerName, committerEmail), DateTimeOffset.Now); await Task.Factory.StartNew(() => { try { try { var remote = repository.Network.Remotes.First(); Commands.Fetch((LibGit2Sharp.Repository)repository, remote.Name, Refspec, new FetchOptions { Prune = true, OnProgress = (a) => !cancellationToken.IsCancellationRequested, OnTransferProgress = (a) => { var percentage = 100 * (((float)a.IndexedObjects + a.ReceivedObjects) / (a.TotalObjects * 2)); progressReporter?.Invoke((int)percentage); return(!cancellationToken.IsCancellationRequested); }, OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, CredentialsProvider = (a, b, c) => username != null ? (Credentials) new UsernamePasswordCredentials { Username = username, Password = password } : new DefaultCredentials() }, logMessage); } catch (UserCancelledException) { } cancellationToken.ThrowIfCancellationRequested(); testMergeParameters.PullRequestRevision = repository.Lookup(testMergeParameters.PullRequestRevision ?? localBranchName).Sha; cancellationToken.ThrowIfCancellationRequested(); result = repository.Merge(testMergeParameters.PullRequestRevision, sig, new MergeOptions { CommitOnSuccess = commitMessage == null, FailOnConflict = true, FastForwardStrategy = FastForwardStrategy.NoFastForward, SkipReuc = true }); } finally { repository.Branches.Remove(localBranchName); } cancellationToken.ThrowIfCancellationRequested(); if (result.Status == MergeStatus.Conflicts) { RawCheckout(originalCommit.CanonicalName ?? originalCommit.Tip.Sha); cancellationToken.ThrowIfCancellationRequested(); } repository.RemoveUntrackedFiles(); }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false); if (result.Status == MergeStatus.Conflicts) { await eventConsumer.HandleEvent(EventType.RepoMergeConflict, new List <string> { originalCommit.Tip.Sha, testMergeParameters.PullRequestRevision, originalCommit.FriendlyName ?? UnknownReference, prBranchName }, cancellationToken).ConfigureAwait(false); return(false); } if (commitMessage != null) { repository.Commit(commitMessage, sig, sig, new CommitOptions { PrettifyMessage = true }); } return(true); }