SOLID refactoring: Abstract prerequisite checks into IPrerequisiteVerifier to bypass physical OS checks and fix Gitea CI/CD test run
Build and Test / build (push) Successful in 1m14s

This commit is contained in:
Marek Novák
2026-07-02 00:02:37 +02:00
parent dd7f1cdaa4
commit 8784ba7b57
7 changed files with 29 additions and 11 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ All future modifications to the `NixWslWrapper` solution must adhere to the foll
* **SOLID Principles**: * **SOLID Principles**:
* *Single Responsibility (SRP)*: Keep execution strategies, builders, stream copiers, and CLI formatting separated. * *Single Responsibility (SRP)*: Keep execution strategies, builders, stream copiers, and CLI formatting separated.
* *Open/Closed (OCP)*: If we need execution methods other than WSL (e.g. SSH, Local), implement a new strategy implementing `ICommandExecutor` rather than modifying `WslCommandExecutor`. * *Open/Closed (OCP)*: If we need execution methods other than WSL (e.g. SSH, Local), implement a new strategy implementing `ICommandExecutor` rather than modifying `WslCommandExecutor`.
* *Dependency Inversion (DIP)*: Inject interfaces (`ICommandExecutor`, `IStreamCopier`) and stream abstractions (`Stream`) to facilitate seamless unit testing and mock assertions. * *Dependency Inversion (DIP)*: Inject interfaces (`ICommandExecutor`, `IStreamCopier`, `IPrerequisiteVerifier`) and stream abstractions (`Stream`) to facilitate seamless unit testing and mock assertions without hitting physical OS or environmental components.
* **Visual UI/UX Check**: * **Visual UI/UX Check**:
* For CLI diagnostics, use `Spectre.Console` markup (`[color]...[/]`) to color-code output. Always escape literal brackets by doubling them (`[[literal-text]]`) to prevent parser errors. * For CLI diagnostics, use `Spectre.Console` markup (`[color]...[/]`) to color-code output. Always escape literal brackets by doubling them (`[[literal-text]]`) to prevent parser errors.
* Render a rich dashboard with `FigletText` and `Table` grids when administrative diagnostics are run (e.g. `--wsl-status`). * Render a rich dashboard with `FigletText` and `Table` grids when administrative diagnostics are run (e.g. `--wsl-status`).
+4 -2
View File
@@ -10,10 +10,12 @@ namespace NixWslWrapper.Cli
public class CliController public class CliController
{ {
private readonly ICommandExecutor _commandExecutor; private readonly ICommandExecutor _commandExecutor;
private readonly IPrerequisiteVerifier _prerequisiteVerifier;
public CliController(ICommandExecutor commandExecutor) public CliController(ICommandExecutor commandExecutor, IPrerequisiteVerifier prerequisiteVerifier)
{ {
_commandExecutor = commandExecutor ?? throw new ArgumentNullException(nameof(commandExecutor)); _commandExecutor = commandExecutor ?? throw new ArgumentNullException(nameof(commandExecutor));
_prerequisiteVerifier = prerequisiteVerifier ?? throw new ArgumentNullException(nameof(prerequisiteVerifier));
} }
public int Run(string[] args) public int Run(string[] args)
@@ -38,7 +40,7 @@ namespace NixWslWrapper.Cli
try try
{ {
PrerequisiteManager.EnsurePrerequisites(distro, user, profile); _prerequisiteVerifier.EnsurePrerequisites(distro, user, profile);
} }
catch (Exception ex) catch (Exception ex)
{ {
+2
View File
@@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection;
using NixWslWrapper.Core.Interfaces; using NixWslWrapper.Core.Interfaces;
using NixWslWrapper.Infrastructure.IO; using NixWslWrapper.Infrastructure.IO;
using NixWslWrapper.Infrastructure.Executors; using NixWslWrapper.Infrastructure.Executors;
using NixWslWrapper.Infrastructure.Services;
namespace NixWslWrapper.Cli namespace NixWslWrapper.Cli
{ {
@@ -20,6 +21,7 @@ namespace NixWslWrapper.Cli
return new ServiceCollection() return new ServiceCollection()
.AddSingleton<IStreamCopier, ThreadedStreamCopier>() .AddSingleton<IStreamCopier, ThreadedStreamCopier>()
.AddSingleton<ICommandExecutor, WslCommandExecutor>() .AddSingleton<ICommandExecutor, WslCommandExecutor>()
.AddSingleton<IPrerequisiteVerifier, WslPrerequisiteVerifier>()
.AddSingleton<CliController>() .AddSingleton<CliController>()
.BuildServiceProvider(); .BuildServiceProvider();
} }
@@ -0,0 +1,7 @@
namespace NixWslWrapper.Core.Interfaces
{
public interface IPrerequisiteVerifier
{
void EnsurePrerequisites(string distro, string user, string profilePath);
}
}
@@ -4,6 +4,10 @@
<ProjectReference Include="..\NixWslWrapper.Core\NixWslWrapper.Core.csproj" /> <ProjectReference Include="..\NixWslWrapper.Core\NixWslWrapper.Core.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Spectre.Console" Version="0.57.1" />
</ItemGroup>
<PropertyGroup> <PropertyGroup>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
@@ -2,20 +2,21 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using NixWslWrapper.Core.Interfaces;
using Spectre.Console; using Spectre.Console;
namespace NixWslWrapper.Cli namespace NixWslWrapper.Infrastructure.Services
{ {
public class PrerequisiteManager public class WslPrerequisiteVerifier : IPrerequisiteVerifier
{ {
public static void EnsurePrerequisites(string distro, string user, string profilePath) public void EnsurePrerequisites(string distro, string user, string profilePath)
{ {
EnsurePathRegistered(); EnsurePathRegistered();
EnsureWslAndDistro(distro); EnsureWslAndDistro(distro);
EnsureNix(distro, user, profilePath); EnsureNix(distro, user, profilePath);
} }
private static void EnsurePathRegistered() private void EnsurePathRegistered()
{ {
try try
{ {
@@ -55,7 +56,7 @@ namespace NixWslWrapper.Cli
} }
} }
private static void EnsureWslAndDistro(string distro) private void EnsureWslAndDistro(string distro)
{ {
// 1. Check if wsl.exe exists // 1. Check if wsl.exe exists
bool wslExists = false; bool wslExists = false;
@@ -146,7 +147,7 @@ namespace NixWslWrapper.Cli
} }
} }
private static void EnsureNix(string distro, string user, string profilePath) private void EnsureNix(string distro, string user, string profilePath)
{ {
bool nixInstalled = false; bool nixInstalled = false;
try try
+4 -2
View File
@@ -13,12 +13,13 @@ namespace NixWslWrapper.Tests
public void CliController_ForwardArguments_ShouldReturnExecutorExitCode() public void CliController_ForwardArguments_ShouldReturnExecutorExitCode()
{ {
var mockExecutor = new Mock<ICommandExecutor>(); var mockExecutor = new Mock<ICommandExecutor>();
var mockVerifier = new Mock<IPrerequisiteVerifier>();
var expectedResult = new ExecutionResult(42); var expectedResult = new ExecutionResult(42);
mockExecutor mockExecutor
.Setup(m => m.Execute(It.IsAny<NixArguments>(), It.IsAny<WslTarget>())) .Setup(m => m.Execute(It.IsAny<NixArguments>(), It.IsAny<WslTarget>()))
.Returns(expectedResult); .Returns(expectedResult);
var controller = new CliController(mockExecutor.Object); var controller = new CliController(mockExecutor.Object, mockVerifier.Object);
string[] cliArgs = new[] { "run", "nixpkgs#hello" }; string[] cliArgs = new[] { "run", "nixpkgs#hello" };
int exitCode = controller.Run(cliArgs); int exitCode = controller.Run(cliArgs);
@@ -34,7 +35,8 @@ namespace NixWslWrapper.Tests
public void CliController_HelpMenuFlag_ShouldReturnZeroImmediately() public void CliController_HelpMenuFlag_ShouldReturnZeroImmediately()
{ {
var mockExecutor = new Mock<ICommandExecutor>(); var mockExecutor = new Mock<ICommandExecutor>();
var controller = new CliController(mockExecutor.Object); var mockVerifier = new Mock<IPrerequisiteVerifier>();
var controller = new CliController(mockExecutor.Object, mockVerifier.Object);
string[] cliArgs = new[] { "--wsl-help" }; string[] cliArgs = new[] { "--wsl-help" };
int exitCode = controller.Run(cliArgs); int exitCode = controller.Run(cliArgs);