<commit_before>// Copyright 2019 Maintainers of NUKE.
// Distributed under the MIT License.
// https://github.com/nuke-build/nuke/blob/master/LICENSE

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Nuke.Common.Git;
using Nuke.Common.Utilities;
using Octokit;
using static Nuke.Common.IO.PathConstruction;

namespace Nuke.Common.Tools.GitHub
{
    [PublicAPI]
    public static class GitHubTasks
    {
        public static GitHubClient GitHubClient;

        private static GitHubClient Client =>
            GitHubClient ??= new GitHubClient(new ProductHeaderValue(nameof(NukeBuild)));

        public static async Task<IEnumerable<(string DownloadUrl, string RelativePath)>> GetGitHubDownloadUrls(
            this GitRepository repository,
            string directory = null,
            string branch = null)
        {
            ControlFlow.Assert(repository.IsGitHubRepository(), "repository.IsGitHubRepository()");
            ControlFlow.Assert(!HasPathRoot(directory) || repository.LocalDirectory != null,
                "!HasPathRoot(directory) || repository.LocalDirectory != null");

            var relativeDirectory = HasPathRoot(directory)
                ? GetRelativePath(repository.LocalDirectory, directory)
                : directory;
            relativeDirectory = (relativeDirectory + "/").TrimStart("/");

            branch ??= await repository.GetDefaultBranch();
            var treeResponse = await Client.Git.Tree.GetRecursive(
                repository.GetGitHubOwner(),
                repository.GetGitHubName(),
                branch);

            return treeResponse.Tree
                .Where(x => x.Type == TreeType.Blob)
                .Where(x => x.Path.StartsWithOrdinalIgnoreCase(relativeDirectory))
                .Select(x => (repository.GetGitHubDownloadUrl(x.Path, branch), x.Path.TrimStart(relativeDirectory)));
        }

        public static async Task<string> GetDefaultBranch(this GitRepository repository)
        {
            ControlFlow.Assert(repository.IsGitHubRepository(), text: "repository.IsGitHubRepository()");

            var repo = await Client.Repository.Get(repository.GetGitHubOwner(), repository.GetGitHubName());
            return repo.DefaultBranch;
        }

        [ItemCanBeNull]
        public static async Task<Milestone> GetGitHubMilestone(this GitRepository repository, string name)
        {
            ControlFlow.Assert(repository.IsGitHubRepository(), text: "repository.IsGitHubRepository()");
<commit_msg>Add GitRepository.GetLatestRelease for GitHub repositories<commit_after>// Copyright 2019 Maintainers of NUKE.
// Distributed under the MIT License.
// https://github.com/nuke-build/nuke/blob/master/LICENSE

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Nuke.Common.Git;
using Nuke.Common.Utilities;
using Octokit;
using static Nuke.Common.IO.PathConstruction;

namespace Nuke.Common.Tools.GitHub
{
    [PublicAPI]
    public static class GitHubTasks
    {
        public static GitHubClient GitHubClient;

        private static GitHubClient Client =>
            GitHubClient ??= new GitHubClient(new ProductHeaderValue(nameof(NukeBuild)));

        public static async Task<IEnumerable<(string DownloadUrl, string RelativePath)>> GetGitHubDownloadUrls(
            this GitRepository repository,
            string directory = null,
            string branch = null)
        {
            ControlFlow.Assert(repository.IsGitHubRepository(), "repository.IsGitHubRepository()");
            ControlFlow.Assert(!HasPathRoot(directory) || repository.LocalDirectory != null,
                "!HasPathRoot(directory) || repository.LocalDirectory != null");

            var relativeDirectory = HasPathRoot(directory)
                ? GetRelativePath(repository.LocalDirectory, directory)
                : directory;
            relativeDirectory = (relativeDirectory + "/").TrimStart("/");

            branch ??= await repository.GetDefaultBranch();
            var treeResponse = await Client.Git.Tree.GetRecursive(
                repository.GetGitHubOwner(),
                repository.GetGitHubName(),
                branch);

            return treeResponse.Tree
                .Where(x => x.Type == TreeType.Blob)
                .Where(x => x.Path.StartsWithOrdinalIgnoreCase(relativeDirectory))
                .Select(x => (repository.GetGitHubDownloadUrl(x.Path, branch), x.Path.TrimStart(relativeDirectory)));
        }

        public static async Task<string> GetDefaultBranch(this GitRepository repository)
        {
            ControlFlow.Assert(repository.IsGitHubRepository(), text: "repository.IsGitHubRepository()");

            var repo = await Client.Repository.Get(repository.GetGitHubOwner(), repository.GetGitHubName());
            return repo.DefaultBranch;
        }

        public static async Task<string> GetLatestRelease(this GitRepository repository, bool includePrerelease = false, bool trimPrefix = false)
        {
            ControlFlow.Assert(repository.IsGitHubRepository(), text: "repository.IsGitHubRepository()");

            var releases = await Client.Repository.Release.GetAll(repository.GetGitHubOwner(), repository.GetGitHubName());
            return releases.First(x => !x.Prerelease || includePrerelease).TagName.TrimStart(trimPrefix ? "v" : string.Empty);
        }

        [ItemCanBeNull]
        public static async Task<Milestone> GetGitHubMilestone(this GitRepository repository, string name)
        {
            ControlFlow.Assert(repository.IsGitHubRepository(), text: "repository.IsGitHubRepository()");

{'fraction_non_alphanumeric': 0.09865005192107996, 'fraction_numerical': 0.0013845621322256837, 'mean_word_length': 2.9501025290498974, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5892114', 'n_tokens_mistral': 1510, 'n_tokens_neox': 1414, 'n_words': 305}