Files
jdescopingtool/NEW/src/Utils/JdeScoping.ConfigManager.Cli/Commands/ValidateCommand.cs
T
Joseph Doherty 7c4781dfe3 refactor(configmanager): split into Core, CLI, and UI projects
Extract shared models, services, and application logic into
JdeScoping.ConfigManager.Core library. Add JdeScoping.ConfigManager.Cli
console app with validate, test-connection, and secret commands using
System.CommandLine. UI project now references Core for platform-agnostic
functionality while retaining Avalonia-specific dialog and clipboard services.
2026-01-28 10:01:48 -05:00

274 lines
9.1 KiB
C#

using System.CommandLine;
using JdeScoping.ConfigManager.Core.Services;
using Microsoft.Extensions.DependencyInjection;
namespace JdeScoping.ConfigManager.Cli.Commands;
/// <summary>
/// Validation command implementations.
/// </summary>
public static class ValidateCommand
{
/// <summary>
/// Creates the validate appsettings command.
/// </summary>
public static Command CreateAppSettingsCommand(
IServiceProvider serviceProvider,
Option<string?> configPathOption,
Option<bool> verboseOption,
Option<bool> quietOption)
{
var command = new Command("appsettings", "Validate appsettings.json");
command.SetHandler(async (string? configPath, bool verbose, bool quiet) =>
{
var exitCode = await ValidateAppSettingsAsync(serviceProvider, configPath, verbose, quiet);
Environment.ExitCode = exitCode;
}, configPathOption, verboseOption, quietOption);
return command;
}
/// <summary>
/// Creates the validate pipelines command.
/// </summary>
public static Command CreatePipelinesCommand(
IServiceProvider serviceProvider,
Option<string?> configPathOption,
Option<bool> verboseOption,
Option<bool> quietOption)
{
var command = new Command("pipelines", "Validate pipeline configuration files");
command.SetHandler(async (string? configPath, bool verbose, bool quiet) =>
{
var exitCode = await ValidatePipelinesAsync(serviceProvider, configPath, verbose, quiet);
Environment.ExitCode = exitCode;
}, configPathOption, verboseOption, quietOption);
return command;
}
/// <summary>
/// Creates the validate all command.
/// </summary>
public static Command CreateAllCommand(
IServiceProvider serviceProvider,
Option<string?> configPathOption,
Option<bool> verboseOption,
Option<bool> quietOption)
{
var command = new Command("all", "Validate all configuration files");
command.SetHandler(async (string? configPath, bool verbose, bool quiet) =>
{
var exitCode1 = await ValidateAppSettingsAsync(serviceProvider, configPath, verbose, quiet);
var exitCode2 = await ValidatePipelinesAsync(serviceProvider, configPath, verbose, quiet);
Environment.ExitCode = Math.Max(exitCode1, exitCode2);
}, configPathOption, verboseOption, quietOption);
return command;
}
/// <summary>
/// Creates the validate runtime command.
/// </summary>
public static Command CreateRuntimeCommand(
IServiceProvider serviceProvider,
Option<string?> configPathOption,
Option<bool> verboseOption,
Option<bool> quietOption)
{
var command = new Command("runtime", "Run Infrastructure validators");
command.SetHandler(async (string? configPath, bool verbose, bool quiet) =>
{
var exitCode = await ValidateRuntimeAsync(serviceProvider, configPath, verbose, quiet);
Environment.ExitCode = exitCode;
}, configPathOption, verboseOption, quietOption);
return command;
}
private static async Task<int> ValidateAppSettingsAsync(
IServiceProvider serviceProvider,
string? configPath,
bool verbose,
bool quiet)
{
var folderPath = await GetConfigFolderAsync(serviceProvider, configPath);
if (folderPath == null)
{
Console.Error.WriteLine("Error: Could not find configuration folder. Use --config-path to specify.");
return 1;
}
var configFileService = serviceProvider.GetRequiredService<IConfigFileService>();
var validationService = serviceProvider.GetRequiredService<IValidationService>();
var appSettingsPath = Path.Combine(folderPath, "appsettings.json");
if (!File.Exists(appSettingsPath))
{
Console.Error.WriteLine($"Error: appsettings.json not found at {appSettingsPath}");
return 1;
}
try
{
var config = await configFileService.LoadAppSettingsAsync(appSettingsPath);
var result = validationService.ValidateAppSettings(config);
if (!quiet)
{
Console.WriteLine("=== AppSettings Validation ===");
Console.WriteLine($"File: {appSettingsPath}");
}
if (result.IsValid)
{
if (!quiet)
Console.WriteLine("Status: Valid");
return 0;
}
foreach (var error in result.Errors)
{
Console.Error.WriteLine($"Error: {error}");
}
foreach (var warning in result.Warnings)
{
if (!quiet)
Console.WriteLine($"Warning: {warning}");
}
return 1;
}
catch (ConfigLoadException ex)
{
Console.Error.WriteLine($"Error loading configuration: {ex.Message}");
return 1;
}
}
private static async Task<int> ValidatePipelinesAsync(
IServiceProvider serviceProvider,
string? configPath,
bool verbose,
bool quiet)
{
var folderPath = await GetConfigFolderAsync(serviceProvider, configPath);
if (folderPath == null)
{
Console.Error.WriteLine("Error: Could not find configuration folder. Use --config-path to specify.");
return 1;
}
var configFileService = serviceProvider.GetRequiredService<IConfigFileService>();
var validationService = serviceProvider.GetRequiredService<IValidationService>();
var pipelinesDir = Path.Combine(folderPath, "Pipelines");
try
{
var pipelines = await configFileService.LoadAllPipelinesAsync(pipelinesDir);
var result = validationService.ValidatePipelines(pipelines);
if (!quiet)
{
Console.WriteLine("=== Pipelines Validation ===");
Console.WriteLine($"Directory: {pipelinesDir}");
Console.WriteLine($"Pipelines found: {pipelines.Count}");
}
if (result.IsValid)
{
if (!quiet)
Console.WriteLine("Status: Valid");
return 0;
}
foreach (var error in result.Errors)
{
Console.Error.WriteLine($"Error: {error}");
}
foreach (var warning in result.Warnings)
{
if (!quiet)
Console.WriteLine($"Warning: {warning}");
}
return result.Errors.Count > 0 ? 1 : 0;
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error validating pipelines: {ex.Message}");
return 1;
}
}
private static async Task<int> ValidateRuntimeAsync(
IServiceProvider serviceProvider,
string? configPath,
bool verbose,
bool quiet)
{
var folderPath = await GetConfigFolderAsync(serviceProvider, configPath);
if (folderPath == null)
{
Console.Error.WriteLine("Error: Could not find configuration folder. Use --config-path to specify.");
return 1;
}
var runtimeValidationService = serviceProvider.GetRequiredService<IRuntimeConfigValidationService>();
if (!quiet)
{
Console.WriteLine("=== Runtime Configuration Validation ===");
Console.WriteLine($"Folder: {folderPath}");
}
var results = runtimeValidationService.ValidateRuntimeConfig(folderPath);
var hasErrors = false;
foreach (var result in results)
{
if (result.Errors.Count > 0)
{
hasErrors = true;
Console.Error.WriteLine($"\n[{result.ValidatorName}]");
foreach (var error in result.Errors)
{
Console.Error.WriteLine($" Error: {error}");
}
}
else if (!quiet)
{
Console.WriteLine($"[{result.ValidatorName}]: OK");
}
foreach (var warning in result.Warnings)
{
if (!quiet)
Console.WriteLine($" Warning: {warning}");
}
}
return hasErrors ? 1 : 0;
}
private static async Task<string?> GetConfigFolderAsync(IServiceProvider serviceProvider, string? configPath)
{
if (!string.IsNullOrEmpty(configPath))
{
if (Directory.Exists(configPath))
return configPath;
return null;
}
var autoDiscoveryService = serviceProvider.GetRequiredService<IAutoDiscoveryService>();
return await autoDiscoveryService.FindConfigFolderAsync();
}
}