diff --git a/CodeQuality.sln b/CodeQuality.sln index 96bf783..cc0ac21 100644 --- a/CodeQuality.sln +++ b/CodeQuality.sln @@ -48,6 +48,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoloX.CodeQuality.Playwrigh EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoloX.CodeQuality.Playwright.E2ETest", "src\tests\SoloX.CodeQuality.Playwright.E2ETest\SoloX.CodeQuality.Playwright.E2ETest.csproj", "{D0CDEC61-7956-4F49-AC4D-C0DA3063969F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoloX.CodeQuality.TestTool", "src\tests\SoloX.CodeQuality.TestTool\SoloX.CodeQuality.TestTool.csproj", "{C92C3947-9EBB-43E3-9104-58CADE937BB3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -106,6 +108,10 @@ Global {D0CDEC61-7956-4F49-AC4D-C0DA3063969F}.Debug|Any CPU.Build.0 = Debug|Any CPU {D0CDEC61-7956-4F49-AC4D-C0DA3063969F}.Release|Any CPU.ActiveCfg = Release|Any CPU {D0CDEC61-7956-4F49-AC4D-C0DA3063969F}.Release|Any CPU.Build.0 = Release|Any CPU + {C92C3947-9EBB-43E3-9104-58CADE937BB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C92C3947-9EBB-43E3-9104-58CADE937BB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C92C3947-9EBB-43E3-9104-58CADE937BB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C92C3947-9EBB-43E3-9104-58CADE937BB3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -124,6 +130,7 @@ Global {3507CA64-D718-427E-BA4F-40986B34F56A} = {5B172423-1455-41CB-8D81-7DCFCFF8855D} {B339195D-10B0-471F-9401-F883B18838CE} = {5B172423-1455-41CB-8D81-7DCFCFF8855D} {D0CDEC61-7956-4F49-AC4D-C0DA3063969F} = {1D5021C0-2423-494A-98F6-71AB937CDF8B} + {C92C3947-9EBB-43E3-9104-58CADE937BB3} = {1D5021C0-2423-494A-98F6-71AB937CDF8B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {74BCF463-5FDE-4DBC-B32A-431E8A228CA0} diff --git a/README.md b/README.md index 7353819..2f38412 100644 --- a/README.md +++ b/README.md @@ -52,26 +52,26 @@ You can checkout this Github repository or you can use the NuGet package: **Install using the command line from the Package Manager:** ```bash -Install-Package SoloX.CodeQuality.Prod -version 2.3.3 +Install-Package SoloX.CodeQuality.Prod -version 2.3.4 or -Install-Package SoloX.CodeQuality.Test -version 2.3.3 +Install-Package SoloX.CodeQuality.Test -version 2.3.4 ``` **Install using the .Net CLI:** ```bash -dotnet add package SoloX.CodeQuality.Prod --version 2.3.3 +dotnet add package SoloX.CodeQuality.Prod --version 2.3.4 or -dotnet add package SoloX.CodeQuality.Test --version 2.3.3 +dotnet add package SoloX.CodeQuality.Test --version 2.3.4 ``` **Install editing your project file (csproj):** ```xml - + all runtime; build; native; contentfiles; analyzers or - + all runtime; build; native; contentfiles; analyzers @@ -218,17 +218,17 @@ You can checkout this Github repository or use the NuGet package: **Install using the command line from the Package Manager:** ```bash -Install-Package SoloX.CodeQuality.Playwright -version 2.3.3 +Install-Package SoloX.CodeQuality.Playwright -version 2.3.4 ``` **Install using the .Net CLI:** ```bash -dotnet add package SoloX.CodeQuality.Playwright --version 2.3.3 +dotnet add package SoloX.CodeQuality.Playwright --version 2.3.4 ``` **Install editing your project file (csproj):** ```xml - + ``` * * * @@ -424,29 +424,29 @@ You can checkout this Github repository or you can use the NuGet package: **Install using the command line from the Package Manager:** ```bash -Install-Package SoloX.CodeQuality.Test.Helpers -version 2.3.3 +Install-Package SoloX.CodeQuality.Test.Helpers -version 2.3.4 -Install-Package SoloX.CodeQuality.Test.Helpers.XUnit -version 2.3.3 +Install-Package SoloX.CodeQuality.Test.Helpers.XUnit -version 2.3.4 -Install-Package SoloX.CodeQuality.Test.Helpers.NUnit -version 2.3.3 +Install-Package SoloX.CodeQuality.Test.Helpers.NUnit -version 2.3.4 ``` **Install using the .Net CLI:** ```bash -dotnet add package SoloX.CodeQuality.Test.Helpers --version 2.3.3 +dotnet add package SoloX.CodeQuality.Test.Helpers --version 2.3.4 -dotnet add package SoloX.CodeQuality.Test.Helpers.XUnit --version 2.3.3 +dotnet add package SoloX.CodeQuality.Test.Helpers.XUnit --version 2.3.4 -dotnet add package SoloX.CodeQuality.Test.Helpers.NUnit --version 2.3.3 +dotnet add package SoloX.CodeQuality.Test.Helpers.NUnit --version 2.3.4 ``` **Install editing your project file (csproj):** ```xml - + - + - + ``` * * * diff --git a/src/SharedProperties.props b/src/SharedProperties.props index 1fc2487..1c56ddb 100644 --- a/src/SharedProperties.props +++ b/src/SharedProperties.props @@ -1,7 +1,7 @@ - 2.3.3 + 2.3.4 Xavier Solau Copyright © 2021 Xavier Solau MIT @@ -14,7 +14,7 @@ $(PackageLicenseExpression) LICENSE - 2.3.3.0 + 2.3.4.0 12 diff --git a/src/libs/SoloX.CodeQuality.Prod/build/SoloX.CodeQuality.Prod.targets b/src/libs/SoloX.CodeQuality.Prod/build/SoloX.CodeQuality.Prod.targets index c2163f4..dd2fed5 100644 --- a/src/libs/SoloX.CodeQuality.Prod/build/SoloX.CodeQuality.Prod.targets +++ b/src/libs/SoloX.CodeQuality.Prod/build/SoloX.CodeQuality.Prod.targets @@ -108,7 +108,7 @@ $(MSBuildProjectDirectory)/.editorconfig - $(MSBuildProjectDirectory)/obj/.editorconfig + $(MSBuildProjectDirectory)/obj/.editorconfig-$(TargetFramework) $(MSBuildThisFileDirectory)../resources/style.cs.compiler.ca.editorconfig $(MSBuildThisFileDirectory)../resources/style.cs.compiler.cs.editorconfig $(MSBuildThisFileDirectory)../resources/style.cs.ide1.editorconfig diff --git a/src/libs/SoloX.CodeQuality.Test.Helpers/DotnetHelper.cs b/src/libs/SoloX.CodeQuality.Test.Helpers/DotnetHelper.cs index 0d729e1..b8ebec5 100644 --- a/src/libs/SoloX.CodeQuality.Test.Helpers/DotnetHelper.cs +++ b/src/libs/SoloX.CodeQuality.Test.Helpers/DotnetHelper.cs @@ -6,6 +6,9 @@ // // ---------------------------------------------------------------------- +using System.Collections.Specialized; +using System; + namespace SoloX.CodeQuality.Test.Helpers { #pragma warning disable CA1021 // Avoid out parameters @@ -25,65 +28,92 @@ public static class DotnetHelper private const string ADD = "add"; private const string PACKAGE = "package"; private const string REFERENCE = "reference "; + private const string TOOL = "tool"; + private const string TOOL_MANIFEST = "tool-manifest"; + private const string INSTALL = "install"; + + public static bool Restore(string projectPath, out ProcessResult processResult, + Action? environmentVariablesHandler = null) + { + return Dotnet(projectPath, RESTORE, out processResult, environmentVariablesHandler); + } + + public static bool Build(string projectPath, out ProcessResult processResult, + Action? environmentVariablesHandler = null) + { + return Dotnet(projectPath, BUILD, out processResult, environmentVariablesHandler); + } - public static bool Restore(string projectPath, out ProcessResult processResult) + public static bool Test(string projectPath, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return Dotnet(projectPath, RESTORE, out processResult); + return Dotnet(projectPath, TEST, out processResult, environmentVariablesHandler); } - public static bool Build(string projectPath, out ProcessResult processResult) + public static bool Publish(string projectPath, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return Dotnet(projectPath, BUILD, out processResult); + return Dotnet(projectPath, PUBLISH, out processResult, environmentVariablesHandler); } - public static bool Test(string projectPath, out ProcessResult processResult) + public static bool New(string path, string template, string output, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return Dotnet(projectPath, TEST, out processResult); + return Dotnet(path, $"{NEW} {template} --output {output}", out processResult, environmentVariablesHandler); } - public static bool Publish(string projectPath, out ProcessResult processResult) + public static bool NewSln(string path, string solutionName, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return Dotnet(projectPath, PUBLISH, out processResult); + return New(path, SLN, solutionName, out processResult, environmentVariablesHandler); } - public static bool New(string path, string template, string output, out ProcessResult processResult) + public static bool SlnAdd(string path, string project, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return Dotnet(path, $"{NEW} {template} --output {output}", out processResult); + return Dotnet(path, $"{SLN} {ADD} {project}", out processResult, environmentVariablesHandler); } - public static bool NewSln(string path, string solutionName, out ProcessResult processResult) + public static bool AddPackage(string path, string projectFilePath, string packageName, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return New(path, SLN, solutionName, out processResult); + return Dotnet(path, $"{ADD} {projectFilePath} {PACKAGE} {packageName}", out processResult, environmentVariablesHandler); } - public static bool SlnAdd(string path, string project, out ProcessResult processResult) + public static bool AddReference(string path, string projectFilePath, string projectReferenceFilePath, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return Dotnet(path, $"{SLN} {ADD} {project}", out processResult); + return Dotnet(path, $"{ADD} {projectFilePath} {REFERENCE} {projectReferenceFilePath}", out processResult, environmentVariablesHandler); } - public static bool AddPackage(string path, string projectFilePath, string packageName, out ProcessResult processResult) + public static bool Run(string projectPath, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return Dotnet(path, $"{ADD} {projectFilePath} {PACKAGE} {packageName}", out processResult); + return Run(projectPath, string.Empty, out processResult, environmentVariablesHandler); } - public static bool AddReference(string path, string projectFilePath, string projectReferenceFilePath, out ProcessResult processResult) + public static bool Run(string projectPath, string args, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return Dotnet(path, $"{ADD} {projectFilePath} {REFERENCE} {projectReferenceFilePath}", out processResult); + return Dotnet(projectPath, $"{RUN} {args}", out processResult, environmentVariablesHandler); } - public static bool Run(string projectPath, out ProcessResult processResult) + internal static bool NewToolManifest(string path, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return Run(projectPath, string.Empty, out processResult); + return Dotnet(path, $"{NEW} {TOOL_MANIFEST}", out processResult, environmentVariablesHandler); } - public static bool Run(string projectPath, string args, out ProcessResult processResult) + internal static bool ToolInstall(string path, string toolName, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - return Dotnet(projectPath, $"{RUN} {args}", out processResult); + return Dotnet(path, $"{TOOL} {INSTALL} {toolName}", out processResult, environmentVariablesHandler); } - public static bool Dotnet(string path, string args, out ProcessResult processResult) + public static bool Dotnet(string path, string args, out ProcessResult processResult, + Action? environmentVariablesHandler = null) { - processResult = ProcessHelper.Run(path, DOTNET, args); + processResult = ProcessHelper.Run(path, DOTNET, args, environmentVariablesHandler); return processResult.ExitCode == 0; } } diff --git a/src/libs/SoloX.CodeQuality.Test.Helpers/ProcessHelper.cs b/src/libs/SoloX.CodeQuality.Test.Helpers/ProcessHelper.cs index 3dea878..c7cf85a 100644 --- a/src/libs/SoloX.CodeQuality.Test.Helpers/ProcessHelper.cs +++ b/src/libs/SoloX.CodeQuality.Test.Helpers/ProcessHelper.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Diagnostics; using System.Linq; using System.Text; @@ -28,9 +29,11 @@ public static class ProcessHelper /// The command arguments. /// Standard output. /// Error output. + /// Handler to set up process environment variables. /// The process exit code. public static int Run(string workingDirectory, string command, string arguments, - out string stdout, out string stderr) + out string stdout, out string stderr, + Action? environmentVariablesHandler = null) { var outBuilder = new StringBuilder(); var errBuilder = new StringBuilder(); @@ -40,7 +43,8 @@ public static int Run(string workingDirectory, string command, string arguments, command, arguments, s => outBuilder.Append(s), - s => errBuilder.Append(s)); + s => errBuilder.Append(s), + environmentVariablesHandler); stderr = errBuilder.ToString(); stdout = outBuilder.ToString(); @@ -54,8 +58,10 @@ public static int Run(string workingDirectory, string command, string arguments, /// Working directory. /// The command to run. /// The command arguments. + /// Handler to set up process environment variables. /// The process result. - public static ProcessResult Run(string workingDirectory, string command, string arguments) + public static ProcessResult Run(string workingDirectory, string command, string arguments, + Action? environmentVariablesHandler = null) { var processResult = new ProcessResult(); @@ -64,7 +70,8 @@ public static ProcessResult Run(string workingDirectory, string command, string command, arguments, processResult.AppendInfo, - processResult.AppendError); + processResult.AppendError, + environmentVariablesHandler); processResult.SetReturnCode(exitCode); @@ -72,7 +79,8 @@ public static ProcessResult Run(string workingDirectory, string command, string } private static int RunInternal(string workingDirectory, string command, string arguments, - Action outCallback, Action errorCallback) + Action outCallback, Action errorCallback, + Action? environmentVariablesHandler) { using (var process = new Process()) using (var outputWaitHandle = new AutoResetEvent(false)) @@ -109,6 +117,8 @@ private static int RunInternal(string workingDirectory, string command, string a RedirectStandardInput = true, }; + environmentVariablesHandler?.Invoke(dotnetStartInfo.EnvironmentVariables); + process.StartInfo = dotnetStartInfo; process.Start(); @@ -131,10 +141,8 @@ private static int RunInternal(string workingDirectory, string command, string a /// /// Message log. /// Tells if this is an error log. - public record Log(string Message, bool IsError) - { - public DateTime TimeStamp { get; } = DateTime.Now; - } + /// Log message time stamp. + public record struct Log(string Message, bool IsError, DateTime TimeStamp); /// /// Process logs. @@ -155,12 +163,12 @@ public class ProcessResult internal void AppendInfo(string logMessage) { - this.logs.Add(new Log(logMessage, false)); + this.logs.Add(new Log(logMessage, false, DateTime.Now)); } internal void AppendError(string logMessage) { - this.logs.Add(new Log(logMessage, true)); + this.logs.Add(new Log(logMessage, true, DateTime.Now)); } internal void SetReturnCode(int exitCode) diff --git a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Exceptions/ProjectBuilderException.cs b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Exceptions/ProjectBuilderException.cs deleted file mode 100644 index 4f6076d..0000000 --- a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Exceptions/ProjectBuilderException.cs +++ /dev/null @@ -1,40 +0,0 @@ -// ---------------------------------------------------------------------- -// -// Copyright © 2021 Xavier Solau. -// Licensed under the MIT license. -// See LICENSE file in the project root for full license information. -// -// ---------------------------------------------------------------------- - -using System; - -namespace SoloX.CodeQuality.Test.Helpers.Solution.Exceptions -{ - /// - /// Exception while building a project part. - /// - public class ProjectBuilderException : Exception - { - private readonly ProcessResult? processResult; - - public ProjectBuilderException() - { - } - - public ProjectBuilderException(string message) - : base(message) - { - } - - public ProjectBuilderException(ProcessResult processResult) - : this(processResult.GetLogs()) - { - this.processResult = processResult; - } - - public ProjectBuilderException(string message, Exception innerException) - : base(message, innerException) - { - } - } -} diff --git a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Exceptions/SolutionBuilderException.cs b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Exceptions/SolutionBuilderException.cs index 7b9fa3d..f3a4901 100644 --- a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Exceptions/SolutionBuilderException.cs +++ b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Exceptions/SolutionBuilderException.cs @@ -10,12 +10,22 @@ namespace SoloX.CodeQuality.Test.Helpers.Solution.Exceptions { + public abstract class ASolutionBuilderError { } + + public sealed class BuilderError : ASolutionBuilderError { } + public sealed class SolutionError : ASolutionBuilderError { } + public sealed class ProjectError : ASolutionBuilderError { } + public sealed class TestError : ASolutionBuilderError { } + public sealed class ToolError : ASolutionBuilderError { } + public sealed class NugetConfigError : ASolutionBuilderError { } + /// /// Exception while building solution part. /// - public class SolutionBuilderException : Exception + public class SolutionBuilderException : Exception + where T : ASolutionBuilderError { - private readonly ProcessResult? processResult; + public ProcessResult? ProcessResult { get; } public SolutionBuilderException() { @@ -29,7 +39,7 @@ public SolutionBuilderException(string message) public SolutionBuilderException(ProcessResult processResult) : this(processResult.GetLogs()) { - this.processResult = processResult; + ProcessResult = processResult; } public SolutionBuilderException(string message, Exception innerException) diff --git a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/IDotnetToolsConfiguration.cs b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/IDotnetToolsConfiguration.cs new file mode 100644 index 0000000..106b7e4 --- /dev/null +++ b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/IDotnetToolsConfiguration.cs @@ -0,0 +1,20 @@ +// ---------------------------------------------------------------------- +// +// Copyright © 2021 Xavier Solau. +// Licensed under the MIT license. +// See LICENSE file in the project root for full license information. +// +// ---------------------------------------------------------------------- + +namespace SoloX.CodeQuality.Test.Helpers.Solution +{ + public interface IDotnetToolsConfiguration + { + /// + /// Use and install the given Dotnet Tool locally to the solution. + /// + /// Dotnet Tool name to install. + /// Self. + IDotnetToolsConfiguration UseTool(string dotnetToolName); + } +} diff --git a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/ISolution.cs b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/ISolution.cs index 976332b..a33fe17 100644 --- a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/ISolution.cs +++ b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/ISolution.cs @@ -17,18 +17,30 @@ public interface ISolution /// Build solution. /// /// Project to build or null to build all solution. - void Build(string? project = null); + /// Process result. + ProcessResult Build(string? project = null); /// /// Test solution. /// /// Project to run. - void Run(string? project = null); + /// Process result. + ProcessResult Run(string? project = null); /// /// Test solution. /// /// Project to test or null to run all solution tests. - void Test(string? project = null); + /// Process result. + ProcessResult Test(string? project = null); + + /// + /// Run a Dotnet tool. + /// + /// Tool command to run. + /// Tool command arguments to run. + /// Project where to run the tool or null to run from solution folder. + /// Process result. + ProcessResult RunTool(string toolName, string? toolArgs = null, string? project = null); } } diff --git a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/DotnetToolsConfiguration.cs b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/DotnetToolsConfiguration.cs new file mode 100644 index 0000000..de4da51 --- /dev/null +++ b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/DotnetToolsConfiguration.cs @@ -0,0 +1,45 @@ +// ---------------------------------------------------------------------- +// +// Copyright © 2021 Xavier Solau. +// Licensed under the MIT license. +// See LICENSE file in the project root for full license information. +// +// ---------------------------------------------------------------------- + +using System.Collections.Generic; +using SoloX.CodeQuality.Test.Helpers.Solution.Exceptions; + +namespace SoloX.CodeQuality.Test.Helpers.Solution.Impl +{ + internal class DotnetToolsConfiguration : IDotnetToolsConfiguration + { + private readonly SolutionBuilder solutionBuilder; + private readonly List dotnetTools = new List(); + + public DotnetToolsConfiguration(SolutionBuilder solutionBuilder) + { + this.solutionBuilder = solutionBuilder; + } + + public IDotnetToolsConfiguration UseTool(string dotnetToolName) + { + this.dotnetTools.Add(dotnetToolName); + + return this; + } + + public void Build() + { + SolutionBuilder.DotnetCall((out ProcessResult processResult) => + DotnetHelper.NewToolManifest(this.solutionBuilder.SolutionPath, out processResult, this.solutionBuilder.SetupVariables) + ); + + foreach (var dotnetTool in this.dotnetTools) + { + SolutionBuilder.DotnetCall((out ProcessResult processResult) => + DotnetHelper.ToolInstall(this.solutionBuilder.SolutionPath, dotnetTool, out processResult, this.solutionBuilder.SetupVariables) + ); + } + } + } +} diff --git a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/NugetConfigWriter.cs b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/NugetConfigWriter.cs index 4448511..3a45229 100644 --- a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/NugetConfigWriter.cs +++ b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/NugetConfigWriter.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using SoloX.CodeQuality.Test.Helpers.Solution.Exceptions; namespace SoloX.CodeQuality.Test.Helpers.Solution.Impl { @@ -77,10 +78,17 @@ public void Build() "", ]; - File.WriteAllLines(configFilePath, - begin - .Concat(this.config) - .Concat(end)); + try + { + File.WriteAllLines(configFilePath, + begin + .Concat(this.config) + .Concat(end)); + } + catch (Exception e) + { + throw new SolutionBuilderException("Could not write Nuget config file.", e); + } } } } diff --git a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/ProjectConfiguration.cs b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/ProjectConfiguration.cs index e07a420..3a24018 100644 --- a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/ProjectConfiguration.cs +++ b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/Impl/ProjectConfiguration.cs @@ -57,7 +57,7 @@ public ProjectConfiguration( public void Build() { - DotnetCall((out ProcessResult processResult) => + SolutionBuilder.DotnetCall((out ProcessResult processResult) => DotnetHelper.New(this.solutionBuilder.SolutionPath, Template, ProjectName, out processResult) ); @@ -116,7 +116,7 @@ public IProjectFiles Remove(string target) public IProjectConfiguration UsePackageReference(string packageName) { - DotnetCall((out ProcessResult processResult) => + SolutionBuilder.DotnetCall((out ProcessResult processResult) => DotnetHelper.AddPackage(this.solutionBuilder.SolutionPath, ProjectFilePath, packageName, out processResult) ); @@ -150,16 +150,5 @@ private void CopyResourceFile(string filePath, string targetPath, IEnumerable<(s File.WriteAllText(Path.Combine(this.solutionBuilder.SolutionPath, this.ProjectPath, targetPath), txt); } - - - private delegate bool DotnetCallHandler(out ProcessResult processResult); - - private static void DotnetCall(DotnetCallHandler handler) - { - if (!handler(out var processResult)) - { - throw new ProjectBuilderException(processResult); - } - } } } diff --git a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/SolutionBuilder.cs b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/SolutionBuilder.cs index 2c12d89..01d1e2d 100644 --- a/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/SolutionBuilder.cs +++ b/src/libs/SoloX.CodeQuality.Test.Helpers/Solution/SolutionBuilder.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; using SoloX.CodeQuality.Test.Helpers.Solution.Exceptions; using SoloX.CodeQuality.Test.Helpers.Solution.Impl; @@ -24,7 +25,7 @@ namespace SoloX.CodeQuality.Test.Helpers.Solution public class SolutionBuilder { private const string DefaultPackageFolder = "Packages"; - private static readonly Action DefaultNugetConfigConfiguration = + private static readonly Action DefaultNugetConfigConfigurationHandler = configuration => configuration.UsePackageSources(s => { s.Clear(); @@ -48,7 +49,9 @@ public class SolutionBuilder private bool withNugetConfig; private string globalPackagesFolder = DefaultPackageFolder; - private Action nugetConfigConfiguration = DefaultNugetConfigConfiguration; + private Action nugetConfigConfigurationHandler = DefaultNugetConfigConfigurationHandler; + + private Action? dotnetToolsConfigurationHandler; private readonly Dictionary projectConfigurations = new Dictionary(); @@ -72,18 +75,19 @@ public SolutionBuilder(string root, string solutionName) /// Relative to the Solution builder Root folder. /// nuget.config file configuration. /// Self. + /// if method already called. public SolutionBuilder WithNugetConfig( string globalPackagesFolder = DefaultPackageFolder, Action? configuration = null) { if (this.withNugetConfig) { - throw new SolutionBuilderException("WithNugetConfig builder method already called."); + throw new SolutionBuilderException("WithNugetConfig builder method already called."); } this.withNugetConfig = true; this.globalPackagesFolder = globalPackagesFolder; - this.nugetConfigConfiguration = configuration ?? DefaultNugetConfigConfiguration; + this.nugetConfigConfigurationHandler = configuration ?? DefaultNugetConfigConfigurationHandler; return this; } @@ -104,6 +108,24 @@ public SolutionBuilder WithProject(string projectName, string template, Action + /// Generate the solution with a tool manifest file. + /// + /// Dotnet tools configuration. + /// Self. + /// if method already called. + public SolutionBuilder WithDotnetTools(Action configuration) + { + if (this.dotnetToolsConfigurationHandler != null) + { + throw new SolutionBuilderException("WithDotnetTools builder method already called."); + } + + this.dotnetToolsConfigurationHandler = configuration; + + return this; + } + /// /// Build the solution and all its projects. /// @@ -118,19 +140,28 @@ public ISolution Build() Directory.CreateDirectory(Path.Combine(this.Root, this.globalPackagesFolder)); } - DotnetCall((out ProcessResult processResult) => - DotnetHelper.NewSln(this.Root, this.SolutionName, out processResult) + DotnetCall((out ProcessResult processResult) => + DotnetHelper.NewSln(this.Root, this.SolutionName, out processResult, SetupVariables) ); if (this.withNugetConfig) { var nugetConfigWriter = new NugetConfigWriter(this, this.globalPackagesFolder); - this.nugetConfigConfiguration(nugetConfigWriter); + this.nugetConfigConfigurationHandler(nugetConfigWriter); nugetConfigWriter.Build(); } + if (this.dotnetToolsConfigurationHandler != null) + { + var dotnetToolsConfiguration = new DotnetToolsConfiguration(this); + + this.dotnetToolsConfigurationHandler(dotnetToolsConfiguration); + + dotnetToolsConfiguration.Build(); + } + var projectPathMap = new Dictionary(); foreach (var projectConfigurationItem in this.projectConfigurations) @@ -145,12 +176,12 @@ public ISolution Build() projectConfiguration.Build(); - DotnetCall((out ProcessResult processResult) => - DotnetHelper.SlnAdd(this.SolutionPath, projectFilePath, out processResult) + DotnetCall((out ProcessResult processResult) => + DotnetHelper.SlnAdd(this.SolutionPath, projectFilePath, out processResult, SetupVariables) ); } - return new Solution(this.SolutionPath, projectPathMap); + return new Solution(this, projectPathMap); } catch (Exception) { @@ -160,57 +191,76 @@ public ISolution Build() } } - private delegate bool DotnetCallHandler(out ProcessResult processResult); + internal delegate bool DotnetCallHandler(out ProcessResult processResult); - private static void DotnetCall(DotnetCallHandler handler) + internal static ProcessResult DotnetCall(DotnetCallHandler handler) + where T : ASolutionBuilderError { if (!handler(out var processResult)) { - throw new SolutionBuilderException(processResult); + throw new SolutionBuilderException(processResult); } + + return processResult; + } + + internal void SetupVariables(StringDictionary environmentVariables) + { + environmentVariables.Add("DOTNET_CLI_HOME", Path.GetFullPath(Root)); } private class Solution : ISolution { - private readonly string solutionPath; + private readonly SolutionBuilder solutionBuilder; private readonly IReadOnlyDictionary projectPathMap; - public Solution(string solutionPath, IReadOnlyDictionary projectPathMap) + public Solution(SolutionBuilder solutionBuilder, IReadOnlyDictionary projectPathMap) { - this.solutionPath = solutionPath; + this.solutionBuilder = solutionBuilder; this.projectPathMap = projectPathMap; } - public void Build(string? project = null) + public ProcessResult Build(string? project = null) { - var path = string.IsNullOrEmpty(project) - ? this.solutionPath - : GetProjectPath(project); + return string.IsNullOrEmpty(project) + ? DotnetCall((out ProcessResult processResult) => + DotnetHelper.Build(this.solutionBuilder.SolutionPath, out processResult, this.solutionBuilder.SetupVariables) + ) + : DotnetCall((out ProcessResult processResult) => + DotnetHelper.Build(GetProjectPath(project), out processResult, this.solutionBuilder.SetupVariables) + ); + } - DotnetCall((out ProcessResult processResult) => - DotnetHelper.Build(path, out processResult) - ); + public ProcessResult Run(string? project = null) + { + return string.IsNullOrEmpty(project) + ? DotnetCall((out ProcessResult processResult) => + DotnetHelper.Run(this.solutionBuilder.SolutionPath, out processResult, this.solutionBuilder.SetupVariables) + ) + : DotnetCall((out ProcessResult processResult) => + DotnetHelper.Run(GetProjectPath(project), out processResult, this.solutionBuilder.SetupVariables) + ); } - public void Run(string? project = null) + public ProcessResult RunTool(string toolName, string? toolArgs, string? project = null) { var path = string.IsNullOrEmpty(project) - ? this.solutionPath + ? this.solutionBuilder.SolutionPath : GetProjectPath(project); - DotnetCall((out ProcessResult processResult) => - DotnetHelper.Run(path, out processResult) + return DotnetCall((out ProcessResult processResult) => + DotnetHelper.Dotnet(path, $"{toolName} {toolArgs}", out processResult, this.solutionBuilder.SetupVariables) ); } - public void Test(string? project = null) + public ProcessResult Test(string? project = null) { var path = string.IsNullOrEmpty(project) - ? this.solutionPath + ? this.solutionBuilder.SolutionPath : GetProjectPath(project); - DotnetCall((out ProcessResult processResult) => - DotnetHelper.Test(path, out processResult) + return DotnetCall((out ProcessResult processResult) => + DotnetHelper.Test(path, out processResult, this.solutionBuilder.SetupVariables) ); } @@ -218,10 +268,10 @@ private string GetProjectPath(string project) { if (this.projectPathMap.TryGetValue(project, out var projectPath)) { - return Path.Combine(this.solutionPath, projectPath); + return Path.Combine(this.solutionBuilder.SolutionPath, projectPath); } - throw new SolutionBuilderException($"Could not find project {project}"); + throw new SolutionBuilderException($"Could not find project {project}"); } } } diff --git a/src/libs/SoloX.CodeQuality.Test/build/SoloX.CodeQuality.Test.targets b/src/libs/SoloX.CodeQuality.Test/build/SoloX.CodeQuality.Test.targets index b22e472..8c12575 100644 --- a/src/libs/SoloX.CodeQuality.Test/build/SoloX.CodeQuality.Test.targets +++ b/src/libs/SoloX.CodeQuality.Test/build/SoloX.CodeQuality.Test.targets @@ -108,7 +108,7 @@ $(MSBuildProjectDirectory)/.editorconfig - $(MSBuildProjectDirectory)/obj/.editorconfig + $(MSBuildProjectDirectory)/obj/.editorconfig-$(TargetFramework) $(MSBuildThisFileDirectory)../resources/style.cs.compiler.ca.editorconfig $(MSBuildThisFileDirectory)../resources/style.cs.compiler.cs.editorconfig $(MSBuildThisFileDirectory)../resources/style.cs.ide1.editorconfig diff --git a/src/tests/SoloX.CodeQuality.Playwright.E2ETest/Package/PackageNugetTest.cs b/src/tests/SoloX.CodeQuality.Playwright.E2ETest/Package/PackageNugetTest.cs index 03ba8e2..62e2b49 100644 --- a/src/tests/SoloX.CodeQuality.Playwright.E2ETest/Package/PackageNugetTest.cs +++ b/src/tests/SoloX.CodeQuality.Playwright.E2ETest/Package/PackageNugetTest.cs @@ -14,7 +14,6 @@ namespace SoloX.CodeQuality.Playwright.E2ETest.Package { public class PackageNugetTest { - [Fact] public void IsShouldDeployNugetPackageAndRunTestWithEmbeddedWebHost() { @@ -63,7 +62,6 @@ public void IsShouldDeployNugetPackageAndRunTestWithEmbeddedWebHost() try { - var actBuild = () => solution.Build(); actBuild.Should().NotThrow(); diff --git a/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/Http/HttpClientMockBuilderTest.cs b/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/Http/HttpClientMockBuilderTest.cs index d864ea6..d53fe4c 100644 --- a/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/Http/HttpClientMockBuilderTest.cs +++ b/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/Http/HttpClientMockBuilderTest.cs @@ -9,11 +9,8 @@ using FluentAssertions; using SoloX.CodeQuality.Test.Helpers.Http; using SoloX.CodeQuality.Test.Helpers.UTest.Data; -using System; using System.Net; -using System.Net.Http; using System.Net.Http.Json; -using System.Threading.Tasks; using Xunit; namespace SoloX.CodeQuality.Test.Helpers.UTest.Http diff --git a/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/ProcessHelperTest.cs b/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/ProcessHelperTest.cs index 710449d..ddb8f87 100644 --- a/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/ProcessHelperTest.cs +++ b/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/ProcessHelperTest.cs @@ -6,7 +6,6 @@ // // ---------------------------------------------------------------------- -using System.Linq; using FluentAssertions; using Xunit; diff --git a/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/SoloX.CodeQuality.Test.Helpers.UTest.csproj b/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/SoloX.CodeQuality.Test.Helpers.UTest.csproj index 47cc766..c60027e 100644 --- a/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/SoloX.CodeQuality.Test.Helpers.UTest.csproj +++ b/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/SoloX.CodeQuality.Test.Helpers.UTest.csproj @@ -8,8 +8,11 @@ net9.0 + enable + enable false + true @@ -28,6 +31,7 @@ + diff --git a/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/Solution/SolutionBuilderTest.cs b/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/Solution/SolutionBuilderTest.cs new file mode 100644 index 0000000..238f3a9 --- /dev/null +++ b/src/tests/SoloX.CodeQuality.Test.Helpers.UTest/Solution/SolutionBuilderTest.cs @@ -0,0 +1,119 @@ +// ---------------------------------------------------------------------- +// +// Copyright © 2021 Xavier Solau. +// Licensed under the MIT license. +// See LICENSE file in the project root for full license information. +// +// ---------------------------------------------------------------------- + +using FluentAssertions; +using SoloX.CodeQuality.Test.Helpers.Solution; +using Xunit; + +namespace SoloX.CodeQuality.Test.Helpers.UTest.Solution +{ + public class SolutionBuilderTest + { + [Fact] + public void IsShouldBuildASolutionWithATestProject() + { + var root = new RandomGenerator().RandomString(4); + + // Let's create a solution in the random root folder. + var solution = new SolutionBuilder(root, "TestSolution") + // Set up the nuget.config to use a dedicated nuget cache and to specify where to get the nuget + // packages we want to test (generated in the same solution). + .WithNugetConfig(@"PkgCache", configuration => + { + // We want to use the package generated by the projects SoloX.CodeQuality.WebHost and SoloX.CodeQuality.Playwright. + configuration + .UsePackageSources(src => + { + src.Clear().AddNugetOrg(); + }); + }) + // Set up a xunit project to use the nugets. + .WithProject("TestProject", "xunit", configuration => + { + // Nothing more to do for now. + // We will use the default UnitTest1.cs file. + }) + // Finally create the solution. + .Build(); + + try + { + var actBuild = () => solution.Build(); + + actBuild.Should().NotThrow(); + + var actTest = () => solution.Test(); + + actTest.Should().NotThrow(); + } + finally + { + Directory.Delete(root, true); + } + } + + [Fact] + public void IsShouldBuildASolutionUsingADotnetTool() + { + var configurationName = ProbConfiguration(); + + var root = new RandomGenerator().RandomString(4); + + // Let's create a solution in the random root folder. + var solution = new SolutionBuilder(root, "TestSolution") + // Set up the nuget.config to use a dedicated nuget cache and to specify where to get the nuget + // packages we want to test (generated in the same solution). + .WithNugetConfig(@"PkgCache", configuration => + { + // We want to use the package generated by the projects SoloX.CodeQuality.WebHost and SoloX.CodeQuality.Playwright. + configuration + .UsePackageSources(src => + { + src.Clear() + .Add(@$"../../../../../SoloX.CodeQuality.TestTool/bin/{configurationName}") + .AddNugetOrg(); + }); + }) + .WithDotnetTools(configuration => + { + configuration + .UseTool("SoloX.CodeQuality.TestTool"); + }) + // Finally create the solution. + .Build(); + + try + { + var actBuild = () => solution.Build(); + + actBuild.Should().NotThrow(); + + var actTest = () => solution.RunTool("testtool", $"a1 a2 --debug:false"); + + var logs = actTest.Should().NotThrow().Subject.LogMessages; + + logs.Should().NotBeEmpty(); + + logs![0].Message.Should().Be("Hello, World!"); + logs![1].Message.Should().Be("given arg 0: a1"); + logs![2].Message.Should().Be("given arg 1: a2"); + } + finally + { + Directory.Delete(root, true); + } + } + + private static string ProbConfiguration() + { + var location = Path.GetDirectoryName(typeof(SolutionBuilderTest).Assembly.Location); + + return Path.GetFileName(Path.GetDirectoryName(location)!); + } + } +} diff --git a/src/tests/SoloX.CodeQuality.TestTool/Program.cs b/src/tests/SoloX.CodeQuality.TestTool/Program.cs new file mode 100644 index 0000000..68f8f9b --- /dev/null +++ b/src/tests/SoloX.CodeQuality.TestTool/Program.cs @@ -0,0 +1,28 @@ +// See https://aka.ms/new-console-template for more information + +#if DEBUG +using System.Diagnostics; + +if (!Debugger.IsAttached && args != null && args.Contains("--debug:true")) +{ + Debugger.Launch(); +} + +#endif + +Console.WriteLine("Hello, World!"); + +if (args != null) +{ + for (var i = 0; i < args.Length; i++) + { + var arg = args[i]; + + Console.WriteLine($"given arg {i}: {arg}"); + } +} +else +{ + Console.WriteLine($"no given args"); +} + diff --git a/src/tests/SoloX.CodeQuality.TestTool/SoloX.CodeQuality.TestTool.csproj b/src/tests/SoloX.CodeQuality.TestTool/SoloX.CodeQuality.TestTool.csproj new file mode 100644 index 0000000..bdfed4b --- /dev/null +++ b/src/tests/SoloX.CodeQuality.TestTool/SoloX.CodeQuality.TestTool.csproj @@ -0,0 +1,18 @@ + + + + + + Exe + net9.0 + enable + enable + + true + testtool + + true + + + +