LLM: Code review suggestions plus what was changed:
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
* Simplify string splitting in GetGiteaConfiguration by using Span and avoid multiple splits for better performance. * Replace string.Split with more efficient string manipulation. * Use pattern matching and string.IsNullOrEmpty instead of !string.IsNullOrWhiteSpace when appropriate. * Catch specific exceptions instead of generic Exception to avoid swallowing important errors. * Add ConfigureAwait(false) to awaits for library code to avoid deadlocks in certain contexts. * Improve null checking for decision and JSON properties to avoid potential NullReferenceException. * Rename inconsistent variable names (e.g. repoGetContentsAsync is not a method). * Use StringComparer.Ordinal for dictionary key contains checks to be explicit. * Remove redundant TODOs or comments if any. * The method CreateVaultService is never used, consider removing or integrate. * Add XML documentation comments to public methods and class for better maintainability. * Minor formatting adjustments for readability and consistent code style. These changes aim at improving performance, robustness, maintainability, and follow best practices in async programming.
This commit is contained in:
@@ -15,10 +15,10 @@ public class ChangesCheckerAgent(IOpenAiService openAiService, IVaultService vau
|
||||
{
|
||||
try
|
||||
{
|
||||
var giteaApiToken = await vaultService.GetSecretAsync("api_keys/gitea", "gitea_api_token_write", "secret");
|
||||
var giteaApiToken = await vaultService.GetSecretAsync("api_keys/gitea", "gitea_api_token_write", "secret").ConfigureAwait(false);
|
||||
var giteaConfiguration = GetGiteaConfiguration(repositoryPath, giteaApiToken);
|
||||
var giteaClient = giteaService.CreateGiteaClient(giteaConfiguration);
|
||||
var lastChangesFromGitea = await GetLastChangesFromGiteaAsync(giteaClient, giteaConfiguration);
|
||||
var lastChangesFromGitea = await GetLastChangesFromGiteaAsync(giteaClient, giteaConfiguration).ConfigureAwait(false);
|
||||
|
||||
if (lastChangesFromGitea.Count == 0)
|
||||
{
|
||||
@@ -26,95 +26,102 @@ public class ChangesCheckerAgent(IOpenAiService openAiService, IVaultService vau
|
||||
}
|
||||
|
||||
var chatRequest = lastChangesFromGitea.Select(x => new ChatRequest(x.Key, x.Value));
|
||||
var prompt = await File.ReadAllTextAsync(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Prompts",
|
||||
"ChangesChecker.txt"));
|
||||
var promptPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Prompts", "ChangesChecker.txt");
|
||||
var prompt = await File.ReadAllTextAsync(promptPath).ConfigureAwait(false);
|
||||
|
||||
var decisionDoc = await openAiService.GetResponseFromChat(chatRequest, prompt);
|
||||
var decisionDoc = await openAiService.GetResponseFromChat(chatRequest, prompt).ConfigureAwait(false);
|
||||
|
||||
if (decisionDoc == null)
|
||||
{
|
||||
Console.WriteLine("AI‑Gate: no response from LLM, continuing by default.");
|
||||
Console.WriteLine("AI–Gate: no response from LLM, continuing by default.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
var decision = decisionDoc.RootElement.GetProperty("decision").GetString();
|
||||
if (!decisionDoc.RootElement.TryGetProperty("decision", out var decisionElement) || decisionElement.ValueKind == JsonValueKind.Null)
|
||||
{
|
||||
Console.WriteLine("AI–Gate: decision property missing or null in LLM response, continuing by default.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!decisionDoc.RootElement.TryGetProperty("changes", out var changesElement) ||
|
||||
changesElement.ValueKind == JsonValueKind.Null) return 0;
|
||||
var decision = decisionElement.GetString();
|
||||
|
||||
if (!decisionDoc.RootElement.TryGetProperty("changes", out var changesElement) || changesElement.ValueKind == JsonValueKind.Null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var content = GetFormattedJsonRequest(changesElement);
|
||||
var (status, response) = await giteaService.SendRequestAsync(giteaConfiguration, "contents", content);
|
||||
var (status, response) = await giteaService.SendRequestAsync(giteaConfiguration, "contents", content).ConfigureAwait(false);
|
||||
|
||||
if (status)
|
||||
{
|
||||
Console.WriteLine($"AI‑Gate: created PR with suggested changes.");
|
||||
Console.WriteLine("AI–Gate: created PR with suggested changes.");
|
||||
Console.WriteLine(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("AI‑Gate: failed to create PR with suggested changes.");
|
||||
Console.WriteLine("AI–Gate: failed to create PR with suggested changes.");
|
||||
Console.WriteLine(response);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Console.WriteLine("AI–Gate: operation was canceled.");
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"AI‑Gate: while processing: {ex.Message}");
|
||||
Console.WriteLine($"AI–Gate: while processing: {ex.Message}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, string>> GetLastChangesFromGiteaAsync(RepositoryApi giteaClient,
|
||||
GiteaConfiguration giteaConfiguration)
|
||||
private async Task<Dictionary<string, string>> GetLastChangesFromGiteaAsync(RepositoryApi giteaClient, GiteaConfiguration giteaConfiguration)
|
||||
{
|
||||
var lastChanges = new Dictionary<string, string>();
|
||||
var lastCommit = await giteaService.GetLastCommitAsync(giteaClient, giteaConfiguration);
|
||||
var lastChanges = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
var lastCommit = await giteaService.GetLastCommitAsync(giteaClient, giteaConfiguration).ConfigureAwait(false);
|
||||
|
||||
if (lastCommit == null || lastCommit.VarCommit.Message.Contains("LLM: Code review suggestions"))
|
||||
if (lastCommit == null || (lastCommit.VarCommit?.Message is not null && lastCommit.VarCommit.Message.Contains("LLM: Code review suggestions", StringComparison.Ordinal)))
|
||||
{
|
||||
return lastChanges;
|
||||
}
|
||||
|
||||
foreach (CommitAffectedFiles commitAffectedFile in lastCommit.Files)
|
||||
{
|
||||
var repoGetContentsAsync =
|
||||
await giteaService.GetFileContentAsync(giteaClient, giteaConfiguration, commitAffectedFile.Filename);
|
||||
var fileContent = await giteaService.GetFileContentAsync(giteaClient, giteaConfiguration, commitAffectedFile.Filename).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(repoGetContentsAsync.Content) &&
|
||||
!lastChanges.ContainsKey(commitAffectedFile.Filename))
|
||||
if (!string.IsNullOrEmpty(fileContent.Content) && !lastChanges.ContainsKey(commitAffectedFile.Filename))
|
||||
{
|
||||
lastChanges.Add(commitAffectedFile.Filename, Base64Decode(repoGetContentsAsync.Content));
|
||||
lastChanges.Add(commitAffectedFile.Filename, Base64Decode(fileContent.Content));
|
||||
}
|
||||
}
|
||||
|
||||
return lastChanges;
|
||||
}
|
||||
|
||||
private VaultService CreateVaultService()
|
||||
{
|
||||
var vaultUrl = Environment.GetEnvironmentVariable("VAULT_URL") ?? "http://vault:8200";
|
||||
var vaultToken = Environment.GetEnvironmentVariable("VAULT_TOKEN") ?? "dev-only-token";
|
||||
return new VaultService(vaultUrl, vaultToken);
|
||||
}
|
||||
|
||||
private GiteaConfiguration GetGiteaConfiguration(string repositoryPath, string giteaApiToken)
|
||||
{
|
||||
string owner = repositoryPath.Split("/").SkipLast(1).Last();
|
||||
string repository = repositoryPath.Split("/").Last();
|
||||
string branch = "master";
|
||||
string host = "https://git.modwad.pl";
|
||||
|
||||
ReadOnlySpan<char> repoSpan = repositoryPath.AsSpan();
|
||||
int lastSlash = repoSpan.LastIndexOf('/');
|
||||
int secondLastSlash = lastSlash > 0 ? repoSpan.Slice(0, lastSlash).LastIndexOf('/') : -1;
|
||||
|
||||
string owner = secondLastSlash >= 0 ? repoSpan.Slice(secondLastSlash + 1, lastSlash - secondLastSlash - 1).ToString() : string.Empty;
|
||||
string repository = lastSlash >= 0 ? repoSpan.Slice(lastSlash + 1).ToString() : repositoryPath;
|
||||
const string branch = "master";
|
||||
const string host = "https://git.modwad.pl";
|
||||
|
||||
return new GiteaConfiguration
|
||||
{
|
||||
Owner = owner,
|
||||
Repository = repository,
|
||||
Branch = branch,
|
||||
ApiToken = giteaApiToken,
|
||||
ApiToken = giteaApiToken,
|
||||
Host = host
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private string Base64Decode(string base64EncodedData)
|
||||
{
|
||||
byte[] bytes = Convert.FromBase64String(base64EncodedData);
|
||||
@@ -128,7 +135,7 @@ public class ChangesCheckerAgent(IOpenAiService openAiService, IVaultService vau
|
||||
var message = json.GetProperty("message").GetString();
|
||||
|
||||
var filesJson = json.GetProperty("files");
|
||||
var files = new List<object>();
|
||||
var files = new List<object>(filesJson.GetArrayLength());
|
||||
|
||||
foreach (var fileEl in filesJson.EnumerateArray())
|
||||
{
|
||||
@@ -155,7 +162,7 @@ public class ChangesCheckerAgent(IOpenAiService openAiService, IVaultService vau
|
||||
};
|
||||
|
||||
var jsonPayload = JsonSerializer.Serialize(payload);
|
||||
|
||||
|
||||
return new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user