diff --git a/Sources/Kysect.Configuin.Core/CliExecution/CmdExecutionResult.cs b/Sources/Kysect.Configuin.Core/CliExecution/CmdExecutionResult.cs new file mode 100644 index 0000000..45492fb --- /dev/null +++ b/Sources/Kysect.Configuin.Core/CliExecution/CmdExecutionResult.cs @@ -0,0 +1,32 @@ +namespace Kysect.Configuin.Core.CliExecution; + +public class CmdExecutionResult +{ + public int ExitCode { get; init; } + public IReadOnlyCollection Errors { get; init; } + + public CmdExecutionResult(int exitCode, IReadOnlyCollection errors) + { + ExitCode = exitCode; + Errors = errors; + } + + public void ThrowIfAnyError() + { + if (Errors.Count == 1) + throw new CmdProcessException(Errors.Single()); + + if (Errors.Count > 0) + { + var exceptions = Errors + .Select(m => new CmdProcessException(m)) + .ToList(); + throw new AggregateException(exceptions); + } + + if (ExitCode != 0) + { + throw new CmdProcessException($"Return {ExitCode} exit code."); + } + } +} \ No newline at end of file diff --git a/Sources/Kysect.Configuin.Core/CliExecution/CmdProcess.cs b/Sources/Kysect.Configuin.Core/CliExecution/CmdProcess.cs new file mode 100644 index 0000000..89e70d0 --- /dev/null +++ b/Sources/Kysect.Configuin.Core/CliExecution/CmdProcess.cs @@ -0,0 +1,67 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Kysect.Configuin.Core.CliExecution; + +public class CmdProcess +{ + public CmdExecutionResult ExecuteCommand(string command) + { + using var process = new Process(); + + ProcessStartInfo startInfo = CreateProcessStartInfo(command); + + process.StartInfo = startInfo; + process.Start(); + process.WaitForExit(); + + int exitCode = process.ExitCode; + IReadOnlyCollection errors = GetErrors(process); + process.Close(); + + return new CmdExecutionResult(exitCode, errors); + } + + private ProcessStartInfo CreateProcessStartInfo(string command) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return new ProcessStartInfo + { + WindowStyle = ProcessWindowStyle.Hidden, + RedirectStandardError = true, + FileName = "cmd.exe", + Arguments = $"/C {command}" + }; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return new ProcessStartInfo + { + WindowStyle = ProcessWindowStyle.Hidden, + RedirectStandardError = true, + FileName = "sh", + Arguments = $"-c {command}" + }; + } + + throw new NotSupportedException(RuntimeInformation.OSDescription); + } + + private IReadOnlyCollection GetErrors(Process process) + { + var errors = new List(); + + // TODO: fixed error stream reading + // Line splitting triggered by char limit =_= + while (!process.StandardError.EndOfStream) + { + string? line = process.StandardError.ReadLine(); + if (line is not null) + errors.Add(line); + } + + return errors; + } +} \ No newline at end of file diff --git a/Sources/Kysect.Configuin.Core/CliExecution/CmdProcessException.cs b/Sources/Kysect.Configuin.Core/CliExecution/CmdProcessException.cs new file mode 100644 index 0000000..96c5dc6 --- /dev/null +++ b/Sources/Kysect.Configuin.Core/CliExecution/CmdProcessException.cs @@ -0,0 +1,12 @@ +namespace Kysect.Configuin.Core.CliExecution; + +public class CmdProcessException : Exception +{ + public CmdProcessException(string message) : base(message) + { + } + + public CmdProcessException() : base("Failed to execute cmd command") + { + } +} \ No newline at end of file diff --git a/Sources/Kysect.Configuin.Core/DotnetFormat/DotnetFormatCli.cs b/Sources/Kysect.Configuin.Core/DotnetFormat/DotnetFormatCli.cs new file mode 100644 index 0000000..bd238c9 --- /dev/null +++ b/Sources/Kysect.Configuin.Core/DotnetFormat/DotnetFormatCli.cs @@ -0,0 +1,19 @@ +using Kysect.Configuin.Core.CliExecution; + +namespace Kysect.Configuin.Core.DotnetFormat; + +public class DotnetFormatCli +{ + private readonly CmdProcess _cmdProcess = new CmdProcess(); + + public void Validate() + { + _cmdProcess.ExecuteCommand("dotnet format -h").ThrowIfAnyError(); + } + + public void GenerateWarnings(string pathToSolution, string pathToJson) + { + + _cmdProcess.ExecuteCommand($"dotnet format \"{pathToSolution}\" --verify-no-changes --report \"{pathToJson}\"").ThrowIfAnyError(); + } +} \ No newline at end of file diff --git a/Sources/Kysect.Configuin.Tests/CmdProcessTests.cs b/Sources/Kysect.Configuin.Tests/CmdProcessTests.cs new file mode 100644 index 0000000..5e54eca --- /dev/null +++ b/Sources/Kysect.Configuin.Tests/CmdProcessTests.cs @@ -0,0 +1,18 @@ +using FluentAssertions; +using Kysect.Configuin.Core.CliExecution; +using NUnit.Framework; + +namespace Kysect.Configuin.Tests; + +public class CmdProcessTests +{ + [Test] + public void Execute_ForInvalidCommand_ThrowError() + { + var cmdProcess = new CmdProcess(); + + CmdExecutionResult cmdExecutionResult = cmdProcess.ExecuteCommand("qwerasdf1234"); + + cmdExecutionResult.ExitCode.Should().NotBe(0); + } +} \ No newline at end of file diff --git a/Sources/Kysect.Configuin.Tests/DotnetFormat/DotnetFormatCliTests.cs b/Sources/Kysect.Configuin.Tests/DotnetFormat/DotnetFormatCliTests.cs new file mode 100644 index 0000000..5ef4184 --- /dev/null +++ b/Sources/Kysect.Configuin.Tests/DotnetFormat/DotnetFormatCliTests.cs @@ -0,0 +1,30 @@ +using Kysect.Configuin.Core.DotnetFormat; +using NUnit.Framework; + +namespace Kysect.Configuin.Tests.DotnetFormat; + +public class DotnetFormatCliTests +{ + private readonly DotnetFormatCli _dotnetFormatCli; + + public DotnetFormatCliTests() + { + _dotnetFormatCli = new DotnetFormatCli(); + } + + [Test] + [Ignore("This test require infrastructure")] + public void Validate_FinishedWithoutErrors() + { + _dotnetFormatCli.Validate(); + } + + [Test] + [Ignore("This test require infrastructure")] + public void GenerateWarnings_CreateReportFile() + { + const string pathToSln = "./../../../../"; + + _dotnetFormatCli.GenerateWarnings(pathToSln, "sample.json"); + } +} \ No newline at end of file