Beispiel #1
0
        protected override async Task HandleCoreAsync(HandlerContext <CheckRunEventPayload> context, CancellationToken cancellationToken)
        {
            var payload = context.Payload;

            var installationId            = payload.Installation.Id;
            var repositoryId              = payload.Repository.Id;
            var sha                       = payload.CheckRun.CheckSuite.HeadSha;
            var distributedLockIdentifier = $"{installationId}/{repositoryId}/{sha}";

            using (var scope = Logger.BeginScope("Processing check-run event on: {distributedLockIdentifier}", distributedLockIdentifier))
            {
                if (payload.CheckRun.Name == this.GlobalConfigurationProvider.GetApplicationName())
                {
                    Logger.LogTrace(
                        SkippedProcessingCheckEnforcerCheckRunEventEventId,
                        "Skipping processing event for: {distributedLockIdentifier}",
                        distributedLockIdentifier
                        );
                }
                else
                {
                    try
                    {
                        if (payload.CheckRun.Status != new StringEnum <CheckStatus>(CheckStatus.Completed))
                        {
                            Logger.LogTrace(
                                SkippedProcessingIncompleteCheckRunEventEventId,
                                "Skipping processing event for: {distributedLockIdentifier}",
                                distributedLockIdentifier
                                );
                            return;
                        }

                        var trapSemaphore  = GetSemaphore($"trap/{distributedLockIdentifier}");
                        var queueSemaphore = GetSemaphore($"queue/{distributedLockIdentifier}");

                        if (trapSemaphore.CurrentCount == 0)
                        {
                            Logger.LogTrace(
                                SkippedProcessingTrapSemaphoreEventId,
                                "Skipped processing check-run event: {distributedLockIdentifier} because semaphore current count was zero."
                                );
                            return;
                        }

                        Logger.LogTrace(
                            WaitingOnTrapSemaphoreEventId,
                            "Waiting on trap semaphore for: {distributedLockIdentifier}",
                            distributedLockIdentifier
                            );

                        var trapWaitSuccessful = await trapSemaphore.WaitAsync(10000, cancellationToken);

                        if (!trapWaitSuccessful)
                        {
                            Logger.LogWarning(
                                WaitOnTrapSemaphoreTimeoutEventId,
                                "Timed out waiting in trap semaphore for: {distributedLockIdentifier}.",
                                distributedLockIdentifier
                                );
                            return;
                        }

                        Logger.LogTrace(
                            WaitingOnQueueSemaphoreEventId,
                            "Waiting on queue semaphore for: {distributedLockIdentifier}",
                            distributedLockIdentifier
                            );

                        var queueWaitSuccessful = await queueSemaphore.WaitAsync(10000, cancellationToken);

                        if (!queueWaitSuccessful)
                        {
                            Logger.LogWarning(
                                WaitOnQueueSemaphoreTimeoutEventId,
                                "Timed out waiting in queue semaphore for: {distributedLockIdentifier}.",
                                distributedLockIdentifier
                                );
                            return;
                        }

                        var configuration = await this.RepositoryConfigurationProvider.GetRepositoryConfigurationAsync(installationId, repositoryId, sha, cancellationToken);

                        if (configuration.IsEnabled)
                        {
                            Logger.LogInformation(
                                CheckEnforcerEnabledEventId,
                                "Check Enforcer was enabled for: {distributedLockIdentifier}.",
                                distributedLockIdentifier
                                );
                        }
                        else
                        {
                            Logger.LogInformation(
                                CheckEnforcerDisabledEventId,
                                "Check Enforcer was disabled for: {distributedLockIdentifier}.",
                                distributedLockIdentifier
                                );
                            return;
                        }

                        Logger.LogTrace(
                            AcquiringDistributedLockEventId,
                            "Acquiring distributed lock for: {distributedLockIdentifier}.",
                            distributedLockIdentifier
                            );

                        var distributedLock        = this.DistributedLockProvider.Create(distributedLockIdentifier);
                        var distributedLockAquired = await distributedLock.AcquireAsync();

                        if (!distributedLockAquired)
                        {
                            Logger.LogWarning(
                                FailedToAcquiredDistributedLockEventId,
                                "Failed to acquire distributed lock for: {distributedLockIdentifier}.",
                                distributedLockIdentifier
                                );

                            // Quickly clean up and get out of here.
                            trapSemaphore.Release();
                            queueSemaphore.Release();
                            return;
                        }

                        Logger.LogTrace(
                            ReleasingSemaphoreEventId,
                            "Releasing trap semaphore for: {distributedLockIdentifier}.",
                            distributedLockIdentifier
                            );

                        trapSemaphore.Release();

                        Logger.LogTrace(
                            ReleasedSemaphoreEventId,
                            "Released trap semaphore for: {distributedLockIdentifier}.",
                            distributedLockIdentifier
                            );

                        Logger.LogInformation(
                            EvaluatingCheckRunEventId,
                            "Evaluating check-run for: {distributedLockIdentifier}.",
                            distributedLockIdentifier
                            );

                        await EvaluatePullRequestAsync(context.Client, installationId, repositoryId, sha, cancellationToken);

                        Logger.LogInformation(
                            EvaluatedCheckRunEventId,
                            "Evaluated check-run for: {distributedLockIdentifier}.",
                            distributedLockIdentifier
                            );

                        Logger.LogTrace(
                            ReleasingDistributedLockEventId,
                            "Releasing distributed lock for: {distributedLockIdentifier}.",
                            distributedLockIdentifier
                            );

                        await distributedLock.ReleaseAsync();

                        Logger.LogTrace(
                            ReleasedDistributedLockEventId,
                            "Released distributed lock for: {distributedLockIdentifier}.",
                            distributedLockIdentifier
                            );

                        Logger.LogTrace(
                            ReleasingSemaphoreEventId,
                            "Releasing queue semaphore for: {distributedLockIdentifier}.",
                            distributedLockIdentifier
                            );

                        queueSemaphore.Release();

                        Logger.LogTrace(
                            ReleasingSemaphoreEventId,
                            "Released queue semaphore for: {distributedLockIdentifier}.",
                            distributedLockIdentifier
                            );
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(
                            CheckRunEventProcessingFailedEventId,
                            ex,
                            "Failed to process check-run event for: {distributedLockIdentifier}",
                            distributedLockIdentifier
                            );

                        // Clear the semaphores.
                        semaphores.TryRemove($"trap/{distributedLockIdentifier}", out SemaphoreSlim _);
                        semaphores.TryRemove($"queue/{distributedLockIdentifier}", out SemaphoreSlim _);

                        throw ex;
                    }
                }
            }
        }
Beispiel #2
0
 protected abstract Task HandleCoreAsync(HandlerContext <T> context, CancellationToken cancellationToken);
Beispiel #3
0
        protected override async Task HandleCoreAsync(HandlerContext <CheckRunEventPayload> context, CancellationToken cancellationToken)
        {
            var payload = context.Payload;

            var installationId = payload.Installation.Id;
            var repositoryId   = payload.Repository.Id;
            var sha            = payload.CheckRun.CheckSuite.HeadSha;
            var runIdentifier  = $"{installationId}/{repositoryId}/{sha}";

            using (var scope = Logger.BeginScope("Processing check-run event on: {runIdentifier}", runIdentifier))
            {
                if (payload.CheckRun.Name == this.GlobalConfigurationProvider.GetApplicationName() && payload.Action == "requested_action" && payload.RequestedAction.Identifier == "evaluate")
                {
                    Logger.LogInformation(
                        "Responding to check run action button: {identifier}.",
                        payload.RequestedAction.Identifier
                        );

                    await EvaluatePullRequestAsync(context.Client, installationId, repositoryId, sha, cancellationToken);
                }
                else if (payload.CheckRun.Name.Contains("("))
                {
                    // HACK: This change short circuits processing of events that come from jobs rather than runs. We
                    //       are leveraging the fact that Azure Pipelines jobs have check names with an opening bracket.
                    //       This is a short term fox to stop the bleeding whilst we figure out a better way to ignore
                    //       notifications from the job level.

                    Logger.LogInformation(
                        "Skipping processing event for: {runIdentifier} because based on the name it is a job, not a run.",
                        runIdentifier
                        );
                }
                else if (payload.CheckRun.Name == this.GlobalConfigurationProvider.GetApplicationName())
                {
                    Logger.LogInformation(
                        "Skipping processing event for: {runIdentifier} because appplication name match.",
                        runIdentifier
                        );
                }
                else if (payload.CheckRun.StartedAt < DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(1)))
                {
                    Logger.LogWarning(
                        "Skipping stake check-run event for: {runIdentifier} because it started {days} ago.",
                        runIdentifier,
                        (DateTimeOffset.UtcNow - payload.CheckRun.StartedAt).Days
                        );
                }
                else if (payload.CheckRun.Conclusion == new StringEnum <CheckConclusion>(CheckConclusion.Neutral))
                {
                    Logger.LogInformation("" +
                                          "Skipping processing event for: {runIdentifier} check-run conclusion is neutral.",
                                          runIdentifier
                                          );
                    return;
                }
                else if (payload.CheckRun.Status != new StringEnum <CheckStatus>(CheckStatus.Completed))
                {
                    Logger.LogInformation(
                        "Skipping processing event for: {runIdentifier} check-run status not completed.",
                        runIdentifier
                        );
                    return;
                }
                else
                {
                    try
                    {
                        var configuration = await this.RepositoryConfigurationProvider.GetRepositoryConfigurationAsync(installationId, repositoryId, sha, cancellationToken);

                        if (configuration.IsEnabled)
                        {
                            Logger.LogInformation(
                                "Check Enforcer was enabled for: {runIdentifier}.",
                                runIdentifier
                                );
                        }
                        else
                        {
                            Logger.LogInformation(
                                "Check Enforcer was disabled for: {runIdentifier}.",
                                runIdentifier
                                );
                            return;
                        }

                        Logger.LogInformation(
                            "Evaluating check-run for: {runIdentifier}.",
                            runIdentifier
                            );

                        await EvaluatePullRequestAsync(context.Client, installationId, repositoryId, sha, cancellationToken);

                        Logger.LogInformation(
                            "Evaluated check-run for: {runIdentifier}.",
                            runIdentifier
                            );
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(
                            ex,
                            "Failed to process check-run event for: {runIdentifier}",
                            runIdentifier
                            );

                        throw ex;
                    }
                }
            }
        }
Beispiel #4
0
        protected override async Task HandleCoreAsync(HandlerContext <CheckRunEventPayload> context, CancellationToken cancellationToken)
        {
            var payload = context.Payload;

            var installationId = payload.Installation.Id;
            var repositoryId   = payload.Repository.Id;
            var sha            = payload.CheckRun.CheckSuite.HeadSha;
            var runIdentifier  = $"{installationId}/{repositoryId}/{sha}";

            using (var scope = Logger.BeginScope("Processing check-run event on: {runIdentifier}", runIdentifier))
            {
                if (payload.CheckRun.Name == this.GlobalConfigurationProvider.GetApplicationName() && payload.Action == "requested_action" && payload.RequestedAction.Identifier == "evaluate")
                {
                    Logger.LogInformation(
                        "Responding to check run action button: {identifier}.",
                        payload.RequestedAction.Identifier
                        );

                    await EvaluatePullRequestAsync(context.Client, installationId, repositoryId, sha, cancellationToken);
                }
                else if (payload.CheckRun.Name == this.GlobalConfigurationProvider.GetApplicationName())
                {
                    Logger.LogInformation(
                        "Skipping processing event for: {runIdentifier} because appplication name match.",
                        runIdentifier
                        );
                }
                else if (payload.CheckRun.StartedAt < DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(1)))
                {
                    Logger.LogWarning(
                        "Skipping stake check-run event for: {runIdentifier} because it started {days} ago.",
                        runIdentifier,
                        (DateTimeOffset.UtcNow - payload.CheckRun.StartedAt).Days
                        );
                }
                else
                {
                    try
                    {
                        if (payload.CheckRun.Status != new StringEnum <CheckStatus>(CheckStatus.Completed))
                        {
                            Logger.LogInformation(
                                "Skipping processing event for: {runIdentifier} check-run status not completed.",
                                runIdentifier
                                );
                            return;
                        }

                        var configuration = await this.RepositoryConfigurationProvider.GetRepositoryConfigurationAsync(installationId, repositoryId, sha, cancellationToken);

                        if (configuration.IsEnabled)
                        {
                            Logger.LogInformation(
                                "Check Enforcer was enabled for: {runIdentifier}.",
                                runIdentifier
                                );
                        }
                        else
                        {
                            Logger.LogInformation(
                                "Check Enforcer was disabled for: {runIdentifier}.",
                                runIdentifier
                                );
                            return;
                        }

                        Logger.LogInformation(
                            "Evaluating check-run for: {runIdentifier}.",
                            runIdentifier
                            );

                        await EvaluatePullRequestAsync(context.Client, installationId, repositoryId, sha, cancellationToken);

                        Logger.LogInformation(
                            "Evaluated check-run for: {runIdentifier}.",
                            runIdentifier
                            );
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(
                            ex,
                            "Failed to process check-run event for: {runIdentifier}",
                            runIdentifier
                            );

                        throw ex;
                    }
                }
            }
        }
Beispiel #5
0
        protected override async Task HandleCoreAsync(HandlerContext <CheckRunEventPayload> context, CancellationToken cancellationToken)
        {
            var payload = context.Payload;

            var installationId = payload.Installation.Id;
            var repositoryId   = payload.Repository.Id;
            var sha            = payload.CheckRun.CheckSuite.HeadSha;
            var runIdentifier  = $"{installationId}/{repositoryId}/{sha}";

            using (var scope = Logger.BeginScope("Processing check-run event on: {runIdentifier}", runIdentifier))
            {
                if (payload.CheckRun.Name == this.GlobalConfigurationProvider.GetApplicationName())
                {
                    Logger.LogInformation(
                        SkippedProcessingCheckEnforcerCheckRunEventEventId,
                        "Skipping processing event for: {runIdentifier} because appplication name match.",
                        runIdentifier
                        );
                }
                else
                {
                    try
                    {
                        if (payload.CheckRun.Status != new StringEnum <CheckStatus>(CheckStatus.Completed))
                        {
                            Logger.LogInformation(
                                SkippedProcessingIncompleteCheckRunEventEventId,
                                "Skipping processing event for: {runIdentifier} check-run status not completed.",
                                runIdentifier
                                );
                            return;
                        }

                        var configuration = await this.RepositoryConfigurationProvider.GetRepositoryConfigurationAsync(installationId, repositoryId, sha, cancellationToken);

                        if (configuration.IsEnabled)
                        {
                            Logger.LogInformation(
                                CheckEnforcerEnabledEventId,
                                "Check Enforcer was enabled for: {runIdentifier}.",
                                runIdentifier
                                );
                        }
                        else
                        {
                            Logger.LogInformation(
                                CheckEnforcerDisabledEventId,
                                "Check Enforcer was disabled for: {runIdentifier}.",
                                runIdentifier
                                );
                            return;
                        }

                        Logger.LogInformation(
                            EvaluatingCheckRunEventId,
                            "Evaluating check-run for: {runIdentifier}.",
                            runIdentifier
                            );

                        await EvaluatePullRequestAsync(context.Client, installationId, repositoryId, sha, cancellationToken);

                        Logger.LogInformation(
                            EvaluatedCheckRunEventId,
                            "Evaluated check-run for: {runIdentifier}.",
                            runIdentifier
                            );
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(
                            CheckRunEventProcessingFailedEventId,
                            ex,
                            "Failed to process check-run event for: {runIdentifier}",
                            runIdentifier
                            );

                        throw ex;
                    }
                }
            }
        }
        protected override async Task HandleCoreAsync(HandlerContext <IssueCommentPayload> context, CancellationToken cancellationToken)
        {
            var payload        = context.Payload;
            var installationId = payload.Installation.Id;
            var repositoryId   = payload.Repository.Id;
            var comment        = payload.Comment.Body.ToLower();
            var issueId        = payload.Issue.Number;

            // Bail early if we aren't even a check enforcer comment. Reduces exception noise.
            if (!comment.StartsWith("/check-enforcer"))
            {
                return;
            }

            var pullRequest = await context.Client.PullRequest.Get(repositoryId, issueId);

            var sha = pullRequest.Head.Sha;

            var distributedLockIdentifier = $"{installationId}/{repositoryId}/{sha}";

            using (var distributedLock = DistributedLockProvider.Create(distributedLockIdentifier))
            {
                var distributedLockAcquired = await distributedLock.AcquireAsync();

                if (!distributedLockAcquired)
                {
                    return;
                }

                switch (comment)
                {
                case "/check-enforcer queued":
                    await SetQueuedAsync(context.Client, repositoryId, sha, cancellationToken);

                    break;

                case "/check-enforcer inprogress":
                    await SetInProgressAsync(context.Client, repositoryId, sha, cancellationToken);

                    break;

                case "/check-enforcer success":
                    await SetSuccessAsync(context.Client, repositoryId, sha, cancellationToken);

                    break;

                case "/check-enforcer reset":
                    await CreateCheckAsync(context.Client, repositoryId, sha, true, cancellationToken);

                    break;

                case "/check-enforcer evaluate":
                    await EvaluatePullRequestAsync(context.Client, installationId, repositoryId, sha, cancellationToken);

                    break;

                default:
                    this.Logger.LogTrace("Unrecognized command: {comment}", comment);
                    break;
                }
                await distributedLock.ReleaseAsync();
            }
        }