From 4eed410dd15f5c18ee6e71c96c18396c501c7917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1sp=C3=A1r=20Nagy?= Date: Wed, 6 Nov 2024 09:50:09 +0100 Subject: [PATCH] Improve System Test performance with stubbing dotnet new (#294) * first attempt to improve "dotnet new classlib" * improve "dotnet new sln" * stub "dotnet sln add" * try fixing linux build issue * Fix linux build * Ensure dotnet command is executed with the corresponding sdk version * code cleanup * fix Reqnroll.TestProjectGenerator.Tests * Add --no-restore for new classlib --------- Co-authored-by: obligaron --- .../Dotnet/BaseCommandBuilder.cs | 2 +- .../Dotnet/CacheAndCopyCommandBuilder.cs | 87 +++++++++++++++++++ .../Dotnet/CommandBuilder.cs | 10 +-- .../Dotnet/CopyFolderCommandBuilder.cs | 64 ++++++++++++++ .../Dotnet/DotNet.cs | 4 +- ...CommandBuilder.NewProjectCommandBuilder.cs | 10 +-- ...ommandBuilder.NewSolutionCommandBuilder.cs | 4 +- ...andBuilder.StubNewProjectCommandBuilder.cs | 14 +++ ...ndBuilder.StubNewSolutionCommandBuilder.cs | 14 +++ .../Dotnet/NewCommandBuilder.cs | 12 ++- ...uilder.AddProjectSolutionCommandBuilder.cs | 4 +- ...er.StubAddProjectSolutionCommandBuilder.cs | 66 ++++++++++++++ .../Dotnet/SolutionCommandBuilder.cs | 2 +- .../FilesystemWriter/IProjectWriter.cs | 2 +- .../NewFormatProjectWriter.cs | 8 +- .../OldFormatProjectWriter.cs | 2 +- .../FilesystemWriter/SolutionWriter.cs | 14 +-- 17 files changed, 285 insertions(+), 34 deletions(-) create mode 100644 Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CacheAndCopyCommandBuilder.cs create mode 100644 Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CopyFolderCommandBuilder.cs create mode 100644 Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.StubNewProjectCommandBuilder.cs create mode 100644 Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.StubNewSolutionCommandBuilder.cs create mode 100644 Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.StubAddProjectSolutionCommandBuilder.cs diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/BaseCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/BaseCommandBuilder.cs index 7514e3072..54ff3d952 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/BaseCommandBuilder.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/BaseCommandBuilder.cs @@ -10,7 +10,7 @@ protected BaseCommandBuilder(IOutputWriter outputWriter) _outputWriter = outputWriter; } - public CommandBuilder Build() + public virtual CommandBuilder Build() { return new CommandBuilder(_outputWriter, ExecutablePath, BuildArguments(), GetWorkingDirectory()); } diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CacheAndCopyCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CacheAndCopyCommandBuilder.cs new file mode 100644 index 000000000..a380b241f --- /dev/null +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CacheAndCopyCommandBuilder.cs @@ -0,0 +1,87 @@ +using Reqnroll.TestProjectGenerator.FilesystemWriter; +using System; +using System.Collections.Concurrent; +using System.IO; + +namespace Reqnroll.TestProjectGenerator.Dotnet; + +public class CacheAndCopyCommandBuilder : CommandBuilder +{ + private const string TemplateName = "TName"; + private readonly NetCoreSdkInfo _sdk; + private readonly CommandBuilder _baseCommandBuilder; + private readonly string _targetPath; + private readonly string _nameToReplace; + private static readonly ConcurrentDictionary LockObjects = new(); + + public CacheAndCopyCommandBuilder(IOutputWriter outputWriter, NetCoreSdkInfo sdk, CommandBuilder baseCommandBuilder, string targetPath, string nameToReplace = null) + : base(outputWriter, baseCommandBuilder.ExecutablePath, baseCommandBuilder.ArgumentsFormat, baseCommandBuilder.WorkingDirectory) + { + _sdk = sdk; + _baseCommandBuilder = baseCommandBuilder; + _targetPath = targetPath; + _nameToReplace = nameToReplace; + } + + private string CalculateCacheTargetPath(string suffix = "") + { + var targetPathInfo = new DirectoryInfo(_targetPath); + var directoryName = targetPathInfo.Name; + string argsCleaned = ArgumentsFormat.Replace(_targetPath, "").Replace(" ", "").Replace("\"", "").Replace("/", "") + directoryName; + if (_nameToReplace != null) + { + argsCleaned = argsCleaned.Replace(_nameToReplace, TemplateName); + directoryName = directoryName.Replace(_nameToReplace, TemplateName); + } + + var sdkSpecifier = _sdk == null ? "" : $"_{_sdk.Version}"; + return Path.Combine(Path.GetTempPath(), "RRC", $"RRC{sdkSpecifier}_{argsCleaned}{suffix}", directoryName); + } + + public override CommandResult Execute(Func exceptionFunction) + { + var cachePath = CalculateCacheTargetPath(); + + CommandResult originalResult = null; + if (!Directory.Exists(cachePath)) + { + LockObjects.TryAdd(cachePath, new object()); + + lock (LockObjects[cachePath]) + { + if (!Directory.Exists(cachePath)) + { + var tempPath = CalculateCacheTargetPath($"-tmp{Guid.NewGuid():N}"); + var arguments = ArgumentsFormat.Replace(_targetPath, tempPath); + if (_nameToReplace != null) arguments = arguments.Replace(_nameToReplace, TemplateName); + var commandBuilder = new CommandBuilder(_outputWriter, ExecutablePath, arguments, WorkingDirectory); + + originalResult = commandBuilder.Execute(exceptionFunction); + try + { + if (!Directory.Exists(cachePath)) + Directory.Move(Path.Combine(tempPath, ".."), Path.Combine(cachePath, "..")); + } + catch (IOException ex) + { + _outputWriter.WriteLine($"Unable to move TMP to CACHE: {ex.Message}"); + } + try + { + if (Directory.Exists(tempPath)) + Directory.Delete(Path.Combine(tempPath, ".."), true); + } + catch (IOException ex) + { + _outputWriter.WriteLine($"Unable to delete TMP: {ex.Message}"); + } + } + } + } + + var copyFolderCommandBuilder = new CopyFolderCommandBuilder(_outputWriter, cachePath, _targetPath, TemplateName, _nameToReplace); + var copyFolderResult = copyFolderCommandBuilder.Execute(exceptionFunction); + return originalResult == null ? copyFolderResult : + new CommandResult(originalResult.ExitCode, originalResult.ConsoleOutput + Environment.NewLine + copyFolderResult.ConsoleOutput); + } +} diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CommandBuilder.cs index 6ee240a48..c91f7a188 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CommandBuilder.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CommandBuilder.cs @@ -6,19 +6,19 @@ namespace Reqnroll.TestProjectGenerator.Dotnet { public class CommandBuilder { - private readonly IOutputWriter _outputWriter; - private readonly string _workingDirectory; + protected readonly IOutputWriter _outputWriter; public CommandBuilder(IOutputWriter outputWriter, string executablePath, string argumentsFormat, string workingDirectory) { _outputWriter = outputWriter; - _workingDirectory = workingDirectory; + WorkingDirectory = workingDirectory; ExecutablePath = executablePath; ArgumentsFormat = argumentsFormat; } public string ArgumentsFormat { get; } public string ExecutablePath { get; } + public string WorkingDirectory { get; } public CommandResult ExecuteWithRetry(int times, TimeSpan interval, Func exceptionFunction) { @@ -45,11 +45,11 @@ public CommandResult Execute() return Execute(innerException => new Exception($"Error while executing {ExecutablePath} {ArgumentsFormat}", innerException)); } - public CommandResult Execute(Func exceptionFunction) + public virtual CommandResult Execute(Func exceptionFunction) { var solutionCreateProcessHelper = new ProcessHelper(); - var processResult = solutionCreateProcessHelper.RunProcess(_outputWriter, _workingDirectory, ExecutablePath, ArgumentsFormat); + var processResult = solutionCreateProcessHelper.RunProcess(_outputWriter, WorkingDirectory, ExecutablePath, ArgumentsFormat); if (processResult.ExitCode != 0) { var innerException = new Exception(processResult.CombinedOutput); diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CopyFolderCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CopyFolderCommandBuilder.cs new file mode 100644 index 000000000..8c8d72de0 --- /dev/null +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/CopyFolderCommandBuilder.cs @@ -0,0 +1,64 @@ +using System; +using System.IO; + +namespace Reqnroll.TestProjectGenerator.Dotnet; +public class CopyFolderCommandBuilder : CommandBuilder +{ + private readonly string _replaceFrom; + private readonly string _replaceTo; + + public CopyFolderCommandBuilder(IOutputWriter outputWriter, string sourceFolder, string targetFolder, string replaceFrom = null, string replaceTo = null) + : base(outputWriter, "[copy folder]", sourceFolder, targetFolder) + { + _replaceFrom = replaceFrom; + _replaceTo = replaceTo; + } + + private string ReplaceName(string value) + { + if (_replaceFrom == null || _replaceTo == null) return value; + return value.Replace(_replaceFrom, _replaceTo); + } + + private void CopyDirectoryRecursively(DirectoryInfo source, DirectoryInfo target) + { + Directory.CreateDirectory(target.FullName); + + // Copy each file into the new directory. + foreach (FileInfo fi in source.GetFiles()) + { + string fiName = ReplaceName(fi.Name); + _outputWriter.WriteLine(@"Copying to {0}\{1}", target.FullName, fiName); + fi.CopyTo(Path.Combine(target.FullName, fiName), true); + } + + // Copy each subdirectory using recursion. + foreach (DirectoryInfo diSourceSubDir in source.GetDirectories()) + { + DirectoryInfo nextTargetSubDir = + target.CreateSubdirectory(diSourceSubDir.Name); + CopyDirectoryRecursively(diSourceSubDir, nextTargetSubDir); + } + } + + public override CommandResult Execute(Func exceptionFunction) + { + var sourceFolder = ArgumentsFormat; + var targetFolder = WorkingDirectory; + + try + { + _outputWriter.WriteLine($"Copying '{sourceFolder}' to '{targetFolder}'..."); + + CopyDirectoryRecursively(new DirectoryInfo(sourceFolder), new DirectoryInfo(targetFolder)); + + _outputWriter.WriteLine("Copying done."); + + return new CommandResult(0, $"Copied '{sourceFolder}' to '{targetFolder}'."); + } + catch (Exception ex) + { + throw exceptionFunction(ex); + } + } +} diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/DotNet.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/DotNet.cs index 92cbe2a61..24363ce07 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/DotNet.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/DotNet.cs @@ -1,8 +1,10 @@ +using Reqnroll.TestProjectGenerator.FilesystemWriter; + namespace Reqnroll.TestProjectGenerator.Dotnet { public class DotNet { - public static NewCommandBuilder New(IOutputWriter outputWriter) => NewCommandBuilder.Create(outputWriter); + public static NewCommandBuilder New(IOutputWriter outputWriter, NetCoreSdkInfo sdk) => NewCommandBuilder.Create(outputWriter, sdk); public static BuildCommandBuilder Build(IOutputWriter outputWriter) => BuildCommandBuilder.Create(outputWriter); public static SolutionCommandBuilder Sln(IOutputWriter outputWriter) => SolutionCommandBuilder.Create(outputWriter); public static VersionCommandBuilder Version(IOutputWriter outputWriter) => VersionCommandBuilder.Create(outputWriter); diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.NewProjectCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.NewProjectCommandBuilder.cs index 4a4d20d60..ada90d262 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.NewProjectCommandBuilder.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.NewProjectCommandBuilder.cs @@ -6,10 +6,10 @@ public partial class NewCommandBuilder { public class NewProjectCommandBuilder : BaseCommandBuilder { - private string _templateName = "classlib"; - private string _name = "ClassLib"; - private string _folder; - private ProgrammingLanguage _language = ProgrammingLanguage.CSharp; + protected string _templateName = "classlib"; + protected string _name = "ClassLib"; + protected string _folder; + protected ProgrammingLanguage _language = ProgrammingLanguage.CSharp; public NewProjectCommandBuilder(IOutputWriter outputWriter) : base(outputWriter) @@ -47,7 +47,7 @@ protected override string GetWorkingDirectory() protected override string BuildArguments() { - var arguments = AddArgument($"new {_templateName} --no-update-check", "-o", "\"" + _folder + "\""); + var arguments = AddArgument($"new {_templateName} --no-update-check --no-restore", "-o", "\"" + _folder + "\""); arguments = AddArgument( arguments, "-lang", diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.NewSolutionCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.NewSolutionCommandBuilder.cs index b6d61bbeb..cb9adf381 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.NewSolutionCommandBuilder.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.NewSolutionCommandBuilder.cs @@ -4,8 +4,8 @@ public partial class NewCommandBuilder { public class NewSolutionCommandBuilder : BaseCommandBuilder { - private string _name; - private string _rootPath; + protected string _name; + protected string _rootPath; public NewSolutionCommandBuilder InFolder(string rootPath) { diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.StubNewProjectCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.StubNewProjectCommandBuilder.cs new file mode 100644 index 000000000..d2c0d1f56 --- /dev/null +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.StubNewProjectCommandBuilder.cs @@ -0,0 +1,14 @@ +using Reqnroll.TestProjectGenerator.FilesystemWriter; + +namespace Reqnroll.TestProjectGenerator.Dotnet; + +public partial class NewCommandBuilder +{ + public class StubNewProjectCommandBuilder(IOutputWriter outputWriter, NetCoreSdkInfo _sdk) : NewProjectCommandBuilder(outputWriter) + { + public override CommandBuilder Build() + { + return new CacheAndCopyCommandBuilder(_outputWriter, _sdk, base.Build(), _folder); + } + } +} \ No newline at end of file diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.StubNewSolutionCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.StubNewSolutionCommandBuilder.cs new file mode 100644 index 000000000..7f7e53a75 --- /dev/null +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.StubNewSolutionCommandBuilder.cs @@ -0,0 +1,14 @@ +using Reqnroll.TestProjectGenerator.FilesystemWriter; + +namespace Reqnroll.TestProjectGenerator.Dotnet; + +public partial class NewCommandBuilder +{ + public class StubNewSolutionCommandBuilder(IOutputWriter outputWriter, NetCoreSdkInfo _sdk) : NewSolutionCommandBuilder(outputWriter) + { + public override CommandBuilder Build() + { + return new CacheAndCopyCommandBuilder(_outputWriter, _sdk, base.Build(), _rootPath, _name); + } + } +} \ No newline at end of file diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.cs index 107a63ec4..35ca5470c 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/NewCommandBuilder.cs @@ -1,18 +1,22 @@ +using Reqnroll.TestProjectGenerator.FilesystemWriter; + namespace Reqnroll.TestProjectGenerator.Dotnet { public partial class NewCommandBuilder { private readonly IOutputWriter _outputWriter; + private readonly NetCoreSdkInfo _sdk; - public NewCommandBuilder(IOutputWriter outputWriter) + public NewCommandBuilder(IOutputWriter outputWriter, NetCoreSdkInfo sdk) { _outputWriter = outputWriter; + _sdk = sdk; } - internal static NewCommandBuilder Create(IOutputWriter outputWriter) => new NewCommandBuilder(outputWriter); + internal static NewCommandBuilder Create(IOutputWriter outputWriter, NetCoreSdkInfo sdk) => new NewCommandBuilder(outputWriter, sdk); - public NewSolutionCommandBuilder Solution() => new NewSolutionCommandBuilder(_outputWriter); + public NewSolutionCommandBuilder Solution() => new StubNewSolutionCommandBuilder(_outputWriter, _sdk); - public NewProjectCommandBuilder Project() => new NewProjectCommandBuilder(_outputWriter); + public NewProjectCommandBuilder Project() => new StubNewProjectCommandBuilder(_outputWriter, _sdk); } } diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.AddProjectSolutionCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.AddProjectSolutionCommandBuilder.cs index 10b1c5677..960b221dc 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.AddProjectSolutionCommandBuilder.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.AddProjectSolutionCommandBuilder.cs @@ -7,8 +7,8 @@ public partial class SolutionCommandBuilder { public class AddProjectSolutionCommandBuilder : BaseCommandBuilder { - private string _solutionPath; - private string _projectPath; + protected string _solutionPath; + protected string _projectPath; public AddProjectSolutionCommandBuilder ToSolution(string solutionPath) diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.StubAddProjectSolutionCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.StubAddProjectSolutionCommandBuilder.cs new file mode 100644 index 000000000..e726c656b --- /dev/null +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.StubAddProjectSolutionCommandBuilder.cs @@ -0,0 +1,66 @@ +using System; +using System.IO; +using System.Text.RegularExpressions; + +namespace Reqnroll.TestProjectGenerator.Dotnet; + +public partial class SolutionCommandBuilder +{ + public class StubAddProjectSolutionCommandBuilder(IOutputWriter outputWriter) : AddProjectSolutionCommandBuilder(outputWriter) + { + public override CommandBuilder Build() + { + return new AddProjectSolutionCommand(_outputWriter, _solutionPath, _projectPath, GetWorkingDirectory()); + } + + class AddProjectSolutionCommand(IOutputWriter outputWriter, string _solutionPath, string _projectPath, string workingDirectory) + : CommandBuilder(outputWriter, "[add project to sln]", $"{_projectPath} -> {_solutionPath}", workingDirectory) + { + public override CommandResult Execute(Func exceptionFunction) + { + try + { + var projectGuid = Guid.NewGuid().ToString("B").ToUpperInvariant(); + var projectTypeGuid = Path.GetExtension(_projectPath).ToLowerInvariant().Equals(".vbproj") ? + "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}" : + "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"; + var projectName = Path.GetFileNameWithoutExtension(_projectPath); + var projectRelativePath = _projectPath!.Substring(Path.GetDirectoryName(_solutionPath)!.Length + 1); + var slnContent = File.ReadAllText(_solutionPath); + var projectReference = + $$""" + Project("{{projectTypeGuid}}") = "{{projectName}}", "{{projectRelativePath}}", "{{projectGuid}}" + EndProject + """; + var projectConfPlatforms = + """ + GlobalSection(ProjectConfigurationPlatforms) = postSolution + EndGlobalSection + """; + var projectConfPlatformContent = + $$""" + {{projectGuid}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {{projectGuid}}.Debug|Any CPU.Build.0 = Debug|Any CPU + {{projectGuid}}.Release|Any CPU.ActiveCfg = Release|Any CPU + {{projectGuid}}.Release|Any CPU.Build.0 = Release|Any CPU + """; + + slnContent = Regex.Replace(slnContent, @"\r?\nGlobal\r?\n", match => Environment.NewLine + projectReference + match.Value); + if (!slnContent.Contains("GlobalSection(ProjectConfigurationPlatforms)")) + { + slnContent = Regex.Replace(slnContent, @"\r?\nEndGlobal", match => Environment.NewLine + projectConfPlatforms + match.Value); + } + + slnContent = Regex.Replace(slnContent, @"GlobalSection\(ProjectConfigurationPlatforms\) = postSolution\r?\n", match => match.Value + projectConfPlatformContent + Environment.NewLine); + File.WriteAllText(_solutionPath, slnContent); + _outputWriter.WriteLine($"Solution file updated: {ArgumentsFormat}"); + return new CommandResult(0, "Solution file updated."); + } + catch (Exception ex) + { + throw exceptionFunction(ex); + } + } + } + } +} diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.cs index 0d3b2462e..fb11a9a88 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/Dotnet/SolutionCommandBuilder.cs @@ -12,6 +12,6 @@ public SolutionCommandBuilder(IOutputWriter outputWriter) public static SolutionCommandBuilder Create(IOutputWriter outputWriter) => new SolutionCommandBuilder(outputWriter); - public AddProjectSolutionCommandBuilder AddProject() => new AddProjectSolutionCommandBuilder(_outputWriter); + public AddProjectSolutionCommandBuilder AddProject() => new StubAddProjectSolutionCommandBuilder(_outputWriter); } } diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/IProjectWriter.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/IProjectWriter.cs index 93e0caacb..faf5bd4ed 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/IProjectWriter.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/IProjectWriter.cs @@ -4,7 +4,7 @@ namespace Reqnroll.TestProjectGenerator.FilesystemWriter { public interface IProjectWriter { - string WriteProject(Project project, string path); + string WriteProject(NetCoreSdkInfo sdk, Project project, string path); void WriteReferences(Project project, string projectFilePath); } diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/NewFormatProjectWriter.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/NewFormatProjectWriter.cs index 873890f1a..12c0ab854 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/NewFormatProjectWriter.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/NewFormatProjectWriter.cs @@ -21,7 +21,7 @@ public NewFormatProjectWriter(IOutputWriter outputWriter, TargetFrameworkMoniker _targetFrameworkMonikerStringBuilder = targetFrameworkMonikerStringBuilder; } - public virtual string WriteProject(Project project, string projRootPath) + public virtual string WriteProject(NetCoreSdkInfo sdk, Project project, string projRootPath) { if (project is null) { @@ -29,7 +29,7 @@ public virtual string WriteProject(Project project, string projRootPath) } - CreateProjectFile(project, projRootPath); + CreateProjectFile(sdk, project, projRootPath); string projFileName = $"{project.Name}.{project.ProgrammingLanguage.ToProjectFileExtension()}"; @@ -244,7 +244,7 @@ private void WriteAssemblyReference(XmlWriter xw, Reference reference) xw.WriteEndElement(); } - private void CreateProjectFile(Project project, string projRootPath) + private void CreateProjectFile(NetCoreSdkInfo sdk, Project project, string projRootPath) { string template; @@ -265,7 +265,7 @@ private void CreateProjectFile(Project project, string projRootPath) - var newProjCommand = DotNet.New(_outputWriter) + var newProjCommand = DotNet.New(_outputWriter, sdk) .Project() .InFolder(projRootPath) .WithName(project.Name) diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/OldFormatProjectWriter.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/OldFormatProjectWriter.cs index bf783ffff..e423ec8dc 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/OldFormatProjectWriter.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/OldFormatProjectWriter.cs @@ -20,7 +20,7 @@ public OldFormatProjectWriter(IOutputWriter outputWriter, TargetFrameworkMoniker _targetFrameworkVersionStringBuilder = targetFrameworkVersionStringBuilder; } - public virtual string WriteProject(Project project, string path) + public virtual string WriteProject(NetCoreSdkInfo sdk, Project project, string path) { if (project is null) { diff --git a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/SolutionWriter.cs b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/SolutionWriter.cs index ad0932a43..59161d008 100644 --- a/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/SolutionWriter.cs +++ b/Tests/TestProjectGenerator/Reqnroll.TestProjectGenerator/FilesystemWriter/SolutionWriter.cs @@ -53,16 +53,16 @@ public string WriteToFileSystem(Solution solution, string outputPath) DisableUsingSdkFromEnvironmentVariable(); - var createSolutionCommand = DotNet.New(_outputWriter).Solution().InFolder(outputPath).WithName(solution.Name).Build(); + var createSolutionCommand = DotNet.New(_outputWriter, sdk).Solution().InFolder(outputPath).WithName(solution.Name).Build(); createSolutionCommand.ExecuteWithRetry(1, TimeSpan.FromSeconds(1), (innerException) => { - if (innerException is AggregateException aggregateException && aggregateException.InnerExceptions.Any(x => x.InnerException.Message.Contains("Install the [" + sdk.Version))) + if (sdk != null && innerException is AggregateException aggregateException && aggregateException.InnerExceptions.Any(x => x.InnerException?.Message.Contains("Install the [" + sdk.Version) ?? false)) return new DotNetSdkNotInstalledException($"Sdk Version \"{sdk.Version}\" is not installed", innerException); return new ProjectCreationNotPossibleException("Could not create solution.", innerException); }); string solutionFilePath = Path.Combine(outputPath, $"{solution.Name}.sln"); - WriteProjects(solution, outputPath, solutionFilePath); + WriteProjects(sdk, solution, outputPath, solutionFilePath); if (solution.NugetConfig != null) { @@ -90,13 +90,13 @@ private static void DisableUsingSdkFromEnvironmentVariable() Environment.SetEnvironmentVariable("MSBuildSDKsPath", null); } - private void WriteProjects(Solution solution, string outputPath, string solutionFilePath) + private void WriteProjects(NetCoreSdkInfo sdk, Solution solution, string outputPath, string solutionFilePath) { var projectPathMappings = new Dictionary(); foreach (var project in solution.Projects) { var formatProjectWriter = _projectWriterFactory.FromProjectFormat(project.ProjectFormat); - string pathToProjectFile = WriteProject(project, outputPath, formatProjectWriter, solutionFilePath); + string pathToProjectFile = WriteProject(sdk, project, outputPath, formatProjectWriter, solutionFilePath); projectPathMappings.Add(project, pathToProjectFile); } @@ -107,9 +107,9 @@ private void WriteProjects(Solution solution, string outputPath, string solution } } - private string WriteProject(Project project, string outputPath, IProjectWriter formatProjectWriter, string solutionFilePath) + private string WriteProject(NetCoreSdkInfo sdk, Project project, string outputPath, IProjectWriter formatProjectWriter, string solutionFilePath) { - string projPath = formatProjectWriter.WriteProject(project, Path.Combine(outputPath, project.Name)); + string projPath = formatProjectWriter.WriteProject(sdk, project, Path.Combine(outputPath, project.Name)); var addProjCommand = DotNet.Sln(_outputWriter).AddProject().Project(projPath).ToSolution(solutionFilePath).Build().Execute(); if (addProjCommand.ExitCode != 0)