public async Task GetsCheckRunWithRepositoryId()
            {
                using (var repoContext = await _github.CreateRepositoryContext(new NewRepository(Helper.MakeNameWithTimestamp("public-repo"))
                {
                    AutoInit = true
                }))
                {
                    // Create a new feature branch
                    var headCommit = await _github.Repository.Commit.Get(repoContext.RepositoryId, "master");

                    var featureBranch = await Helper.CreateFeatureBranch(repoContext.RepositoryOwner, repoContext.RepositoryName, headCommit.Sha, "my-feature");

                    // Create a check run for the feature branch
                    var newCheckRun = new NewCheckRun("name", featureBranch.Object.Sha)
                    {
                        Status = CheckStatus.InProgress
                    };
                    var created = await _githubAppInstallation.Check.Run.Create(repoContext.RepositoryId, newCheckRun);

                    // Get the check
                    var checkRun = await _githubAppInstallation.Check.Run.Get(repoContext.RepositoryId, created.Id);

                    // Check result
                    Assert.Equal(featureBranch.Object.Sha, checkRun.HeadSha);
                    Assert.Equal("name", checkRun.Name);
                    Assert.Equal(CheckStatus.InProgress, checkRun.Status);
                }
            }
예제 #2
0
        private async void Process_pull_requestAsync(JToken pull_request)
        {
            // todo: read comments from repo /org admins though for things like
            // "I approve this" and then approve the changes and then wait for
            // "merge squashed/rebased/commit" (if enabled on repository).

            // seems I cannot create a status yet???
            var newCheckRun = new NewCheckRun("Misc/NEWS", pull_request["head"]["sha"].Value <string>())
            {
                Status = CheckStatus.InProgress
            };
            var check = await Program.client.Check.Run.Create(pull_request["base"]["repo"]["owner"].Value <string>(), pull_request["base"]["repo"]["name"].Value <string>(), newCheckRun);

            var _issue = await Program.client.Issue.Get(pull_request["base"]["repo"]["owner"].Value <string>(), pull_request["base"]["repo"]["name"].Value <string>(), Convert.ToInt32(pull_request["number"].Value <string>()));

            foreach (var label in _issue.Labels)
            {
                if (label.Name != "skip news")
                {
                    var _newCheckRunOutput = new NewCheckRunOutput("Misc/NEWS", "'skip news' label found!");
                    var _checkRunUpdate    = new CheckRunUpdate
                    {
                        Status     = CheckStatus.Completed,
                        Output     = _newCheckRunOutput,
                        Conclusion = CheckConclusion.Success
                    };
                    _ = await Program.client.Check.Run.Update(pull_request["base"]["repo"]["owner"].Value <string>(), pull_request["base"]["repo"]["name"].Value <string>(), check.Id, _checkRunUpdate);

                    return;// label.Name == "skip news";
                }
            }
            var files = await Program.client.PullRequest.Files(pull_request["base"]["repo"]["owner"].Value <string>(), pull_request["base"]["repo"]["name"].Value <string>(), Convert.ToInt32(pull_request["number"].Value <string>()));

            foreach (var file in files)
            {
                if (file.FileName.StartsWith("Misc/NEWS"))
                {
                    var _newCheckRunOutput = new NewCheckRunOutput("Misc/NEWS", "Misc/NEWS entry found!");
                    var _checkRunUpdate    = new CheckRunUpdate
                    {
                        Status     = CheckStatus.Completed,
                        Output     = _newCheckRunOutput,
                        Conclusion = CheckConclusion.Success
                    };
                    _ = await Program.client.Check.Run.Update(pull_request["base"]["repo"]["owner"].Value <string>(), pull_request["base"]["repo"]["name"].Value <string>(), check.Id, _checkRunUpdate);

                    return; // !file[:filename].starts_with ? ("Misc/NEWS");
                }
            }

            var newCheckRunOutput = new NewCheckRunOutput("Misc/NEWS", "Misc/NEWS entry not found and 'skip news' is not added!");
            var checkRunUpdate    = new CheckRunUpdate
            {
                Status     = CheckStatus.Completed,
                Output     = newCheckRunOutput,
                Conclusion = CheckConclusion.Failure
            };

            _ = await Program.client.Check.Run.Update(pull_request["base"]["repo"]["owner"].Value <string>(), pull_request["base"]["repo"]["name"].Value <string>(), check.Id, checkRunUpdate);
        }
            public async Task GetsAllAnnotationsWithRepositoryId()
            {
                using (var repoContext = await _github.CreateRepositoryContext(new NewRepository(Helper.MakeNameWithTimestamp("public-repo"))
                {
                    AutoInit = true
                }))
                {
                    // Create a new feature branch
                    var headCommit = await _github.Repository.Commit.Get(repoContext.RepositoryId, "master");

                    var featureBranch = await Helper.CreateFeatureBranch(repoContext.RepositoryOwner, repoContext.RepositoryName, headCommit.Sha, "my-feature");

                    // Create a check run for the feature branch
                    var newCheckRun = new NewCheckRun("name", featureBranch.Object.Sha)
                    {
                        Status = CheckStatus.InProgress,
                        Output = new NewCheckRunOutput("title", "summary")
                        {
                            Annotations = new[]
                            {
                                new NewCheckRunAnnotation("file.txt", "blob", 1, 1, CheckWarningLevel.Warning, "this is a warning")
                            }
                        }
                    };
                    var created = await _githubAppInstallation.Check.Run.Create(repoContext.RepositoryId, newCheckRun);

                    // Get the annotations
                    var annotations = await _githubAppInstallation.Check.Run.GetAllAnnotations(repoContext.RepositoryId, created.Id).ToList();

                    // Check result
                    Assert.Equal(1, annotations.Count);
                    Assert.Equal("this is a warning", annotations.First().Message);
                    Assert.Equal(CheckWarningLevel.Warning, annotations.First().WarningLevel);
                }
            }
            public async Task UpdatesCheckRun()
            {
                using (var repoContext = await _github.CreateRepositoryContext(new NewRepository(Helper.MakeNameWithTimestamp("public-repo"))
                {
                    AutoInit = true
                }))
                {
                    // Create a new feature branch
                    var headCommit = await _github.Repository.Commit.Get(repoContext.RepositoryId, "master");

                    var featureBranch = await Helper.CreateFeatureBranch(repoContext.RepositoryOwner, repoContext.RepositoryName, headCommit.Sha, "my-feature");

                    // Create a check run for the feature branch
                    var newCheckRun = new NewCheckRun("name", featureBranch.Object.Sha)
                    {
                        Status = CheckStatus.Queued
                    };
                    var checkRun = await _githubAppInstallation.Check.Run.Create(repoContext.RepositoryOwner, repoContext.RepositoryName, newCheckRun);

                    // Update the check run
                    var update = new CheckRunUpdate("new-name")
                    {
                        Status = CheckStatus.InProgress
                    };
                    var result = await _githubAppInstallation.Check.Run.Update(repoContext.RepositoryOwner, repoContext.RepositoryName, checkRun.Id, update);

                    // Check result
                    Assert.NotNull(result);
                    Assert.Equal(featureBranch.Object.Sha, result.HeadSha);
                    Assert.Equal("new-name", result.Name);
                    Assert.Equal(CheckStatus.InProgress, result.Status);
                }
            }
예제 #5
0
        /// <summary>
        /// Creates a new check run for a specific commit in a repository
        /// </summary>
        /// <remarks>
        /// See the <a href="https://developer.github.com/v3/checks/runs/#create-a-check-run">Check Runs API documentation</a> for more information.
        /// </remarks>
        /// <param name="owner">The owner of the repository</param>
        /// <param name="name">The name of the repository</param>
        /// <param name="newCheckRun">Details of the Check Run to create</param>
        public IObservable <CheckRun> Create(string owner, string name, NewCheckRun newCheckRun)
        {
            Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
            Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
            Ensure.ArgumentNotNull(newCheckRun, nameof(newCheckRun));

            return(_client.Create(owner, name, newCheckRun).ToObservable());
        }
        /// <summary>
        ///     Create a NewCheckRun based on the result of the merge policy
        /// </summary>
        /// <param name="result">The evaluation of the merge policy</param>
        /// <param name="sha">Sha of the latest commit</param>
        /// <returns>The new check run</returns>
        private NewCheckRun CheckRunForAdd(MergePolicyEvaluationResult result, string sha)
        {
            var newCheckRun = new NewCheckRun($"{MergePolicyConstants.MaestroMergePolicyDisplayName} - {result.MergePolicyInfo.DisplayName}", sha);

            newCheckRun.ExternalId = CheckRunId(result, sha);
            UpdateCheckRun(newCheckRun, result);
            return(newCheckRun);
        }
예제 #7
0
        /// <inheritdoc />
        public async Task <long> CreateCheckRun(long repositoryId, NewCheckRun initializer, CancellationToken cancellationToken)
        {
            logger.LogTrace("Create check run for ref {0} on repository {1}", initializer.HeadSha, repositoryId);
            var client = await CreateInstallationClient(repositoryId, cancellationToken).ConfigureAwait(false);

            var checkRun = await client.Check.Run.Create(repositoryId, initializer).ConfigureAwait(false);

            return(checkRun.Id);
        }
예제 #8
0
            public async Task EnsuresNonEmptyArguments()
            {
                var gitHubClient = Substitute.For <IGitHubClient>();
                var client       = new ObservableCheckRunsClient(gitHubClient);

                var newCheckRun = new NewCheckRun("status", "123abc")
                {
                    Status = CheckStatus.Queued
                };

                Assert.Throws <ArgumentException>(() => client.Create("", "repo", newCheckRun));
                Assert.Throws <ArgumentException>(() => client.Create("fake", "", newCheckRun));
            }
예제 #9
0
            public async Task RequestsCorrectUrlWithRepositoryId()
            {
                var gitHubClient = Substitute.For <IGitHubClient>();
                var client       = new ObservableCheckRunsClient(gitHubClient);

                var newCheckRun = new NewCheckRun("status", "123abc")
                {
                    Status = CheckStatus.Queued
                };

                client.Create(1, newCheckRun);

                gitHubClient.Check.Run.Received().Create(1, newCheckRun);
            }
예제 #10
0
            public async Task EnsuresNonEmptyArguments()
            {
                var connection = Substitute.For <IApiConnection>();
                var client     = new CheckRunsClient(connection);

                var newCheckRun = new NewCheckRun("status", "123abc")
                {
                    Status = CheckStatus.Queued
                };

                await Assert.ThrowsAsync <ArgumentException>(() => client.Create("", "repo", newCheckRun));

                await Assert.ThrowsAsync <ArgumentException>(() => client.Create("fake", "", newCheckRun));
            }
예제 #11
0
        public async Task PassMergeAsync(MergeData data)
        {
            var client = await GetInstallationClientAsync(data.InstallationId);

            var pr = await client.PullRequest.Get(data.RepositoryOwner, data.RepositoryName, data.PullRequestNumber);

            var prHead = pr.Head;

            var checkRun = new NewCheckRun($"PublishingScheduler Auto-Merge", prHead.Ref);

            checkRun.Status     = CheckStatus.Completed;
            checkRun.Conclusion = CheckConclusion.Success;
            checkRun.Output     = new NewCheckRunOutput($"{data.MergeTime} UTC", $"An auto-merge is scheduled for {data.MergeTime} UTC.");
            await client.Check.Run.Create(data.RepositoryOwner, data.RepositoryName, checkRun);
        }
예제 #12
0
            public async Task RequestsCorrectUrlWithRepositoryId()
            {
                var connection = Substitute.For <IApiConnection>();
                var client     = new CheckRunsClient(connection);

                var newCheckRun = new NewCheckRun("status", "123abc")
                {
                    Status = CheckStatus.Queued
                };

                await client.Create(1, newCheckRun);

                connection.Received().Post <CheckRun>(
                    Arg.Is <Uri>(u => u.ToString() == "repositories/1/check-runs"),
                    newCheckRun,
                    "application/vnd.github.antiope-preview+json");
            }
예제 #13
0
        /// <inheritdoc/>
        protected override async Task <object> CallGitHubApi(DialogContext dc, Octokit.GitHubClient gitHubClient, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (Owner != null && Name != null && NewCheckRun != null)
            {
                var ownerValue       = Owner.GetValue(dc.State);
                var nameValue        = Name.GetValue(dc.State);
                var newCheckRunValue = NewCheckRun.GetValue(dc.State);
                return(await gitHubClient.Check.Run.Create(ownerValue, nameValue, newCheckRunValue).ConfigureAwait(false));
            }
            if (RepositoryId != null && NewCheckRun != null)
            {
                var repositoryIdValue = RepositoryId.GetValue(dc.State);
                var newCheckRunValue  = NewCheckRun.GetValue(dc.State);
                return(await gitHubClient.Check.Run.Create((Int64)repositoryIdValue, newCheckRunValue).ConfigureAwait(false));
            }

            throw new ArgumentNullException("Required [newCheckRun] arguments missing for GitHubClient.Check.Run.Create");
        }
        /// <summary>
        ///     Create some properties of a NewCheckRun
        /// </summary>
        /// <param name="newCheckRun">The NewCheckRun that needs to be created</param>
        /// <param name="result">The result of that new check run</param>
        private void UpdateCheckRun(NewCheckRun newCheckRun, MergePolicyEvaluationResult result)
        {
            var output = FormatOutput(result);

            newCheckRun.Output = output;
            newCheckRun.Status = CheckStatus.Completed;

            if (result.Status == MergePolicyEvaluationStatus.Pending)
            {
                newCheckRun.Status = CheckStatus.InProgress;
            }
            else if (result.Status == MergePolicyEvaluationStatus.Success)
            {
                newCheckRun.Conclusion  = "success";
                newCheckRun.CompletedAt = DateTime.Now;
            }
            else
            {
                newCheckRun.Conclusion  = "failure";
                newCheckRun.CompletedAt = DateTime.UtcNow;
            }
        }
            public async Task GetsAllCheckRuns()
            {
                using (var repoContext = await _github.CreateRepositoryContext(new NewRepository(Helper.MakeNameWithTimestamp("public-repo"))
                {
                    AutoInit = true
                }))
                {
                    // Create a new feature branch
                    var headCommit = await _github.Repository.Commit.Get(repoContext.RepositoryId, "master");

                    var featureBranch = await Helper.CreateFeatureBranch(repoContext.RepositoryOwner, repoContext.RepositoryName, headCommit.Sha, "my-feature");

                    // Create a check run for the feature branch
                    var newCheckRun = new NewCheckRun("name", featureBranch.Object.Sha)
                    {
                        Status = CheckStatus.InProgress
                    };
                    await _githubAppInstallation.Check.Run.Create(repoContext.RepositoryOwner, repoContext.RepositoryName, newCheckRun);

                    // Get the check
                    var request = new CheckRunRequest
                    {
                        CheckName = "name",
                        Status    = CheckStatusFilter.InProgress
                    };
                    var checkRuns = await _githubAppInstallation.Check.Run.GetAllForReference(repoContext.RepositoryOwner, repoContext.RepositoryName, featureBranch.Object.Sha, request);

                    // Check result
                    Assert.NotEmpty(checkRuns.CheckRuns);
                    foreach (var checkRun in checkRuns.CheckRuns)
                    {
                        Assert.Equal(featureBranch.Object.Sha, checkRun.HeadSha);
                        Assert.Equal("name", checkRun.Name);
                        Assert.Equal(CheckStatus.InProgress, checkRun.Status);
                    }
                }
            }
예제 #16
0
        /// <summary>
        /// Generates a icon diff for the specified <see cref="PullRequest"/>
        /// </summary>
        /// <param name="repositoryId">The <see cref="PullRequest.Base"/> <see cref="Repository.Id"/></param>
        /// <param name="pullRequestNumber">The <see cref="PullRequest.Number"/></param>
        /// <param name="installationId">The <see cref="InstallationId.Id"/></param>
        /// <param name="scope">The <see cref="IServiceScope"/> for the operation</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
        /// <returns>A <see cref="Task"/> representing the running operation</returns>
        async Task ScanPullRequestImpl(long repositoryId, int pullRequestNumber, long installationId, IServiceScope scope, CancellationToken cancellationToken)
        {
            long?       checkRunId  = null;
            PullRequest pullRequest = null;
            Task <IReadOnlyList <PullRequestFile> > allChangedFilesTask = null;
            var gitHubManager = scope.ServiceProvider.GetRequiredService <IGitHubManager>();

            async Task RunCheck()
            {
                if (pullRequest == null)
                {
                    pullRequest = await gitHubManager.GetPullRequest(repositoryId, installationId, pullRequestNumber, cancellationToken).ConfigureAwait(false);

                    logger.LogTrace("Repository is {0}/{1}", pullRequest.Base.Repository.Owner.Login, pullRequest.Base.Repository.Name);
                    logger.LogTrace("Pull Request: \"{0}\" by {1}", pullRequest.Title, pullRequest.User.Login);
                }

                if (allChangedFilesTask == null || allChangedFilesTask.IsFaulted)
                {
                    allChangedFilesTask = gitHubManager.GetPullRequestChangedFiles(pullRequest, installationId, cancellationToken);
                }

                if (!checkRunId.HasValue)
                {
                    var ncr = new NewCheckRun(String.Format(CultureInfo.InvariantCulture, "Diffs - Pull Request #{0}", pullRequest.Number), pullRequest.Head.Sha)
                    {
                        StartedAt = DateTimeOffset.Now,
                        Status    = CheckStatus.Queued
                    };

                    checkRunId = await gitHubManager.CreateCheckRun(repositoryId, installationId, ncr, cancellationToken).ConfigureAwait(false);
                }

                var allChangedFiles = await allChangedFilesTask.ConfigureAwait(false);

                var changedDmis = allChangedFiles.Where(x => x.FileName.EndsWith(".dmi", StringComparison.InvariantCultureIgnoreCase)).ToList();

                if (changedDmis.Count == 0)
                {
                    logger.LogDebug("Pull request has no changed .dmis, exiting");

                    await gitHubManager.UpdateCheckRun(repositoryId, installationId, checkRunId.Value, new CheckRunUpdate
                    {
                        CompletedAt = DateTimeOffset.Now,
                        Status      = CheckStatus.Completed,
                        Conclusion  = CheckConclusion.Neutral,
                        Output      = new NewCheckRunOutput(stringLocalizer["No Modified Icons"], stringLocalizer["No modified .dmi files were detected in this pull request"])
                    }, cancellationToken).ConfigureAwait(false);

                    return;
                }

                logger.LogTrace("Pull request has icon changes, creating check run");

                await GenerateDiffs(pullRequest, installationId, checkRunId.Value, changedDmis, scope, cancellationToken).ConfigureAwait(false);
            };

            try
            {
                try
                {
                    for (var I = 0; I <= NotFoundRetryAttempts; ++I)
                    {
                        try
                        {
                            await RunCheck().ConfigureAwait(false);

                            break;
                        }
                        catch (NotFoundException)
                        {
                            //chance for spurious github failures
                            if (I == NotFoundRetryAttempts)
                            {
                                throw;
                            }
                            await Task.Delay(NotFoundRetryDelay, cancellationToken).ConfigureAwait(false);
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception e)
                {
                    if (!checkRunId.HasValue)
                    {
                        throw;
                    }
                    logger.LogDebug(e, "Error occurred. Attempting to post debug comment");
                    try
                    {
                        await gitHubManager.UpdateCheckRun(repositoryId, installationId, checkRunId.Value, new CheckRunUpdate
                        {
                            CompletedAt = DateTimeOffset.Now,
                            Status      = CheckStatus.Completed,
                            Conclusion  = CheckConclusion.Failure,
                            Output      = new NewCheckRunOutput(stringLocalizer["Error generating diffs!"], stringLocalizer["Exception details:\n\n```\n{0}\n```\n\nPlease report this [here]({1})", e.ToString(), IssueReportUrl])
                        }, default).ConfigureAwait(false);
                    }
                    catch (Exception innerException)
                    {
                        throw new AggregateException(innerException, e);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                logger.LogTrace("Operation cancelled");
                if (!checkRunId.HasValue)
                {
                    throw;
                }
                await gitHubManager.UpdateCheckRun(repositoryId, installationId, checkRunId.Value, new CheckRunUpdate
                {
                    CompletedAt = DateTimeOffset.Now,
                    Status      = CheckStatus.Completed,
                    Conclusion  = CheckConclusion.Neutral,
                    Output      = new NewCheckRunOutput(stringLocalizer["Operation Cancelled"], stringLocalizer["The operation was cancelled on the server, most likely due to app shutdown. You may attempt re-running it."])
                }, default).ConfigureAwait(false);
            }
        }
        /// <inheritdoc />
        public async Task <CheckRun> CreateCheckRunAsync(string owner, string repository, string sha,
                                                         string checkRunName,
                                                         string checkRunTitle, string checkRunSummary, bool checkRunIsSuccess, Annotation[] annotations,
                                                         DateTimeOffset?startedAt,
                                                         DateTimeOffset?completedAt)
        {
            if (owner == null)
            {
                throw new ArgumentNullException(nameof(owner));
            }
            if (repository == null)
            {
                throw new ArgumentNullException(nameof(repository));
            }
            if (sha == null)
            {
                throw new ArgumentNullException(nameof(sha));
            }
            if (checkRunTitle == null)
            {
                throw new ArgumentNullException(nameof(checkRunTitle));
            }
            if (checkRunSummary == null)
            {
                throw new ArgumentNullException(nameof(checkRunSummary));
            }

            if ((annotations?.Length ?? 0) > 50)
            {
                throw new ArgumentException("Cannot create more than 50 annotations at a time");
            }

            var gitHubClient = await _gitHubAppClientFactory.CreateAppClientForLoginAsync(_tokenGenerator, owner);

            var checkRunsClient = gitHubClient?.Check?.Run;

            if (checkRunsClient == null)
            {
                throw new InvalidOperationException("ICheckRunsClient is null");
            }

            var newCheckRun = new NewCheckRun(checkRunName, sha)
            {
                Output = new NewCheckRunOutput(checkRunTitle, checkRunSummary)
                {
                    Annotations = annotations?
                                  .Select(annotation => new NewCheckRunAnnotation(annotation.Filename, annotation.BlobHref,
                                                                                  annotation.LineNumber, annotation.EndLine, GetCheckWarningLevel(annotation),
                                                                                  annotation.Message))
                                  .ToArray()
                },
                Status      = CheckStatus.Completed,
                StartedAt   = startedAt,
                CompletedAt = completedAt,
                Conclusion  = checkRunIsSuccess ? CheckConclusion.Success : CheckConclusion.Failure
            };

            var checkRun = await checkRunsClient.Create(owner, repository, newCheckRun);

            return(new CheckRun
            {
                Id = checkRun.Id,
                Url = checkRun.HtmlUrl,
            });
        }
예제 #18
0
        /// <summary>
        /// Creates a new check run for a specific commit in a repository
        /// </summary>
        /// <remarks>
        /// See the <a href="https://developer.github.com/v3/checks/runs/#create-a-check-run">Check Runs API documentation</a> for more information.
        /// </remarks>
        /// <param name="repositoryId">The Id of the repository</param>
        /// <param name="newCheckRun">Details of the Check Run to create</param>
        public IObservable <CheckRun> Create(long repositoryId, NewCheckRun newCheckRun)
        {
            Ensure.ArgumentNotNull(newCheckRun, nameof(newCheckRun));

            return(_client.Create(repositoryId, newCheckRun).ToObservable());
        }
예제 #19
0
        public async Task ScanPullRequest(long repositoryId, int pullRequestNumber, IJobCancellationToken jobCancellationToken)
        {
            using (logger.BeginScope("Scanning pull request #{0} for repository {1}", pullRequestNumber, repositoryId))
                using (serviceProvider.CreateScope())
                {
                    var cancellationToken = jobCancellationToken.ShutdownToken;
                    var gitHubManager     = serviceProvider.GetRequiredService <IGitHubManager>();
                    var pullRequest       = await gitHubManager.GetPullRequest(repositoryId, pullRequestNumber, cancellationToken).ConfigureAwait(false);

                    logger.LogTrace("Repository is {0}/{1}", pullRequest.Base.Repository.Owner.Login, pullRequest.Base.Repository.Name);
                    logger.LogTrace("Pull Request: \"{0}\" by {1}", pullRequest.Title, pullRequest.User.Login);

                    var changedMapsTask   = gitHubManager.GetPullRequestChangedFiles(pullRequest, cancellationToken);
                    var requestIdentifier = String.Concat(pullRequest.Base.Repository.Owner.Login, pullRequest.Base.Repository.Name, pullRequest.Number);

                    var ncr = new NewCheckRun
                    {
                        HeadSha   = pullRequest.Head.Sha,
                        Name      = String.Format(CultureInfo.InvariantCulture, "Renderings - Pull Request #{0}", pullRequest.Number),
                        StartedAt = DateTimeOffset.Now,
                        Status    = CheckStatus.Queued
                    };
                    var checkRunId = await gitHubManager.CreateCheckRun(repositoryId, ncr, cancellationToken).ConfigureAwait(false);

                    Task HandleCancel() => gitHubManager.UpdateCheckRun(repositoryId, checkRunId, new CheckRunUpdate
                    {
                        CompletedAt = DateTimeOffset.Now,
                        Status      = CheckStatus.Completed,
                        Conclusion  = CheckConclusion.Neutral,
                        Output      = new CheckRunOutput(stringLocalizer["Operation Cancelled"], stringLocalizer["The operation was cancelled on the server, most likely due to app shutdown. You may attempt re-running it."], null, null, null)
                    }, default);

                    try
                    {
                        for (var I = 0; !pullRequest.Mergeable.HasValue && I < 5; cancellationToken.ThrowIfCancellationRequested(), cancellationToken.ThrowIfCancellationRequested(), ++I)
                        {
                            if (I == 0)
                            {
                                logger.LogTrace("Null mergable state on pull request, refreshing for a maximum of 10s");
                            }
                            await Task.Delay(1000 *I, cancellationToken).ConfigureAwait(false);

                            pullRequest = await gitHubManager.GetPullRequest(pullRequest.Base.Repository.Id, pullRequest.Number, cancellationToken).ConfigureAwait(false);;
                        }

                        if (!pullRequest.Mergeable.HasValue || !pullRequest.Mergeable.Value)
                        {
                            logger.LogDebug("Pull request unmergeable, aborting scan");
                            await gitHubManager.UpdateCheckRun(repositoryId, checkRunId, new CheckRunUpdate
                            {
                                CompletedAt = DateTimeOffset.Now,
                                Status      = CheckStatus.Completed,
                                Conclusion  = CheckConclusion.Failure,
                                Output      = new CheckRunOutput(stringLocalizer["Merge Conflict"], stringLocalizer["Unable to render pull requests in an unmergeable state"], null, null, null)
                            }, cancellationToken).ConfigureAwait(false);

                            return;
                        }

                        var allChangedMaps = await changedMapsTask.ConfigureAwait(false);

                        var changedDmms = allChangedMaps.Where(x => x.FileName.EndsWith(".dmm", StringComparison.InvariantCultureIgnoreCase)).Select(x => x.FileName).ToList();
                        if (changedDmms.Count == 0)
                        {
                            logger.LogDebug("Pull request has no changed maps, exiting");

                            await gitHubManager.UpdateCheckRun(repositoryId, checkRunId, new CheckRunUpdate
                            {
                                CompletedAt = DateTimeOffset.Now,
                                Status      = CheckStatus.Completed,
                                Conclusion  = CheckConclusion.Neutral,
                                Output      = new CheckRunOutput(stringLocalizer["No Modified Maps"], stringLocalizer["No modified .dmm files were detected in this pull request"], null, null, null)
                            }, cancellationToken).ConfigureAwait(false);

                            return;
                        }

                        logger.LogTrace("Pull request has map changes, creating check run");

                        await GenerateDiffs(pullRequest, checkRunId, changedDmms, cancellationToken).ConfigureAwait(false);
                    }
                    catch (OperationCanceledException)
                    {
                        logger.LogTrace("Operation cancelled");

                        await HandleCancel().ConfigureAwait(false);
                    }
                    catch (Exception e)
                    {
                        logger.LogDebug(e, "Error occurred. Attempting to post debug comment");
                        try
                        {
                            await gitHubManager.UpdateCheckRun(repositoryId, checkRunId, new CheckRunUpdate
                            {
                                CompletedAt = DateTimeOffset.Now,
                                Status      = CheckStatus.Completed,
                                Conclusion  = CheckConclusion.Failure,
                                Output      = new CheckRunOutput(stringLocalizer["Error rendering maps!"], stringLocalizer["Exception details:\n\n```\n{0}\n```\n\nPlease report this [here]({1})", e.ToString(), IssueReportUrl], null, null, null)
                            }, default).ConfigureAwait(false);

                            throw;
                        }
                        catch (OperationCanceledException)
                        {
                            logger.LogTrace("Operation cancelled");
                            await HandleCancel().ConfigureAwait(false);
                        }
                        catch (Exception innerException)
                        {
                            throw new AggregateException(innerException, e);
                        }
                    }
                }
        }
예제 #20
0
 private static async Task TryCreateCheckRun(GitHubClient installationClient, long repositoryId, NewCheckRun checkRun, ILogger logger)
 {
     // Ignore check run failures for now. Check run permissions were added later, so users might not have granted permissions to add check runs.
     try
     {
         await installationClient.Check.Run.Create(repositoryId, checkRun);
     }
     catch (Exception e)
     {
         logger.LogWarning(e, $"Failed to create check run for repository {repositoryId}.");
     }
 }
예제 #21
0
        /// <summary>
        /// Generates a icon diff for the specified <see cref="PullRequest"/>
        /// </summary>
        /// <param name="repositoryId">The <see cref="PullRequest.Base"/> <see cref="Repository.Id"/></param>
        /// <param name="pullRequestNumber">The <see cref="PullRequest.Number"/></param>
        /// <param name="installationId">The <see cref="InstallationId.Id"/></param>
        /// <param name="scope">The <see cref="IServiceScope"/> for the operation</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
        /// <returns>A <see cref="Task"/> representing the running operation</returns>
        async Task ScanPullRequestImpl(long repositoryId, int pullRequestNumber, long installationId, IServiceScope scope, CancellationToken cancellationToken)
        {
            var gitHubManager = scope.ServiceProvider.GetRequiredService <IGitHubManager>();
            var pullRequest   = await gitHubManager.GetPullRequest(repositoryId, installationId, pullRequestNumber, cancellationToken).ConfigureAwait(false);

            logger.LogTrace("Repository is {0}/{1}", pullRequest.Base.Repository.Owner.Login, pullRequest.Base.Repository.Name);
            logger.LogTrace("Pull Request: \"{0}\" by {1}", pullRequest.Title, pullRequest.User.Login);

            var allChangedFilesTask = gitHubManager.GetPullRequestChangedFiles(pullRequest, installationId, cancellationToken);
            var requestIdentifier   = String.Concat(pullRequest.Base.Repository.Owner.Login, pullRequest.Base.Repository.Name, pullRequest.Number);

            var ncr = new NewCheckRun
            {
                HeadSha   = pullRequest.Head.Sha,
                Name      = String.Format(CultureInfo.InvariantCulture, "Diffs - Pull Request #{0}", pullRequest.Number),
                StartedAt = DateTimeOffset.Now,
                Status    = CheckStatus.Queued
            };
            var checkRunId = await gitHubManager.CreateCheckRun(repositoryId, installationId, ncr, cancellationToken).ConfigureAwait(false);

            Task HandleCancel() => gitHubManager.UpdateCheckRun(repositoryId, installationId, checkRunId, new CheckRunUpdate
            {
                CompletedAt = DateTimeOffset.Now,
                Status      = CheckStatus.Completed,
                Conclusion  = CheckConclusion.Neutral,
                Output      = new CheckRunOutput(stringLocalizer["Operation Cancelled"], stringLocalizer["The operation was cancelled on the server, most likely due to app shutdown. You may attempt re-running it."], null, null, null)
            }, default);

            try
            {
                var allChangedFiles = await allChangedFilesTask.ConfigureAwait(false);

                var changedDmis = allChangedFiles.Where(x => x.FileName.EndsWith(".dmi", StringComparison.InvariantCultureIgnoreCase)).Select(x => x.FileName).ToList();
                if (changedDmis.Count == 0)
                {
                    logger.LogDebug("Pull request has no changed .dmis, exiting");

                    await gitHubManager.UpdateCheckRun(repositoryId, installationId, checkRunId, new CheckRunUpdate
                    {
                        CompletedAt = DateTimeOffset.Now,
                        Status      = CheckStatus.Completed,
                        Conclusion  = CheckConclusion.Neutral,
                        Output      = new CheckRunOutput(stringLocalizer["No Modified Icons"], stringLocalizer["No modified .dnu files were detected in this pull request"], null, null, null)
                    }, cancellationToken).ConfigureAwait(false);

                    return;
                }

                logger.LogTrace("Pull request has icon changes, creating check run");

                await GenerateDiffs(pullRequest, installationId, checkRunId, changedDmis, scope, cancellationToken).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
                logger.LogTrace("Operation cancelled");

                await HandleCancel().ConfigureAwait(false);
            }
            catch (Exception e)
            {
                logger.LogDebug(e, "Error occurred. Attempting to post debug comment");
                try
                {
                    await gitHubManager.UpdateCheckRun(repositoryId, installationId, checkRunId, new CheckRunUpdate
                    {
                        CompletedAt = DateTimeOffset.Now,
                        Status      = CheckStatus.Completed,
                        Conclusion  = CheckConclusion.Failure,
                        Output      = new CheckRunOutput(stringLocalizer["Error generating diffs!"], stringLocalizer["Exception details:\n\n```\n{0}\n```\n\nPlease report this [here]({1})", e.ToString(), IssueReportUrl], null, null, null)
                    }, default).ConfigureAwait(false);

                    throw;
                }
                catch (OperationCanceledException)
                {
                    logger.LogTrace("Operation cancelled");
                    await HandleCancel().ConfigureAwait(false);
                }
                catch (Exception innerException)
                {
                    throw new AggregateException(innerException, e);
                }
            }
        }
예제 #22
0
        /// <summary>
        /// Creates a CheckRun in the GitHub Api.
        /// </summary>
        /// <param name="owner">The name of the repository owner.</param>
        /// <param name="repository">The name of the repository.</param>
        /// <param name="sha">The sha we are creating this CheckRun for.</param>
        /// <param name="createCheckRun"></param>
        /// <param name="annotations">Array of Annotations for the CheckRun.</param>
        /// <param name="name">The name of the CheckRun.</param>
        /// <param name="title">The title of the CheckRun.</param>
        /// <param name="summary">The summary of the CheckRun.</param>
        /// <param name="success">If the CheckRun is a success.</param>
        /// <param name="startedAt">The time when processing started</param>
        /// <param name="completedAt">The time when processing finished</param>
        /// <returns></returns>
        public async Task <CheckRun> CreateCheckRunAsync(string owner, string repository, string sha,
                                                         CreateCheckRun createCheckRun, Annotation[] annotations)
        {
            try
            {
                if (owner == null)
                {
                    throw new ArgumentNullException(nameof(owner));
                }
                if (repository == null)
                {
                    throw new ArgumentNullException(nameof(repository));
                }
                if (sha == null)
                {
                    throw new ArgumentNullException(nameof(sha));
                }

                if ((annotations?.Length ?? 0) > 50)
                {
                    throw new ArgumentException("Cannot create more than 50 annotations at a time");
                }

                var gitHubClient = await _gitHubAppClientFactory.CreateAppClientForLoginAsync(_tokenGenerator, owner);

                var checkRunsClient = gitHubClient?.Check?.Run;

                if (checkRunsClient == null)
                {
                    throw new InvalidOperationException("ICheckRunsClient is null");
                }

                var newCheckRun = new NewCheckRun(createCheckRun.Name, sha)
                {
                    Output = new NewCheckRunOutput(createCheckRun.Title, createCheckRun.Summary)
                    {
                        Text   = createCheckRun.Text,
                        Images = createCheckRun.Images?.Select(image => new NewCheckRunImage(image.Alt, image.ImageUrl)
                        {
                            Caption = image.Caption
                        }).ToArray(),
                        Annotations = annotations?
                                      .Select(CreateNewCheckRunAnnotation)
                                      .ToArray()
                    },
                    Status      = CheckStatus.Completed,
                    StartedAt   = createCheckRun.StartedAt,
                    CompletedAt = createCheckRun.CompletedAt,
                    Conclusion  = createCheckRun.Conclusion.ToOctokit()
                };

                var checkRun = await checkRunsClient.Create(owner, repository, newCheckRun);

                return(new CheckRun
                {
                    Id = checkRun.Id,
                    Url = checkRun.HtmlUrl
                });
            }
            catch (Exception ex)
            {
                throw new GitHubAppModelException("Error creating CheckRun.", ex);
            }
        }
예제 #23
0
        private async Task StartExecution()
        {
            IReadOnlyList <Installation> installations = await this.gitHubAppClient.GitHubApps.GetAllInstallationsForCurrent().ConfigureAwait(false);

            try
            {
                if (!this.IsGitHubInstallationClientValid())
                {
                    throw new InvalidOperationException("Error: gitHubInstallationClient is invalid.");
                }

                if (IsPullRequest)
                {
                    ICheckSuitesClient checkSuiteClient = gitHubInstallationClient.Check.Suite;

                    CheckSuitesResponse x = await checkSuiteClient.GetAllForReference(CurrentRepository.Id, CommitSha).ConfigureAwait(false);

                    if (x.TotalCount > 0)
                    {
                        long checkSuiteId = x.CheckSuites.FirstOrDefault().Id;
                        bool res          = await checkSuiteClient.Rerequest(CurrentRepository.Id, checkSuiteId);
                    }
                    else
                    {
                        var newCheckSuite = new NewCheckSuite(CommitSha);
                        try
                        {
                            CheckSuite suite =
                                await checkSuiteClient.Create(
                                    CurrentRepository.Owner.Login,
                                    CurrentRepository.Name, newCheckSuite)
                                .ConfigureAwait(false);
                        }
                        catch (Exception ex)
                        {
                        }
                    }

                    return;
                }

                ICheckRunsClient checkRunClient = gitHubInstallationClient.Check.Run;

                // Create a new heckRun in GitHub
                var newCheckRun = new NewCheckRun("ScanX", CommitSha)
                {
                    Status = CheckStatus.Queued,
                };

                CheckRun checkRun =
                    await checkRunClient.Create(
                        CurrentRepository.Owner.Login,
                        CurrentRepository.Name,
                        newCheckRun)
                    .ConfigureAwait(false);

                // --- Downoad a ZIP ---
                byte[] buffer = await ScanHelper.DownloadRepoZip(gitHubInstallationClient, CurrentRepository.Id, CommitSha).ConfigureAwait(false);

                int size = buffer.Length;

                // Upload ZIP to a storage blob
                string blobName = $"{RequestId.ToString()}";
                string blobUri  = await ScanHelper.UploadBufferToStorage(buffer, blobName);

                // Update check's status to "in progress"
                CheckRunUpdate checkRunUpdate = new CheckRunUpdate
                {
                    Status = CheckStatus.InProgress,
                    Name   = checkRun.Name
                };
                checkRun = await checkRunClient.Update(CurrentRepository.Id, checkRun.Id, checkRunUpdate).ConfigureAwait(false);

                // --- Start a scan ---
                // Simulate sending of a message to a SB queue
                // Create worker notification message
                MalwareDeterminationRequest scanRequest = new MalwareDeterminationRequest();
                scanRequest.ClientId        = "GitHubScanX";
                scanRequest.FileName        = $"{RequestId.ToString()}.zip";
                scanRequest.FileSizeInBytes = 1000; //dummy
                scanRequest.RequestId       = RequestId;
                scanRequest.Uri             = new Uri(blobUri);

                // Notify worker (aka put the notification message to a queue)
                ScanXMock mock = new ScanXMock();
                await mock.SendScanRequest(scanRequest).ConfigureAwait(false);

                // --- Poll for a scan completion ---
                MalwareDeterminationResult scanResult;
                do
                {
                    await Task.Delay(500).ConfigureAwait(false);

                    if (await mock.TryGetResult(RequestId))
                    {
                        scanResult = await mock.GetResult(RequestId).ConfigureAwait(false);

                        break;
                    }
                }while (true); //!!!! for POC only

                checkRunUpdate.Status      = CheckStatus.Completed;
                checkRunUpdate.CompletedAt = DateTime.UtcNow;
                checkRunUpdate.Conclusion  = scanResult.WorkStatus == WorkStatus.Clean ? CheckConclusion.Success : CheckConclusion.Failure;

                if (checkRunUpdate.Conclusion == CheckConclusion.Failure)
                {
                    checkRunUpdate.Output = new NewCheckRunOutput(
                        "Scan Report",
                        $"GitScan detected {scanResult.ConfirmedMalwares.Count()} infected files. See details below.");

                    checkRunUpdate.Output.Text  = "| File Path| Malware Type| AV Engines|\n";
                    checkRunUpdate.Output.Text += "|:---|:---|:---|\n";

                    foreach (var entry in scanResult.ConfirmedMalwares)
                    {
                        checkRunUpdate.Output.Text += $"|{entry.FileName}|{entry.MalwareInfo}|{string.Join(",", entry.AvEngines.ToArray())}";
                    }
                }

                checkRun = await checkRunClient.Update(CurrentRepository.Id, checkRun.Id, checkRunUpdate).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Exception: {ex.Message}");
            }
        }