using System.Text; using Approve.Checker.Gitlab; using GitLabApiClient; using GitLabApiClient.Models.Commits.Responses; using GitLabApiClient.Models.MergeRequests.Responses; using GitLabApiClient.Models.Notes.Requests; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; using Settings = Approve.Checker.Gitlab.Settings; namespace Approve.Checker; public class App : IApp { private readonly GitLabClient _client; private readonly Settings _settings; private readonly GitlabCustomClient _customClient; public App() { var httpHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (_, _, _, _) => true }; _settings = new Settings(); _client = new GitLabClient(_settings.GitlabUrl, _settings.GitlabToken, httpHandler); _customClient = new GitlabCustomClient(_settings.GitlabUrl, _settings.GitlabToken, httpHandler); } public async Task Run() { if (string.IsNullOrEmpty(_settings.Approvers)) { Console.WriteLine("Approvers in empty, please define APPROVERS_FILEPATH."); return 0; } if (string.IsNullOrEmpty(_settings.MrPath)) { Console.WriteLine("Not in MergeRequest. Exiting."); return 0; } var mrId = int.Parse(_settings.MrPath.Split('!')[1]); var mergeRequest = await _client.MergeRequests.GetAsync(_settings.ProjectId, mrId); var commit = await _client.Commits.GetAsync(_settings.ProjectId, mergeRequest.Sha); if (!await IsApproved(mergeRequest, commit)) { return -1; } return 0; } private async Task IsApproved(MergeRequest mergeRequest, Commit commit) { var approversDict = ParseApprovers(); if (approversDict is null) { return false; } var emojis = await _client.MergeRequests.GetAwardEmojisAsync(_settings.ProjectId, mergeRequest.Iid); var sb = new StringBuilder(); foreach (var emoji in emojis) { if (emoji.UpdatedAt <= commit.CommittedDate) { sb.AppendLine($" - Удален {emoji.Name} от {emoji.User.Username} ({emoji.UpdatedAt}), т.к. после него были коммиты ({commit.CommittedDate})."); await _customClient.DeleteEmoji(mergeRequest.ProjectId, mergeRequest.Iid, emoji.Id); } } if (sb.Length > 0) { await _client.MergeRequests.CreateNoteAsync(mergeRequest.ProjectId, mergeRequest.Iid, new CreateMergeRequestNoteRequest(sb.ToString())); } emojis = emojis.Where(f => f.UpdatedAt > commit.CommittedDate).ToArray(); foreach (var approversGroup in approversDict) { var needCount = approversGroup.Value.CountApprovers; var groupApproves = 0; var approvedInGroup = new List(); foreach (var approveUser in approversGroup.Value.Users) { if (emojis.Any(f => f.User.Username == approveUser)) { approvedInGroup.Add(approveUser); groupApproves++; if (groupApproves >= needCount) { var approvers = string.Join(",", approvedInGroup); Console.WriteLine($"[+] Approved by group of {approversGroup.Key} ({approvers})."); break; } } } if (groupApproves < needCount) { Console.WriteLine($"[-] Need to be approved by group of {approversGroup.Key} (current approves: {groupApproves}, need: {needCount}):"); foreach (var approveUser in approversGroup.Value.Users) { Console.WriteLine($" - {approveUser}"); } return false; } } return true; } private Dictionary? ParseApprovers() { var deserializer = new DeserializerBuilder() .WithNamingConvention(UnderscoredNamingConvention.Instance) .Build(); try { return deserializer.Deserialize>(_settings.Approvers); } catch (Exception ex) { Console.WriteLine($"Error while deserializing approvers: {ex}"); return null; } } }