Ejemplo n.º 1
0
 /// <inheritdoc />
 public Task <Models.TestMerge> GetTestMerge(
     TestMergeParameters parameters,
     RepositorySettings repositorySettings,
     CancellationToken cancellationToken) => gitRemoteFeatures.GetTestMerge(
     parameters,
     repositorySettings,
     cancellationToken);
        /// <inheritdoc />
        public async Task <Models.TestMerge> GetTestMerge(
            TestMergeParameters parameters,
            RepositorySettings repositorySettings,
            CancellationToken cancellationToken)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }
            if (repositorySettings == null)
            {
                throw new ArgumentNullException(nameof(repositorySettings));
            }

            Models.TestMerge result;
            lock (cachedLookups)
                if (cachedLookups.TryGetValue(parameters, out result))
                {
                    Logger.LogTrace("Using cache for test merge #{0}", parameters.Number);
                }

            if (result == null)
            {
                Logger.LogTrace("Retrieving metadata for test merge #{0}...", parameters.Number);
                result = await GetTestMergeImpl(parameters, repositorySettings, cancellationToken).ConfigureAwait(false);

                lock (cachedLookups)
                    if (!cachedLookups.TryAdd(parameters, result))
                    {
                        Logger.LogError("Race condition on adding test merge #{0}!", parameters.Number);
                    }
            }

            return(result);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
 /// <inheritdoc />
 public Task <Models.TestMerge> GetTestMerge(
     TestMergeParameters parameters,
     Api.Models.Internal.RepositorySettings repositorySettings,
     CancellationToken cancellationToken) => throw new NotSupportedException();
Ejemplo n.º 5
0
        /// <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);
        }
 /// <summary>
 /// Implementation of <see cref="GetTestMerge(TestMergeParameters, RepositorySettings, CancellationToken)"/>.
 /// </summary>
 /// <param name="parameters">The <see cref="TestMergeParameters"/>.</param>
 /// <param name="repositorySettings">The <see cref="RepositorySettings"/>.</param>
 /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
 /// <returns>A <see cref="Task{TResult}"/> resulting in the <see cref="Models.TestMerge"/> of the <paramref name="parameters"/>.</returns>
 protected abstract Task <Models.TestMerge> GetTestMergeImpl(
     TestMergeParameters parameters,
     RepositorySettings repositorySettings,
     CancellationToken cancellationToken);
Ejemplo n.º 7
0
        /// <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);
        }