public async Task <IRepositoryConfiguration> GetRepositoryConfigurationAsync(long installationId, long repositoryId, string pullRequestSha, CancellationToken cancellationToken)
        {
            var repositoryConfigurationCacheKey = $"{installationId}/{repositoryId}_repositoryConfigurationCacheKey"; // HACK: Config is global across all branches at the moment.

            var configuration = await cache.GetOrCreateAsync <IRepositoryConfiguration>(repositoryConfigurationCacheKey, async (entry) =>
            {
                entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(RepositoryConfigurationCacheDurationInSeconds);

                try
                {
                    var client = await gitHubClientProvider.GetInstallationClientAsync(installationId, cancellationToken);
                    await limiter.WaitForGitHubCapacityAsync();
                    var searchResults     = await client.Repository.Content.GetAllContents(repositoryId, "eng/CHECKENFORCER");
                    var configurationFile = searchResults.Single();
                    ThrowIfInvalidFormat(configurationFile);

                    var builder       = new DeserializerBuilder().Build();
                    var configuration = builder.Deserialize <RepositoryConfiguration>(configurationFile.Content);

                    return(configuration);
                }
                catch (NotFoundException) // OK, we just disable if it isn't configured.
                {
                    var configuration = new RepositoryConfiguration()
                    {
                        IsEnabled = false
                    };

                    return(configuration);
                }
            });

            return(configuration);
        }
Esempio n. 2
0
        public async Task <IRepositoryConfiguration> GetRepositoryConfigurationAsync(long installationId, long repositoryId, string pullRequestSha, CancellationToken cancellationToken)
        {
            var cacheKey = $"{installationId}/{repositoryId}"; // HACK: Config is global across all branches at the moment.

            try
            {
                cachedConfigurations.TryGetValue(cacheKey, out RepositoryConfigurationCacheEntry cacheEntry);

                if (cacheEntry?.Fetched.AddSeconds(RepositoryConfigurationCacheDurationInSeconds) > DateTimeOffset.UtcNow)
                {
                    return(cacheEntry.Configuration);
                }

                var client = await gitHubClientProvider.GetInstallationClientAsync(installationId, cancellationToken);

                var searchResults = await client.Repository.Content.GetAllContents(repositoryId, "eng/CHECKENFORCER");

                var configurationFile = searchResults.Single();
                ThrowIfInvalidFormat(configurationFile);

                var builder       = new DeserializerBuilder().Build();
                var configuration = builder.Deserialize <RepositoryConfiguration>(configurationFile.Content);

                cacheEntry = new RepositoryConfigurationCacheEntry(DateTimeOffset.UtcNow, configuration);
                cachedConfigurations.TryAdd(cacheKey, cacheEntry);

                return(configuration);
            }
            catch (NotFoundException) // OK, we just disable if it isn't configured.
            {
                var configuration = new RepositoryConfiguration()
                {
                    IsEnabled = false
                };

                var cacheEntry = new RepositoryConfigurationCacheEntry(DateTimeOffset.UtcNow, configuration);
                cachedConfigurations.TryAdd(cacheKey, cacheEntry);

                return(configuration);
            }
        }
        public async Task <IRepositoryConfiguration> GetRepositoryConfigurationAsync(long installationId, long repositoryId, string pullRequestSha, CancellationToken cancellationToken)
        {
            try
            {
                var client = await gitHubClientProvider.GetInstallationClientAsync(installationId, cancellationToken);

                var searchResults = await client.Repository.Content.GetAllContents(repositoryId, "eng/CHECKENFORCER");

                var configurationFile = searchResults.Single();
                ThrowIfInvalidFormat(configurationFile);

                var builder       = new DeserializerBuilder().Build();
                var configuration = builder.Deserialize <RepositoryConfiguration>(configurationFile.Content);

                return(configuration);
            }
            catch (NotFoundException) // OK, we just disable if it isn't configured.
            {
                return(new RepositoryConfiguration()
                {
                    IsEnabled = false
                });
            }
        }
Esempio n. 4
0
        public async Task Run([TimerTrigger("*/30 * * * * *")] TimerInfo myTimer, ILogger log, CancellationToken cancellationToken)
        {
            log.LogInformation("Fetching tracked pull request tickets.");
            var pullRequestTrackingTickets = await pullRequestTracker.GetTrackedPullRequestsAsync();

            log.LogInformation("Found {ticketCount} pull request tickets.", pullRequestTrackingTickets.Count());

            foreach (var pullRequestTrackingTicket in pullRequestTrackingTickets)
            {
                log.LogInformation(
                    "Processing pull request tracking ticket for installation {installationId} in repository {repositoryId} for pull request number {pullRequestNumber}.",
                    pullRequestTrackingTicket.InstallationId,
                    pullRequestTrackingTicket.RepositoryId,
                    pullRequestTrackingTicket.PullRequestNumber
                    );

                var gitHubClient = await gitHubClientProvider.GetInstallationClientAsync(
                    pullRequestTrackingTicket.InstallationId,
                    cancellationToken
                    );

                await limiter.WaitForGitHubCapacityAsync();

                var pullRequest = await gitHubClient.PullRequest.Get(
                    pullRequestTrackingTicket.RepositoryId,
                    pullRequestTrackingTicket.PullRequestNumber
                    );

                var sha = pullRequest.Head.Sha;
                log.LogInformation(
                    "HEAD SHA for pull request {pullRequestNumber} is {sha}",
                    pullRequestTrackingTicket.PullRequestNumber,
                    sha
                    );

                var configuration = await repositoryConfigurationProvider.GetRepositoryConfigurationAsync(
                    pullRequestTrackingTicket.InstallationId,
                    pullRequestTrackingTicket.RepositoryId,
                    sha,
                    cancellationToken
                    );

                if (configuration.IsEnabled != true)
                {
                    log.LogInformation(
                        "Stopping tracking for pull request {pullRequestNumber} in repository {repositoryId} for installation {installationId} because Check Enforcer is not enabled.",
                        pullRequestTrackingTicket.PullRequestNumber,
                        pullRequestTrackingTicket.RepositoryId,
                        pullRequestTrackingTicket.InstallationId
                        );
                    await pullRequestTracker.StopTrackingPullRequestAsync(pullRequestTrackingTicket);

                    continue;
                }
                else if (pullRequest.State != new StringEnum <ItemState>(ItemState.Open))
                {
                    log.LogInformation(
                        "Stopping tracking for pull request {pullRequestNumber} in repository {repositoryId} for installation {installationId} because it is no longer open.",
                        pullRequestTrackingTicket.PullRequestNumber,
                        pullRequestTrackingTicket.RepositoryId,
                        pullRequestTrackingTicket.InstallationId
                        );
                    await pullRequestTracker.StopTrackingPullRequestAsync(pullRequestTrackingTicket);

                    continue;
                }
                else if (DateTimeOffset.UtcNow < pullRequest.UpdatedAt.AddMinutes(configuration.TimeoutInMinutes))
                {
                    log.LogInformation(
                        "Skipping pull request {pullRequestNumber} in repository {repositoryId} for installation {installationId} because it is still too new.",
                        pullRequestTrackingTicket.PullRequestNumber,
                        pullRequestTrackingTicket.RepositoryId,
                        pullRequestTrackingTicket.InstallationId
                        );
                    continue;
                }
                else
                {
                    await limiter.WaitForGitHubCapacityAsync();

                    var checkRunRepsonse = await gitHubClient.Check.Run.GetAllForReference(pullRequestTrackingTicket.RepositoryId, sha);

                    if (checkRunRepsonse.TotalCount > 0 && checkRunRepsonse.CheckRuns.All((checkRun) => checkRun.Name == globalConfigurationProvider.GetApplicationName()))
                    {
                        log.LogInformation(
                            "Fetching comments for pull request {pullRequestNumber} in repository {repositoryId} for installation {installationId}.",
                            pullRequestTrackingTicket.PullRequestNumber,
                            pullRequestTrackingTicket.RepositoryId,
                            pullRequestTrackingTicket.InstallationId
                            );

                        await limiter.WaitForGitHubCapacityAsync();

                        var issueComments = await gitHubClient.Issue.Comment.GetAllForIssue(pullRequestTrackingTicket.RepositoryId, pullRequestTrackingTicket.PullRequestNumber);

                        log.LogInformation(
                            "Found {commentCount} on pull request {pullRequestNumber} in repository {repositoryId} for installation {installationId}.",
                            issueComments.Count(),
                            pullRequestTrackingTicket.PullRequestNumber,
                            pullRequestTrackingTicket.RepositoryId,
                            pullRequestTrackingTicket.InstallationId
                            );

                        if (issueComments.Any((comment) => comment.User.Login.StartsWith("check-enforcer")))
                        {
                            log.LogInformation(
                                "Stopping tracking {pullRequestNumber} in repository {repositoryId} for installation {installationId} because it already has help comment.",
                                pullRequestTrackingTicket.PullRequestNumber,
                                pullRequestTrackingTicket.RepositoryId,
                                pullRequestTrackingTicket.InstallationId
                                );
                            await pullRequestTracker.StopTrackingPullRequestAsync(pullRequestTrackingTicket);
                        }
                        else
                        {
                            log.LogInformation(
                                "Adding timeout comment to pull request {pullRequestNumber} in repository {repositoryId} for installation {installationId} because it has no check runs.",
                                pullRequestTrackingTicket.PullRequestNumber,
                                pullRequestTrackingTicket.RepositoryId,
                                pullRequestTrackingTicket.InstallationId
                                );

                            await gitHubClient.Issue.Comment.Create(
                                pullRequestTrackingTicket.RepositoryId,
                                pullRequestTrackingTicket.PullRequestNumber,
                                configuration.Message
                                );

                            await pullRequestTracker.StopTrackingPullRequestAsync(pullRequestTrackingTicket);
                        }
                    }
                    else
                    {
                        log.LogInformation(
                            "Stopping tracking pull request {pullRequestNumber} in repository {repositoryId} for installation{installationId} because it has checks.",
                            pullRequestTrackingTicket.PullRequestNumber,
                            pullRequestTrackingTicket.RepositoryId,
                            pullRequestTrackingTicket.InstallationId
                            );
                        await pullRequestTracker.StopTrackingPullRequestAsync(pullRequestTrackingTicket);
                    }
                }
            }
        }