/// <inheritdoc />
        public async Task <AutoMergeStatus> EvaluateFor(PullRequest pullRequest, CancellationToken cancellationToken)
        {
            if (pullRequest == null)
            {
                throw new ArgumentNullException(nameof(pullRequest));
            }

            var setRequired = await dataStore.ReadData <RequireChangelogEntry>(pullRequest.Number.ToString(), cancellationToken).ConfigureAwait(false);

            if (!setRequired.Required.HasValue)
            {
                setRequired.Required = generalConfiguration.DefaultChangelogRequired;
            }

            var changelog = Changelog.GetChangelog(pullRequest, out bool malformed);

            var result = new AutoMergeStatus
            {
                FailStatusReport = true,
                RequiredProgress = 2,                 //setRequired.Required.Value || malformed ? 1 : 0, //TODO:maintainer_can_modify field
                Progress         = (changelog != null ? 1 : 0)
            };

            if (result.Progress < result.RequiredProgress || malformed)
            {
                result.Notes.Add(stringLocalizer[malformed ? "ChangelogMalformed" : "NeedsChangelog"]);
            }
            return(result);
        }
        /// <inheritdoc />
        public async Task <string> ModifyMerge(PullRequest pullRequest, string workingCommit, CancellationToken cancellationToken)
        {
            if (pullRequest == null)
            {
                throw new ArgumentNullException(nameof(pullRequest));
            }
            if (workingCommit == null)
            {
                throw new ArgumentNullException(nameof(workingCommit));
            }

            var changelog = Changelog.GetChangelog(pullRequest, out bool malformed);

            if (changelog == null)
            {
                return(workingCommit);
            }

            var result = new List <Dictionary <string, string> >();

            result.AddRange(changelog.Changes.Select(x => new Dictionary <string, string> {
                { x.Type.ToString().ToLowerInvariant(), x.Text }
            }));

            //create the object graph
            var graph = new
            {
                author = changelog.Author,
                delete_after_temporary_for_replacement = true,
                changes = result
            };
            //hack because '-' isn't a valid identifier in c#
            var yaml = new Serializer().Serialize(graph).Replace("delete_after_temporary_for_replacement", "delete-after");

            var title = String.Format(CultureInfo.InvariantCulture, "AutoChangeLog-pr-{0}.yml", pullRequest.Number);

            var pathToWrite = ioManager.ConcatPath(repository.Path, "html", "changelogs", title);
            await ioManager.WriteAllText(pathToWrite, yaml, cancellationToken).ConfigureAwait(false);

            return(await repository.CommitChanges(new List <string> {
                pathToWrite
            }, cancellationToken));
        }
        /// <summary>
        /// Label a pull request
        /// </summary>
        /// <param name="payload">The <see cref="PullRequestEventPayload"/> for the pull request</param>
        /// <param name="oneCheckTags"><see langword="true"/> if additional tags should be contionally applied, <see langword="false"/> otherwise</param>
        /// <returns>A <see cref="Task"/> representing the running operation</returns>
        async Task TagPR(PullRequestEventPayload payload, bool oneCheckTags)
        {
            async Task <bool?> MergeableCheck()
            {
                //check if the PR is mergeable, if not, don't tag it
                bool?mergeable = payload.PullRequest.Mergeable;

                for (var I = 0; !mergeable.HasValue && I < 3; ++I)
                {
                    await Task.Delay(I * 1000).ConfigureAwait(false);

                    mergeable = (await gitHubManager.GetPullRequest(payload.PullRequest.Number).ConfigureAwait(false)).Mergeable;
                }
                return(mergeable);
            };

            var mergeableTask     = MergeableCheck().ConfigureAwait(false);
            var filesChanged      = gitHubManager.GetPullRequestChangedFiles(payload.PullRequest.Number).ConfigureAwait(false);
            var currentLabelsTask = gitHubManager.GetIssueLabels(payload.PullRequest.Number).ConfigureAwait(false);

            var labelsToAdd    = new List <string>();
            var labelsToRemove = new List <string>();

            var lowerTitle = payload.PullRequest.Title.ToLower(CultureInfo.CurrentCulture);

            if (lowerTitle.Contains("refactor"))
            {
                labelsToAdd.Add("Refactor");
            }
            if (lowerTitle.Contains("[dnm]"))
            {
                labelsToAdd.Add("Do Not Merge");
            }
            if (lowerTitle.Contains("[wip]"))
            {
                labelsToAdd.Add("Work In Progress");
            }
            if (lowerTitle.Contains("revert"))
            {
                labelsToAdd.Add("Revert");
            }
            if (lowerTitle.Contains("removes"))
            {
                labelsToAdd.Add("Removal");
            }

            var mergeableCheck = await mergeableTask;

            if (mergeableCheck.HasValue)
            {
                if (!mergeableCheck.Value)
                {
                    labelsToAdd.Add("Merge Conflict");
                }
                else
                {
                    labelsToRemove.Add("Merge Conflict");
                }
            }

            var treeToLabelMappings = new Dictionary <string, string>
            {
                { "_maps", "Map Edit" },
                { "tools", "Tools" },
                { "SQL", "SQL" },
                { ".github", "GitHub" }
            };

            var addOnlyTreeToLabelMappings = new Dictionary <string, string>
            {
                { "icons", "Sprites" },
                { "sound", "Sounds" },
                { "config", "Config Update" },
                { "code/controllers/configuration/entries", "Config Update" },
                { "tgui", "UI" }
            };

            foreach (var I in await filesChanged)
            {
                foreach (var J in treeToLabelMappings)
                {
                    if (I.FileName.StartsWith(J.Key, StringComparison.CurrentCulture))
                    {
                        labelsToAdd.Add(J.Value);
                    }
                    else
                    {
                        labelsToRemove.Add(J.Value);
                    }
                }
                if (oneCheckTags)
                {
                    foreach (var J in addOnlyTreeToLabelMappings)
                    {
                        if (I.FileName.StartsWith(J.Key, StringComparison.CurrentCulture))
                        {
                            labelsToAdd.Add(J.Value);
                        }
                    }
                }
            }

            void UniqueAdd(string label)
            {
                if (!labelsToAdd.Contains(label))
                {
                    labelsToAdd.Add(label);
                }
            }

            //github close syntax (without "close" variants)
            if (Regex.IsMatch(payload.PullRequest.Body, "(?i)(fix|fixes|fixed|resolve|resolves|resolved)\\s*#[1-9][0-9]*"))
            {
                UniqueAdd("Fix");
            }

            //run through the changelog
            var changelog = Changelog.GetChangelog(payload.PullRequest, out bool malformed);

            if (changelog != null)
            {
                foreach (var I in changelog.Changes.Select(x => x.Type))
                {
                    switch (I)
                    {
                    case ChangelogEntryType.Admin:
                        UniqueAdd("Administration");
                        break;

                    case ChangelogEntryType.Balance:
                        UniqueAdd("Balance/Rebalance");
                        break;

                    case ChangelogEntryType.BugFix:
                        UniqueAdd("Fix");
                        break;

                    case ChangelogEntryType.Code_Imp:
                        UniqueAdd("Code Improvement");
                        break;

                    case ChangelogEntryType.Config:
                        UniqueAdd("Config Update");
                        break;

                    case ChangelogEntryType.ImageAdd:
                        UniqueAdd("Sprites");
                        break;

                    case ChangelogEntryType.ImageDel:
                        UniqueAdd("Sprites");
                        UniqueAdd("Removal");
                        break;

                    case ChangelogEntryType.Refactor:
                        UniqueAdd("Refactor");
                        break;

                    case ChangelogEntryType.RscAdd:
                        UniqueAdd("Feature");
                        break;

                    case ChangelogEntryType.RscDel:
                        UniqueAdd("Removal");
                        break;

                    case ChangelogEntryType.SoundAdd:
                        UniqueAdd("Sounds");
                        break;

                    case ChangelogEntryType.SoundDel:
                        UniqueAdd("Sounds");
                        UniqueAdd("Removal");
                        break;

                    case ChangelogEntryType.SpellCheck:
                        UniqueAdd("Grammar and Formatting");
                        break;

                    case ChangelogEntryType.Tweak:
                        UniqueAdd("Tweak");
                        break;
                    }
                }
            }

            labelsToAdd.RemoveAll(x => labelsToRemove.Contains(x));

            var newLabels = new List <string>();

            foreach (var I in labelsToAdd)
            {
                newLabels.Add(I);
            }

            var currentLabels = new List <Label>(await currentLabelsTask);

            currentLabels.RemoveAll(x => labelsToRemove.Contains(x.Name) || labelsToAdd.Contains(x.Name));
            foreach (var I in currentLabels)
            {
                newLabels.Add(I.Name);
            }

            await gitHubManager.SetIssueLabels(payload.PullRequest.Number, newLabels).ConfigureAwait(false);
        }