using System.CommandLine; using JdeScoping.ConfigManager.Core.Services; using Microsoft.Extensions.DependencyInjection; namespace JdeScoping.ConfigManager.Cli.Commands; /// /// Validation command implementations. /// public static class ValidateCommand { /// /// Creates the validate appsettings command. /// public static Command CreateAppSettingsCommand( IServiceProvider serviceProvider, Option configPathOption, Option verboseOption, Option 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; } /// /// Creates the validate pipelines command. /// public static Command CreatePipelinesCommand( IServiceProvider serviceProvider, Option configPathOption, Option verboseOption, Option 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; } /// /// Creates the validate all command. /// public static Command CreateAllCommand( IServiceProvider serviceProvider, Option configPathOption, Option verboseOption, Option 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; } /// /// Creates the validate runtime command. /// public static Command CreateRuntimeCommand( IServiceProvider serviceProvider, Option configPathOption, Option verboseOption, Option 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 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(); var validationService = serviceProvider.GetRequiredService(); 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 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(); var validationService = serviceProvider.GetRequiredService(); 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 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(); 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 GetConfigFolderAsync(IServiceProvider serviceProvider, string? configPath) { if (!string.IsNullOrEmpty(configPath)) { if (Directory.Exists(configPath)) return configPath; return null; } var autoDiscoveryService = serviceProvider.GetRequiredService(); return await autoDiscoveryService.FindConfigFolderAsync(); } }