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.
This commit is contained in:
@@ -0,0 +1,273 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user