private async Task UpdateCommentOnPullRequest(
            PullRequestEventPayload payload,
            IGitHubClientAdapter gitHubClientAdapter,
            QuantifierResult quantifierClientResult,
            string quantifierContextLink)
        {
            // delete existing comments created by us
            var existingComments =
                await gitHubClientAdapter.GetIssueCommentsAsync(payload.Repository.Id, payload.PullRequest.Number);

            var existingCommentsCreatedByUs = existingComments.Where(
                ec =>
                ec.User.Login.Equals($"{gitHubClientAdapter.GitHubAppSettings.Name}[bot]"));

            foreach (var existingComment in existingCommentsCreatedByUs)
            {
                await gitHubClientAdapter.DeleteIssueCommentAsync(payload.Repository.Id, existingComment.Id);
            }

            // create a new comment on the issue
            var comment = await quantifierClientResult.ToMarkdownCommentAsync(
                payload.Repository.HtmlUrl,
                quantifierContextLink,
                payload.PullRequest.HtmlUrl,
                payload.PullRequest.User.Login,
                ShouldPostAnonymousFeedbackLink(payload),
                new MarkdownCommentOptions { CollapsePullRequestQuantifiedSection = true });

            await gitHubClientAdapter.CreateIssueCommentAsync(
                payload.Repository.Id,
                payload.PullRequest.Number,
                comment);
        }
        private async Task ApplyLabelToPullRequest(
            PullRequestEventPayload payload,
            IGitHubClientAdapter gitHubClientAdapter,
            QuantifierResult quantifierClientResult,
            IEnumerable <string> labelOptionsFromContext)
        {
            // create a new label in the repository if doesn't exist
            try
            {
                var existingLabel = await gitHubClientAdapter.GetLabelAsync(
                    payload.Repository.Id,
                    quantifierClientResult.Label);
            }
            catch (NotFoundException)
            {
                // create new label
                var color = Color.FromName(quantifierClientResult.Color);
                await gitHubClientAdapter.CreateLabelAsync(
                    payload.Repository.Id,
                    new NewLabel(quantifierClientResult.Label, ConvertToHex(color)));
            }

            // remove any previous labels applied if it's different
            // labels do not have the property of who applied them
            // so we use string matching against the label options present in the context
            // if label strings have changed in context since last PR update, this will break
            var existingLabels =
                await gitHubClientAdapter.GetIssueLabelsAsync(payload.Repository.Id, payload.PullRequest.Number);

            var existingLabelsByUs = existingLabels.Select(el => el.Name).Intersect(labelOptionsFromContext).ToList();

            foreach (var existingLabel in existingLabelsByUs)
            {
                if (existingLabel == quantifierClientResult.Label)
                {
                    continue;
                }

                await gitHubClientAdapter.RemoveLabelFromIssueAsync(
                    payload.Repository.Id,
                    payload.PullRequest.Number,
                    existingLabel);
            }

            // apply new label to pull request
            await gitHubClientAdapter.ApplyLabelAsync(
                payload.Repository.Id,
                payload.PullRequest.Number,
                new[] { quantifierClientResult.Label });
        }
        private async Task <QuantifierInput> GetQuantifierInputFromPullRequest(PullRequestEventPayload payload, IGitHubClientAdapter gitHubClientAdapter)
        {
            // get pull request files
            var pullRequestFiles = await gitHubClientAdapter.GetPullRequestFilesAsync(
                payload.Repository.Id,
                payload.PullRequest.Number);

            // convert to quantifier input
            var quantifierInput = new QuantifierInput();

            foreach (var pullRequestFile in pullRequestFiles)
            {
                if (pullRequestFile.Patch == null)
                {
                    continue;
                }

                var changeType = GitChangeType.Modified;
                switch (pullRequestFile.Status)
                {
                case "modified":
                    break;

                case "added":
                    changeType = GitChangeType.Added;
                    break;

                case "deleted":
                    changeType = GitChangeType.Deleted;
                    break;
                }

                var fileExtension = !string.IsNullOrWhiteSpace(pullRequestFile.FileName)
                    ? new FileInfo(pullRequestFile.FileName).Extension
                    : string.Empty;
                var gitFilePatch = new GitFilePatch(
                    pullRequestFile.FileName,
                    fileExtension)
                {
                    ChangeType           = changeType,
                    AbsoluteLinesAdded   = pullRequestFile.Additions,
                    AbsoluteLinesDeleted = pullRequestFile.Deletions,
                    DiffContent          = pullRequestFile.Patch,
                };
                quantifierInput.Changes.Add(gitFilePatch);
            }

            return(quantifierInput);
        }
        private async Task <string> GetContextFromRepoIfPresent(PullRequestEventPayload payload, IGitHubClientAdapter gitHubClientAdapter)
        {
            // get context if present
            string context = null;

            try
            {
                var rawContext = await gitHubClientAdapter.GetRawFileAsync(
                    payload.Repository.Owner.Login,
                    payload.Repository.Name,
                    "/prquantifier.yaml");

                context = Encoding.UTF8.GetString(rawContext);
            }
            catch (NotFoundException)
            {
            }
            catch
            {
                // ignored
            }

            return(context);
        }