Exemple #1
0
        /// <summary>
        /// Checks if a given <paramref name="pullRequest"/> is considered mergeable and does so if need be and sets it's commit status
        /// </summary>
        /// <param name="pullRequest">The <see cref="PullRequest"/> to check</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
        /// <returns>A <see cref="Task"/> representing the running operation</returns>
        async Task CheckMergePullRequest(PullRequest pullRequest, CancellationToken cancellationToken)
        {
            using (logger.BeginScope("Checking mergability of pull request #{0}.", pullRequest.Number))
            {
                bool   merge             = true;
                string mergerToken       = null;
                int    rescheduleIn      = 0;
                Task   pendingStatusTask = null;
                try
                {
                    pendingStatusTask = gitHubManager.SetCommitStatus(pullRequest, CommitState.Pending, stringLocalizer["CommitStatusPending"]);
                    for (var I = 0; I < 4 && !pullRequest.Mergeable.HasValue; ++I)
                    {
                        await Task.Delay(I * 1000, cancellationToken).ConfigureAwait(false);

                        logger.LogTrace("Rechecking git mergeablility.");
                        pullRequest = await gitHubManager.GetPullRequest(pullRequest.Number).ConfigureAwait(false);
                    }

                    if (!pullRequest.Mergeable.HasValue || !pullRequest.Mergeable.Value)
                    {
                        logger.LogDebug("Aborted due to lack of mergeablility: {0}", pullRequest.Mergeable);
                        return;
                    }

                    var tasks = new List <Task <AutoMergeStatus> >();
                    foreach (var I in componentProvider.MergeRequirements)
                    {
                        tasks.Add(I.EvaluateFor(pullRequest, cancellationToken));
                    }

                    await Task.WhenAll(tasks).ConfigureAwait(false);

                    bool goodStatus  = true;
                    var  failReasons = new List <string>();
                    foreach (var I in tasks.Select(x => x.Result))
                    {
                        if (I.Progress < I.RequiredProgress && merge)
                        {
                            logger.LogDebug("Aborting merge due to status failure: {0}/{1}", I.Progress, I.RequiredProgress);
                            merge = false;
                            if (I.FailStatusReport)
                            {
                                goodStatus = false;
                                failReasons.AddRange(I.Notes);
                            }
                        }

                        if (I.ReevaluateIn > 0)
                        {
                            if (rescheduleIn == 0)
                            {
                                rescheduleIn = I.ReevaluateIn;
                            }
                            else
                            {
                                rescheduleIn = Math.Min(rescheduleIn, I.ReevaluateIn);
                            }
                        }
                        if (I.MergerAccessToken != null)
                        {
                            if (mergerToken != null)
                            {
                                throw new InvalidOperationException("Multiple AutoMergeResults with MergerAccessTokens!");
                            }
                            mergerToken = I.MergerAccessToken;
                        }
                    }

                    var failReasonMessage = String.Empty;
                    foreach (var I in failReasons)
                    {
                        failReasonMessage = String.Format(CultureInfo.InvariantCulture, "{0}{1}  - {2}", failReasonMessage, Environment.NewLine, I);
                    }

                    await pendingStatusTask.ConfigureAwait(false);

                    await gitHubManager.SetCommitStatus(pullRequest, goodStatus?CommitState.Success : CommitState.Failure, goodStatus?stringLocalizer["CommitStatusSuccess"] : stringLocalizer["CommitStatusFail", failReasonMessage]).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    if (pendingStatusTask.Exception != null && pendingStatusTask.Exception != e)
                    {
                        logger.LogError(e, "Error setting pending status!");
                    }
                    logger.LogDebug(e, "Error occurred. Setting commit state to errored.");
                    try
                    {
                        await gitHubManager.SetCommitStatus(pullRequest, CommitState.Error, stringLocalizer["CommitStatusError", e]).ConfigureAwait(false);
                    }
                    catch (Exception e2)
                    {
                        logger.LogError(e2, "Unable to create error status!");
                    }
                    throw;
                }

                if (merge)
                {
                    if (mergerToken == null)
                    {
                        logger.LogWarning("Not merging due to lack of provided merger token!");
                    }
                    else
                    {
                        await MergePullRequest(pullRequest, mergerToken, cancellationToken).ConfigureAwait(false);

                        return;
                    }
                }

                if (rescheduleIn > 0)
                {
                    var targetTime = DateTimeOffset.UtcNow.AddSeconds(rescheduleIn);
                    BackgroundJob.Schedule(() => RecheckPullRequest(pullRequest.Number, JobCancellationToken.Null), targetTime);
                    logger.LogDebug("Pull request recheck scheduled for {0}.", targetTime);
                }
                else
                {
                    logger.LogTrace("Not rescheduling pull request check.");
                }
            }
        }