public async Task CreateOrUpdatePullRequestMergeStatusInfoAsync(string pullRequestUrl, IReadOnlyList <MergePolicyEvaluationResult> evaluations)
        {
            (string owner, string repo, int id) = ParsePullRequestUri(pullRequestUrl);
            // Get the sha of the latest commit for the current PR
            string prSha = (await Client.PullRequest.Get(owner, repo, id))?.Head?.Sha;

            if (prSha == null)
            {
                throw new InvalidOperationException("We cannot find the sha of the pull request");
            }

            // Get a list of all the merge policies checks runs for the current PR
            List <CheckRun> existingChecksRuns =
                (await Client.Check.Run.GetAllForReference(owner, repo, prSha))
                .CheckRuns.Where(e => e.ExternalId.StartsWith(MergePolicyConstants.MaestroMergePolicyCheckRunPrefix)).ToList();

            var toBeAdded   = evaluations.Where(e => existingChecksRuns.All(c => c.ExternalId != CheckRunId(e, prSha)));
            var toBeUpdated = existingChecksRuns.Where(c => evaluations.Any(e => c.ExternalId == CheckRunId(e, prSha)));
            var toBeDeleted = existingChecksRuns.Where(c => evaluations.All(e => c.ExternalId != CheckRunId(e, prSha)));

            foreach (var newCheckRunValidation in toBeAdded)
            {
                await Client.Check.Run.Create(owner, repo, CheckRunForAdd(newCheckRunValidation, prSha));
            }
            foreach (var updatedCheckRun in toBeUpdated)
            {
                MergePolicyEvaluationResult eval           = evaluations.Single(e => updatedCheckRun.ExternalId == CheckRunId(e, prSha));
                CheckRunUpdate newCheckRunUpdateValidation = CheckRunForUpdate(eval);
                await Client.Check.Run.Update(owner, repo, updatedCheckRun.Id, newCheckRunUpdateValidation);
            }
            foreach (var deletedCheckRun in toBeDeleted)
            {
                await Client.Check.Run.Update(owner, repo, deletedCheckRun.Id, CheckRunForDelete(deletedCheckRun));
            }
        }
            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);
                }
            }
Example #3
0
        /// <inheritdoc />
        public async Task UpdateCheckRun(long repositoryId, long checkRunId, CheckRunUpdate checkRunUpdate, CancellationToken cancellationToken)
        {
            logger.LogTrace("Update check run {0} on repository {1}", checkRunId, repositoryId);
            var client = await CreateInstallationClient(repositoryId, cancellationToken).ConfigureAwait(false);

            await client.Check.Run.Update(repositoryId, checkRunId, checkRunUpdate).ConfigureAwait(false);
        }
        /// <summary>
        ///     Update a check run based on a NewCheckRun and evaluation
        /// </summary>
        /// <param name="newCheckRun">The NewCheckRun that needs to be updated</param>
        /// <param name="eval">The result of that updated check run</param>
        /// <returns>The updated CheckRun</returns>
        private CheckRunUpdate CheckRunForUpdate(MergePolicyEvaluationResult eval)
        {
            CheckRunUpdate updatedCheckRun = new CheckRunUpdate();

            UpdateCheckRun(updatedCheckRun, eval);
            return(updatedCheckRun);
        }
Example #5
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);
        }
        /// <summary>
        ///     Create a CheckRunUpdate based on a check run that needs to be deleted
        /// </summary>
        /// <param name="checkRun">The check run that needs to be deleted</param>
        /// <returns>The deleted check run</returns>
        private CheckRunUpdate CheckRunForDelete(CheckRun checkRun)
        {
            CheckRunUpdate updatedCheckRun = new CheckRunUpdate();

            updatedCheckRun.CompletedAt = checkRun.CompletedAt;
            updatedCheckRun.Status      = "completed";
            updatedCheckRun.Conclusion  = "skipped";
            return(updatedCheckRun);
        }
            public async Task EnsuresNonEmptyArguments()
            {
                var gitHubClient = Substitute.For <IGitHubClient>();
                var client       = new ObservableCheckRunsClient(gitHubClient);

                var update = new CheckRunUpdate {
                    Status = CheckStatus.InProgress
                };

                Assert.Throws <ArgumentException>(() => client.Update("", "repo", 1, update));
                Assert.Throws <ArgumentException>(() => client.Update("fake", "", 1, update));
            }
Example #8
0
            public async Task EnsuresNonEmptyArguments()
            {
                var connection = Substitute.For <IApiConnection>();
                var client     = new CheckRunsClient(connection);

                var update = new CheckRunUpdate {
                    Status = CheckStatus.InProgress
                };

                await Assert.ThrowsAsync <ArgumentException>(() => client.Update("", "repo", 1, update));

                await Assert.ThrowsAsync <ArgumentException>(() => client.Update("fake", "", 1, update));
            }
            public async Task RequestsCorrectUrl()
            {
                var gitHubClient = Substitute.For <IGitHubClient>();
                var client       = new ObservableCheckRunsClient(gitHubClient);

                var update = new CheckRunUpdate {
                    Status = CheckStatus.InProgress
                };

                client.Update("fake", "repo", 1, update);

                gitHubClient.Check.Run.Received().Update("fake", "repo", 1, update);
            }
Example #10
0
        public async Task UpdateCheckRun(InstallationToken token, string repo, long checkRunId, string status,
                                         string conclusion, CheckRunOutput output, DateTime?completeDate = null, List <Action> actions = null)
        {
            var url     = $"{Base}repos/{token.Account}/{repo}/check-runs/{checkRunId}";
            var payload = new CheckRunUpdate {
                Status = status, Conclusion = conclusion, Output = output, Actions = actions
            };

            if (completeDate != null)
            {
                payload.CompletedAt = completeDate.Value.ToUniversalTime();
            }
            await Execute <CheckRun>(HttpMethod.Patch, url, token, JsonConvert.SerializeObject(payload));
        }
Example #11
0
            public async Task RequestsCorrectUrl()
            {
                var connection = Substitute.For <IApiConnection>();
                var client     = new CheckRunsClient(connection);

                var update = new CheckRunUpdate {
                    Status = CheckStatus.InProgress
                };

                await client.Update("fake", "repo", 1, update);

                connection.Received().Patch <CheckRun>(
                    Arg.Is <Uri>(u => u.ToString() == "repos/fake/repo/check-runs/1"),
                    update,
                    "application/vnd.github.antiope-preview+json");
            }
Example #12
0
        /// <summary>
        /// Publish a <see cref="List{T}"/> of <paramref name="diffResults"/>s to the <see cref="IDatabaseContext"/> and GitHub
        /// </summary>
        /// <param name="pullRequest">The <see cref="PullRequest"/> the <paramref name="diffResults"/> are for</param>
        /// <param name="checkRunId">The <see cref="CheckRun.Id"/></param>
        /// <param name="diffResults">The map of <see cref="MapDiff"/>s to <see cref="MapRegion"/>s</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
        /// <returns>A <see cref="Task"/> representing the running operation</returns>
        async Task HandleResults(PullRequest pullRequest, long checkRunId, Dictionary <MapDiff, MapRegion> diffResults, CancellationToken cancellationToken)
        {
            int formatterCount = 0;

            var databaseContext = serviceProvider.GetRequiredService <IDatabaseContext>();

            var prefix = generalConfiguration.ApplicationPrefix;

            logger.LogTrace("Generating comment and preparing database query...");
            var outputImages = new List <CheckRunImage>()
            {
                Capacity = diffResults.Count
            };

            foreach (var kv in diffResults)
            {
                var I         = kv.Key;
                var beforeUrl = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, "before"));
                var afterUrl  = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, "after"));
                var logsUrl   = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, "logs"));

                logger.LogTrace("Adding MapDiff for {0}...", I.MapPath);
                var region = kv.Value?.ToString() ?? stringLocalizer["ALL"];
                outputImages.Add(new CheckRunImage(region, beforeUrl, stringLocalizer["Old"]));
                outputImages.Add(new CheckRunImage(region, afterUrl, stringLocalizer["New"]));
                databaseContext.MapDiffs.Add(I);
                ++formatterCount;
            }

            logger.LogTrace("Committing new MapDiffs to the database...");
            await databaseContext.Save(cancellationToken).ConfigureAwait(false);

            logger.LogTrace("Finalizing GitHub Check...");

            var ncr = new CheckRunUpdate
            {
                DetailsUrl  = String.Concat(prefix, FilesController.RouteToBrowse(pullRequest.Base.Repository, checkRunId)),
                Status      = CheckStatus.Completed,
                CompletedAt = DateTimeOffset.Now,
                Output      = new CheckRunOutput(stringLocalizer["Map Renderings"], stringLocalizer["Before and after renderings of .dmm files"], null, null, outputImages),
                Conclusion  = CheckConclusion.Success
            };
            await serviceProvider.GetRequiredService <IGitHubManager>().UpdateCheckRun(pullRequest.Base.Repository.Id, checkRunId, ncr, cancellationToken).ConfigureAwait(false);
        }
Example #13
0
        /// <inheritdoc/>
        protected override async Task <object> CallGitHubApi(DialogContext dc, Octokit.GitHubClient gitHubClient, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (Owner != null && Name != null && CheckRunId != null && CheckRunUpdate != null)
            {
                var ownerValue          = Owner.GetValue(dc.State);
                var nameValue           = Name.GetValue(dc.State);
                var checkRunIdValue     = CheckRunId.GetValue(dc.State);
                var checkRunUpdateValue = CheckRunUpdate.GetValue(dc.State);
                return(await gitHubClient.Check.Run.Update(ownerValue, nameValue, (Int64)checkRunIdValue, checkRunUpdateValue).ConfigureAwait(false));
            }
            if (RepositoryId != null && CheckRunId != null && CheckRunUpdate != null)
            {
                var repositoryIdValue   = RepositoryId.GetValue(dc.State);
                var checkRunIdValue     = CheckRunId.GetValue(dc.State);
                var checkRunUpdateValue = CheckRunUpdate.GetValue(dc.State);
                return(await gitHubClient.Check.Run.Update((Int64)repositoryIdValue, (Int64)checkRunIdValue, checkRunUpdateValue).ConfigureAwait(false));
            }

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

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

            if (result.Status == MergePolicyEvaluationStatus.Pending)
            {
                newUpdateCheckRun.Status = CheckStatus.InProgress;
            }
            else if (result.Status == MergePolicyEvaluationStatus.Success)
            {
                newUpdateCheckRun.Conclusion  = "success";
                newUpdateCheckRun.CompletedAt = DateTime.Now;
            }
            else
            {
                newUpdateCheckRun.Conclusion  = "failure";
                newUpdateCheckRun.CompletedAt = DateTime.UtcNow;
            }
        }
Example #15
0
        /// <summary>
        /// Publish a <see cref="List{T}"/> of <paramref name="diffResults"/>s to the <see cref="IDatabaseContext"/> and GitHub
        /// </summary>
        /// <param name="pullRequest">The <see cref="PullRequest"/> the <paramref name="diffResults"/> are for</param>
        /// <param name="installationId">The <see cref="InstallationId.Id"/></param>
        /// <param name="checkRunId">The <see cref="CheckRun.Id"/></param>
        /// <param name="diffResults">The <see cref="IconDiff"/>s</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
        /// <returns>A <see cref="Task"/> representing the running operation</returns>
        async Task HandleResults(PullRequest pullRequest, long installationId, long checkRunId, List <IconDiff> diffResults, CancellationToken cancellationToken)
        {
            int formatterCount = 0;

            var databaseContext = serviceProvider.GetRequiredService <IDatabaseContext>();

            logger.LogTrace("Generating check run output and preparing database query...");

            var outputImages = new List <CheckRunImage>()
            {
                Capacity = diffResults.Count
            };

            foreach (var kv in diffResults)
            {
                var beforeUrl = FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, "before");
                var afterUrl  = FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, "after");

                logger.LogTrace("Adding IconDiff for {0}...", kv.DmiPath);
                outputImages.Add(new CheckRunImage(null, beforeUrl, stringLocalizer["Old - {0}", kv.DmiPath]));
                outputImages.Add(new CheckRunImage(null, afterUrl, stringLocalizer["New - {0}", kv.DmiPath]));
                databaseContext.IconDiffs.Add(kv);
                ++formatterCount;
            }

            logger.LogTrace("Committing new IconDiffs to the database...");
            await databaseContext.Save(cancellationToken).ConfigureAwait(false);

            logger.LogTrace("Finalizing GitHub Check...");

            var ncr = new CheckRunUpdate
            {
                Status      = CheckStatus.Completed,
                CompletedAt = DateTimeOffset.Now,
                Output      = new CheckRunOutput(stringLocalizer["Icon Diffs"], null, null, outputImages),
                Conclusion  = CheckConclusion.Success
            };
            await serviceProvider.GetRequiredService <IGitHubManager>().UpdateCheckRun(pullRequest.Base.Repository.Id, installationId, checkRunId, ncr, cancellationToken).ConfigureAwait(false);
        }
Example #16
0
        /// <summary>
        /// Publish a <see cref="List{T}"/> of <paramref name="diffResults"/>s to the <paramref name="databaseContext"/> and GitHub
        /// </summary>
        /// <param name="pullRequest">The <see cref="PullRequest"/> the <paramref name="diffResults"/> are for</param>
        /// <param name="installationId">The <see cref="InstallationId.Id"/></param>
        /// <param name="checkRunId">The <see cref="CheckRun.Id"/></param>
        /// <param name="diffResults">The <see cref="IconDiff"/>s</param>
        /// <param name="scope">The <see cref="IServiceScope"/> for the operation</param>
        /// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the operation if any</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
        /// <returns>A <see cref="Task"/> representing the running operation</returns>
        async Task HandleResults(PullRequest pullRequest, long installationId, long checkRunId, List <IconDiff> diffResults, IServiceScope scope, IDatabaseContext databaseContext, CancellationToken cancellationToken)
        {
            logger.LogTrace("Generating check run output and preparing database query...");

            var prefix         = generalConfiguration.ApplicationPrefix;
            var commentBuilder = new StringBuilder();

            //create a dic of filepath -> IconDiff
            var dic = new Dictionary <string, List <IconDiff> >();

            foreach (var I in diffResults)
            {
                if (!dic.TryGetValue(I.DmiPath, out List <IconDiff> list))
                {
                    list = new List <IconDiff>();
                    dic.Add(I.DmiPath, list);
                }
                list.Add(I);
                if (databaseContext != null && (I.Before != null || I.After != null))
                {
                    databaseContext.IconDiffs.Add(I);
                }
            }

            foreach (var kv in dic)
            {
                commentBuilder.Append(String.Format(CultureInfo.InvariantCulture,
                                                    "<details><summary>{0}</summary>{5}{5}{1} | {2} | {3} | {4}{5}--- | --- | --- | ---",
                                                    kv.Key,
                                                    stringLocalizer["State"],
                                                    stringLocalizer["Old"],
                                                    stringLocalizer["New"],
                                                    stringLocalizer["Status"],
                                                    Environment.NewLine));

                foreach (var I in kv.Value)
                {
                    var beforeUrl = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, I.FileId, true, (I.Before ?? I.After)?.IsGif ?? false));
                    var afterUrl  = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, I.FileId, false, (I.After ?? I.Before)?.IsGif ?? false));

                    string status;
                    if (I.Before == null && I.After == null)
                    {
                        status = stringLocalizer["This icon could not be renderered due to an error. Please add a permalink to the .dmi that caused this [here]({0}) to help discover the reason.{1}```{1}{2}{1}```", IssueReportUrl, Environment.NewLine, I.Error];
                    }
                    else
                    {
                        status = stringLocalizer[I.Before == null ? "Created" : I.After == null ? "Deleted" : "Modified"];
                    }

                    var stateName = I.StateName;
                    if (stateName == null)
                    {
                        stateName = "(Empty Icon File)";
                    }
                    else if (stateName.Length == 0)
                    {
                        stateName = "(Default State)";
                    }

                    commentBuilder.Append(String.Format(CultureInfo.InvariantCulture,
                                                        "{0}{1} | ![]({2}) | ![]({3}) | {4}",
                                                        Environment.NewLine,
                                                        stateName,
                                                        beforeUrl,
                                                        afterUrl,
                                                        status
                                                        ));
                }

                commentBuilder.Append(String.Format(CultureInfo.InvariantCulture, "{0}{0}</details>{0}{0}", Environment.NewLine));
            }

            var comment = String.Format(CultureInfo.CurrentCulture,
                                        "{0}{1}{1}{1}{1}<br>{1}{1}{2}",
                                        commentBuilder,
                                        Environment.NewLine,
                                        stringLocalizer["Please report any issues [here]({0}).", IssueReportUrl]
                                        );


            if (databaseContext != null)
            {
                logger.LogTrace("Committing new IconDiffs to the database...");
                await databaseContext.Save(cancellationToken).ConfigureAwait(false);
            }

            logger.LogTrace("Finalizing GitHub Check...");

            var ghm = scope.ServiceProvider.GetRequiredService <IGitHubManager>();

            if (comment.Length > 65535)             //arbitrary github limit
            {
                if (diffResults.Count > 1)          //come on dude
                {
                    logger.LogInformation("Comment too large, employing breakdown procedure.");
                    var cutoff = diffResults.Count / 2;
                    var set1   = new List <IconDiff>();
                    var set2   = new List <IconDiff>();
                    for (var I = 0; I < diffResults.Count; ++I)
                    {
                        (I < cutoff ? set1 : set2).Add(diffResults[I]);
                    }

                    var firstCR        = HandleResults(pullRequest, installationId, checkRunId, set1, scope, null, cancellationToken);
                    var nextCheckRunId = await ghm.CreateCheckRun(pullRequest.Base.Repository.Id, installationId, new NewCheckRun(stringLocalizer["Additional Diffs - Pull Request #{0} - Set Base: {1}", pullRequest.Number, set2.First().DmiPath], pullRequest.Head.Sha)
                    {
                        StartedAt = DateTimeOffset.Now,
                        Status    = CheckStatus.InProgress
                    }, cancellationToken).ConfigureAwait(false);
                    await HandleResults(pullRequest, installationId, nextCheckRunId, set2, scope, null, cancellationToken).ConfigureAwait(false);

                    await firstCR.ConfigureAwait(false);

                    return;
                }
                var iPath = diffResults.First().DmiPath;
                logger.LogWarning("Unable to post check run for icon {0}!", iPath);
                comment = stringLocalizer["Unable to render this icon ({0}) due to limitations on github check run output!", iPath];
            }

            var ncr = new CheckRunUpdate
            {
                Status      = CheckStatus.Completed,
                CompletedAt = DateTimeOffset.Now,
                Output      = new NewCheckRunOutput(stringLocalizer["Icon Diffs"], stringLocalizer["Icons with diff:"])
                {
                    Text = comment
                },
                Conclusion = CheckConclusion.Success
            };
            await ghm.UpdateCheckRun(pullRequest.Base.Repository.Id, installationId, checkRunId, ncr, cancellationToken).ConfigureAwait(false);
        }
        /// <summary>
        /// Updates a check run for a specific commit in a repository
        /// </summary>
        /// <remarks>
        /// See the <a href="https://developer.github.com/v3/checks/runs/#update-a-check-run">Check Runs API documentation</a> for more information.
        /// </remarks>
        /// <param name="repositoryId">The Id of the repository</param>
        /// <param name="checkRunId">The Id of the check run</param>
        /// <param name="checkRunUpdate">The updates to the check run</param>
        public IObservable <CheckRun> Update(long repositoryId, long checkRunId, CheckRunUpdate checkRunUpdate)
        {
            Ensure.ArgumentNotNull(checkRunUpdate, nameof(checkRunUpdate));

            return(_client.Update(repositoryId, checkRunId, checkRunUpdate).ToObservable());
        }
        /// <summary>
        /// Updates a check run for a specific commit in a repository
        /// </summary>
        /// <remarks>
        /// See the <a href="https://developer.github.com/v3/checks/runs/#update-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="checkRunId">The Id of the check run</param>
        /// <param name="checkRunUpdate">The updates to the check run</param>
        public IObservable <CheckRun> Update(string owner, string name, long checkRunId, CheckRunUpdate checkRunUpdate)
        {
            Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
            Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
            Ensure.ArgumentNotNull(checkRunUpdate, nameof(checkRunUpdate));

            return(_client.Update(owner, name, checkRunId, checkRunUpdate).ToObservable());
        }
Example #19
0
        /// <summary>
        /// Publish a <see cref="List{T}"/> of <paramref name="diffResults"/>s to the <see cref="IDatabaseContext"/> and GitHub
        /// </summary>
        /// <param name="pullRequest">The <see cref="PullRequest"/> the <paramref name="diffResults"/> are for</param>
        /// <param name="checkRunId">The <see cref="CheckRun.Id"/></param>
        /// <param name="diffResults">The map of <see cref="MapDiff"/>s to <see cref="MapRegion"/>s</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 HandleResults(PullRequest pullRequest, long checkRunId, Dictionary <MapDiff, MapRegion> diffResults, IServiceScope scope, CancellationToken cancellationToken)
        {
            int formatterCount = 0;

            var databaseContext = scope.ServiceProvider.GetRequiredService <IDatabaseContext>();

            logger.LogTrace("Generating comment and preparing database query...");
            var commentBuilder = new StringBuilder();
            var prefix         = generalConfiguration.ApplicationPrefix;

            foreach (var kv in diffResults)
            {
                var I             = kv.Key;
                var beforeUrl     = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, "before"));
                var afterUrl      = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, "after"));
                var differenceUrl = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, "diff"));
                var logsUrl       = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, "logs"));

                commentBuilder.Append(String.Format(CultureInfo.InvariantCulture,
                                                    "<details><summary>{0}</summary>{11}{11}{1} | {2} | {14}{11}--- | --- | ---{11}![{13}]({3}) | ![{13}]({4}) | ![{13}]({15}){11}{11}{5} | {6} | {7} | {12}{11}--- | --- | --- | ---{11}{8} | {9} | [{7}]({10}) | [{1}]({3}) \\| [{2}]({4}) \\| [{14}]({15}){11}{11}</details>{11}{11}",
                                                    I.MapPath,
                                                    stringLocalizer["Old"],
                                                    stringLocalizer["New"],
                                                    beforeUrl,
                                                    afterUrl,
                                                    stringLocalizer["Status"],
                                                    stringLocalizer["Region"],
                                                    stringLocalizer["Logs"],
                                                    I.BeforeImage != null ? (I.AfterImage != null ? stringLocalizer["Modified"] : stringLocalizer["Deleted"]) : stringLocalizer["Created"],
                                                    kv.Value?.ToString() ?? stringLocalizer["ALL"],
                                                    logsUrl,
                                                    Environment.NewLine,
                                                    stringLocalizer["Raw"],
                                                    stringLocalizer["If the image doesn't load, it may be too big for GitHub. Use the \"Raw\" links."],
                                                    stringLocalizer["Difference"],
                                                    differenceUrl
                                                    ));
                logger.LogTrace("Adding MapDiff for {0}...", I.MapPath);
                databaseContext.MapDiffs.Add(I);
                ++formatterCount;
            }

            var comment = String.Format(CultureInfo.CurrentCulture,
                                        "{0}{2}{2}{2}{2}<br>{1}{2}{2}{2}{2}{3}",
                                        commentBuilder,
                                        stringLocalizer["Merge base commit used: {0}", pullRequest.Base.Sha],
                                        Environment.NewLine,
                                        stringLocalizer["Please report any issues [here]({0}).", IssueReportUrl]
                                        );

            logger.LogTrace("Committing new MapDiffs to the database...");
            await databaseContext.Save(cancellationToken).ConfigureAwait(false);

            logger.LogTrace("Finalizing GitHub Check...");

            var ncr = new CheckRunUpdate
            {
                DetailsUrl  = String.Concat(prefix, FilesController.RouteToBrowse(pullRequest.Base.Repository, checkRunId)),
                Status      = CheckStatus.Completed,
                CompletedAt = DateTimeOffset.Now,
                Output      = new NewCheckRunOutput(stringLocalizer["Map Renderings"], stringLocalizer["Maps with diff:"])
                {
                    Text = comment
                },
                Conclusion = CheckConclusion.Success
            };
            await scope.ServiceProvider.GetRequiredService <IGitHubManager>().UpdateCheckRun(pullRequest.Base.Repository.Id, checkRunId, ncr, cancellationToken).ConfigureAwait(false);
        }
Example #20
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}");
            }
        }
Example #21
0
        /// <summary>
        /// Publish a <see cref="List{T}"/> of <paramref name="diffResults"/>s to the <paramref name="databaseContext"/> and GitHub
        /// </summary>
        /// <param name="pullRequest">The <see cref="PullRequest"/> the <paramref name="diffResults"/> are for</param>
        /// <param name="installationId">The <see cref="InstallationId.Id"/></param>
        /// <param name="checkRunId">The <see cref="CheckRun.Id"/></param>
        /// <param name="diffResults">The <see cref="IconDiff"/>s</param>
        /// <param name="scope">The <see cref="IServiceScope"/> for the operation</param>
        /// <param name="databaseContext">The <see cref="IDatabaseContext"/> 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 HandleResults(PullRequest pullRequest, long installationId, long checkRunId, List <IconDiff> diffResults, IServiceScope scope, IDatabaseContext databaseContext, CancellationToken cancellationToken)
        {
            int formatterCount = 0;

            logger.LogTrace("Generating check run output and preparing database query...");

            var outputImages = new List <CheckRunImage>()
            {
                Capacity = diffResults.Count
            };

            var prefix         = generalConfiguration.ApplicationPrefix;
            var commentBuilder = new StringBuilder();

            //create a dic of filepath -> IconDiff
            var dic = new Dictionary <string, List <IconDiff> >();

            foreach (var I in diffResults)
            {
                if (!dic.TryGetValue(I.DmiPath, out List <IconDiff> list))
                {
                    list = new List <IconDiff>();
                    dic.Add(I.DmiPath, list);
                }
                list.Add(I);
                databaseContext.IconDiffs.Add(I);
            }

            foreach (var kv in dic)
            {
                commentBuilder.Append(String.Format(CultureInfo.InvariantCulture,
                                                    "<details><summary>{0}</summary>{5}{5}{1} | {2} | {3} | {4}{5}--- | --- | --- | ---",
                                                    kv.Key,
                                                    stringLocalizer["State"],
                                                    stringLocalizer["Old"],
                                                    stringLocalizer["New"],
                                                    stringLocalizer["Status"],
                                                    Environment.NewLine));

                foreach (var I in kv.Value)
                {
                    var beforeUrl = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, true));
                    var afterUrl  = String.Concat(prefix, FilesController.RouteTo(pullRequest.Base.Repository, checkRunId, formatterCount, false));

                    commentBuilder.Append(String.Format(CultureInfo.InvariantCulture,
                                                        "{0}{1} | ![]({2}) | ![]({3}) | {4}",
                                                        Environment.NewLine,
                                                        I.StateName,
                                                        beforeUrl,
                                                        afterUrl,
                                                        stringLocalizer[I.Before == null ? "Created" : I.After == null ? "Deleted" : "Modified"]
                                                        ));

                    ++formatterCount;
                }

                commentBuilder.Append(String.Format(CultureInfo.InvariantCulture, "{0}{0}</details>{0}{0}", Environment.NewLine));
            }

            var comment = String.Format(CultureInfo.CurrentCulture,
                                        "{0}{1}{1}{1}{1}<br>{1}{1}{2}",
                                        commentBuilder,
                                        Environment.NewLine,
                                        stringLocalizer["Please report any issues [here]({0}).", IssueReportUrl]
                                        );

            logger.LogTrace("Committing new IconDiffs to the database...");
            await databaseContext.Save(cancellationToken).ConfigureAwait(false);

            logger.LogTrace("Finalizing GitHub Check...");

            var ncr = new CheckRunUpdate
            {
                Status      = CheckStatus.Completed,
                CompletedAt = DateTimeOffset.Now,
                Output      = new CheckRunOutput(stringLocalizer["Icon Diffs"], stringLocalizer["Icons with diff:"], comment, null, outputImages),
                Conclusion  = CheckConclusion.Success
            };
            await scope.ServiceProvider.GetRequiredService <IGitHubManager>().UpdateCheckRun(pullRequest.Base.Repository.Id, installationId, checkRunId, ncr, cancellationToken).ConfigureAwait(false);
        }