btcpayserver-plugin-builder/PluginBuilder/Services/GithubService.cs
Chukwuleta Tobechi bb44aaf095 save snapshot
2026-02-19 16:10:05 +01:00

115 lines
4.1 KiB
C#

using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PluginBuilder.APIModels;
namespace PluginBuilder.Services;
public static class GithubService
{
private static readonly Regex GithubRepositoryRegex = new("^https://(www\\.)?github\\.com/([^/]+)/([^/]+)/?");
public static async Task<List<GitHubContributor>> GetContributorsAsync(HttpClient githubClient, string gitRepository, string pluginDir)
{
var repo = ParseRepository(gitRepository);
if (repo == null)
return new List<GitHubContributor>();
var pathQuery = string.IsNullOrEmpty(pluginDir) ? "" : $"&path={Uri.EscapeDataString(pluginDir)}";
var contributors = new Dictionary<string, GitHubContributor>(StringComparer.OrdinalIgnoreCase);
int page = 1;
const int perPage = 100;
try
{
while (true)
{
var apiPath = $"repos/{repo.Value.Owner}/{repo.Value.RepoName}/commits?per_page={perPage}&page={page}{pathQuery}";
using var response = await githubClient.GetAsync(apiPath);
if (!response.IsSuccessStatusCode)
break;
var json = await response.Content.ReadAsStringAsync();
var commits = JsonConvert.DeserializeObject<List<GitHubCommit>>(json);
if (commits == null || commits.Count == 0)
break;
foreach (var commit in commits)
{
var login = commit.Author?.Login;
if (commit.Author == null || string.IsNullOrEmpty(login))
continue;
if (contributors.TryGetValue(login, out var existing))
{
existing.Contributions++;
}
else
{
contributors[login] = new GitHubContributor
{
Login = commit.Author.Login,
AvatarUrl = commit.Author.AvatarUrl,
HtmlUrl = commit.Author.HtmlUrl,
Contributions = 1
};
}
}
if (!response.Headers.TryGetValues("Link", out var linkHeaders) || !linkHeaders.Any(l => l.Contains("rel=\"next\"")))
break;
page++;
}
return contributors.Values.OrderByDescending(c => c.Contributions).ToList();
}
catch (Exception)
{
return new List<GitHubContributor>();
}
}
public static async Task SaveSnapshot(string pluginDataDir, PluginSlug pluginSlug, List<GitHubContributor> contributors)
{
if (!Directory.Exists(pluginDataDir))
Directory.CreateDirectory(pluginDataDir);
var filePath = Path.Combine(pluginDataDir, $"{pluginSlug}.json");
var data = new JObject
{
["contributors"] = JArray.FromObject(contributors)
};
await File.WriteAllTextAsync(filePath, data.ToString(Formatting.Indented));
}
public static List<GitHubContributor> LoadSnapshot(string pluginDataDir, PluginSlug pluginSlug)
{
if (!Directory.Exists(pluginDataDir))
Directory.CreateDirectory(pluginDataDir);
try
{
var filePath = Path.Combine(pluginDataDir, $"{pluginSlug}.json");
if (!File.Exists(filePath))
return new List<GitHubContributor>();
var json = File.ReadAllText(filePath);
var data = JObject.Parse(json);
return data["contributors"]?.ToObject<List<GitHubContributor>>() ?? new();
}
catch (Exception)
{
return new();
}
}
private static (string Owner, string RepoName)? ParseRepository(string gitRepository)
{
if (string.IsNullOrEmpty(gitRepository))
return null;
var match = GithubRepositoryRegex.Match(gitRepository);
if (!match.Success)
return null;
return (match.Groups[2].Value, match.Groups[3].Value);
}
}