From c4aa8f5badefb493f491fe42fa8606165d3b5b26 Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:55:47 -0500 Subject: [PATCH 01/14] Alpha --- .../ProjectTemplate.csproj | 12 +-- .../Reqnroll.VisualStudio.csproj | 5 ++ .../Resources/TestFrameworkDescriptors.json | 14 +++ .../AddNewReqnrollProjectViewModel.cs | 5 ++ .../NewProjectMetaDataProvider.cs | 87 +++++++++++++++++++ .../Wizards/ReqnrollProjectWizard.cs | 12 ++- 6 files changed, 121 insertions(+), 14 deletions(-) create mode 100644 Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json create mode 100644 Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs diff --git a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj index af39a4ff..a0291dc4 100644 --- a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj +++ b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj @@ -7,16 +7,8 @@ - $if$ ('$unittestframework$' == 'xUnit') - - - $endif$$if$ ('$unittestframework$' == 'NUnit') - - - $endif$$if$ ('$unittestframework$' == 'MSTest') - - - $endif$$if$ ('$fluentassertionsincluded$' == 'True') + + $unittestframework$$if$ ('$fluentassertionsincluded$' == 'True') $endif$ diff --git a/Reqnroll.VisualStudio/Reqnroll.VisualStudio.csproj b/Reqnroll.VisualStudio/Reqnroll.VisualStudio.csproj index d7ff0e86..11f3b47f 100644 --- a/Reqnroll.VisualStudio/Reqnroll.VisualStudio.csproj +++ b/Reqnroll.VisualStudio/Reqnroll.VisualStudio.csproj @@ -8,8 +8,13 @@ TRACE; + + + + + diff --git a/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json b/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json new file mode 100644 index 00000000..c202368a --- /dev/null +++ b/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json @@ -0,0 +1,14 @@ +{ + "xUnit": { + "description": "Use xUnit v2 test executor with Reqnroll", + "dependencies": "\n\n" + }, + "MsTest": { + "description": "Use MsTest v3 test executor with Reqnroll", + "dependencies": "\n\n" + }, + "NUnit": { + "description": "Use NUnit v3 test executor with Reqnroll", + "dependencies": "\n\n" + } +} \ No newline at end of file diff --git a/Reqnroll.VisualStudio/UI/ViewModels/AddNewReqnrollProjectViewModel.cs b/Reqnroll.VisualStudio/UI/ViewModels/AddNewReqnrollProjectViewModel.cs index 50c42a64..0638344f 100644 --- a/Reqnroll.VisualStudio/UI/ViewModels/AddNewReqnrollProjectViewModel.cs +++ b/Reqnroll.VisualStudio/UI/ViewModels/AddNewReqnrollProjectViewModel.cs @@ -6,6 +6,11 @@ public class AddNewReqnrollProjectViewModel : INotifyPropertyChanged private const string MsTest = "MsTest"; private const string Net8 = "net8.0"; + public AddNewReqnrollProjectViewModel() { } + public AddNewReqnrollProjectViewModel(IEnumerable testFrameworkNames) + { + TestFrameworks = new (testFrameworkNames); + } #if DEBUG public static AddNewReqnrollProjectViewModel DesignData = new() { diff --git a/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs b/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs new file mode 100644 index 00000000..06ecab12 --- /dev/null +++ b/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs @@ -0,0 +1,87 @@ +namespace Reqnroll.VisualStudio.Wizards.Infrastructure; + +public interface INewProjectMetaDataProvider +{ + IEnumerable TestFrameworks { get; } + string DependenciesOf(string testFramework); +} +public record TestFrameworkInfoModel(string description, string dependencies); + +[Export(typeof(INewProjectMetaDataProvider))] +public class NewProjectMetaDataProvider : INewProjectMetaDataProvider +{ + private Dictionary _testFrameworkDescriptors = new(); + private Task> _httpTask; + private Lazy> _resolvedTestFrameworkDescriptors; + + [ImportingConstructor] + public NewProjectMetaDataProvider() + { + // read static metadata from a resource file, deserialize the resulting json, storing it in the _testFrameworkDescriptors field + var resourceName = "Reqnroll.VisualStudio.Resources.TestFrameworkDescriptors.json"; + using (var stream = typeof(NewProjectMetaDataProvider).Assembly.GetManifestResourceStream(resourceName)) + using (var reader = new StreamReader(stream)) + { + var json = reader.ReadToEnd(); + var data = JsonSerialization.DeserializeObject>(json); + if (data != null) + _testFrameworkDescriptors = data; + } + + // launch a task to read metadata from http resource and deserialize the resulting json, save the Task to a field + _httpTask = Task.Run(async () => + { + try + { + using (var httpClient = new System.Net.Http.HttpClient()) + { + var httpJson = await httpClient.GetStringAsync("https://example.com/testframeworks.json").ConfigureAwait(false); + var httpData = JsonSerialization.DeserializeObject>(httpJson); + return httpData; + } + } + catch + { + return null; + } + }); + + _resolvedTestFrameworkDescriptors = new Lazy>(FinishRetrievalOfTestFrameworkDescriptors); + } + + public IEnumerable TestFrameworks + { + get + { + var descriptors = _resolvedTestFrameworkDescriptors.Value; + return descriptors.Keys; + } + } + + public string DependenciesOf(string testFramework) + { + var descriptors = _resolvedTestFrameworkDescriptors.Value; + return descriptors[testFramework].dependencies.Replace("\\n", Environment.NewLine); + } + + private Dictionary FinishRetrievalOfTestFrameworkDescriptors() + { + // Wait for the HTTP task to complete + if (_httpTask == null) + return _testFrameworkDescriptors; + + try + { + var result = _httpTask.GetAwaiter().GetResult(); + if (result != null) + { + _testFrameworkDescriptors = result; + } + } + catch + { + // Ignore exceptions, keep existing _testFrameworkDescriptors + } + return _testFrameworkDescriptors; + } +} diff --git a/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs b/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs index fc783a2d..69f216e3 100644 --- a/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs +++ b/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs @@ -10,28 +10,32 @@ public class ReqnrollProjectWizard : IDeveroomWizard { private readonly IDeveroomWindowManager _deveroomWindowManager; private readonly IMonitoringService _monitoringService; + private readonly INewProjectMetaDataProvider _newProjectMetaDataProvider; [ImportingConstructor] - public ReqnrollProjectWizard(IDeveroomWindowManager deveroomWindowManager, IMonitoringService monitoringService) + public ReqnrollProjectWizard(IDeveroomWindowManager deveroomWindowManager, IMonitoringService monitoringService, INewProjectMetaDataProvider newProjectMetaDataProvider) { _deveroomWindowManager = deveroomWindowManager; _monitoringService = monitoringService; + _newProjectMetaDataProvider = newProjectMetaDataProvider; } public bool RunStarted(WizardRunParameters wizardRunParameters) { _monitoringService.MonitorProjectTemplateWizardStarted(); - var viewModel = new AddNewReqnrollProjectViewModel(); + var frameworkNames = _newProjectMetaDataProvider.TestFrameworks; + + var viewModel = new AddNewReqnrollProjectViewModel(frameworkNames); var dialogResult = _deveroomWindowManager.ShowDialog(viewModel); if (!dialogResult.HasValue || !dialogResult.Value) return false; _monitoringService.MonitorProjectTemplateWizardCompleted(viewModel.DotNetFramework, viewModel.UnitTestFramework, viewModel.FluentAssertionsIncluded); - + var packageReferencesToInclude = _newProjectMetaDataProvider.DependenciesOf(viewModel.UnitTestFramework); // Add custom parameters. wizardRunParameters.ReplacementsDictionary.Add("$dotnetframework$", viewModel.DotNetFramework); - wizardRunParameters.ReplacementsDictionary.Add("$unittestframework$", viewModel.UnitTestFramework); + wizardRunParameters.ReplacementsDictionary.Add("$unittestframework$", packageReferencesToInclude); wizardRunParameters.ReplacementsDictionary.Add("$fluentassertionsincluded$", viewModel.FluentAssertionsIncluded.ToString(CultureInfo.InvariantCulture)); From 0be9ff0f6cac8ba876349cf6e59507195f966850 Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Thu, 5 Jun 2025 17:50:30 -0500 Subject: [PATCH 02/14] Revised substitution model. --- .../ProjectTemplate.csproj | 5 ++- .../Resources/TestFrameworkDescriptors.json | 45 +++++++++++++++++-- .../NewProjectMetaDataProvider.cs | 9 ++-- .../Wizards/ReqnrollProjectWizard.cs | 13 +++++- 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj index a0291dc4..3525fdcd 100644 --- a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj +++ b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj @@ -8,7 +8,10 @@ - $unittestframework$$if$ ('$fluentassertionsincluded$' == 'True') + $Reqnroll_Lib$ + $TestFramework_Lib$ + $Adapter_Lib$ + $if$ ('$fluentassertionsincluded$' == 'True') $endif$ diff --git a/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json b/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json index c202368a..10944a18 100644 --- a/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json +++ b/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json @@ -1,14 +1,53 @@ { "xUnit": { "description": "Use xUnit v2 test executor with Reqnroll", - "dependencies": "\n\n" + "dependencies": { + "Reqnroll_Lib": { + "name": "Reqnroll.xUnit", + "version": "2.4.1" + }, + "TestFramework_Lib": { + "name": "xunit", + "version": "2.8.1" + }, + "Adapter_Lib": { + "name": "xunit.runner.visualstudio", + "version": "2.8.1" + } + } }, "MsTest": { "description": "Use MsTest v3 test executor with Reqnroll", - "dependencies": "\n\n" + "dependencies": { + "Reqnroll_Lib": { + "name": "Reqnroll.MsTest", + "version": "2.4.1" + }, + "TestFramework_Lib": { + "name": "MSTest.TestFramework", + "version": "3.4.3" + }, + "Adapter_Lib": { + "name": "MSTest.TestAdapter", + "version": "3.4.3" + } + } }, "NUnit": { "description": "Use NUnit v3 test executor with Reqnroll", - "dependencies": "\n\n" + "dependencies": { + "Reqnroll_Lib": { + "name": "Reqnroll.NUnit", + "version": "2.4.1" + }, + "TestFramework_Lib": { + "name": "nunit", + "version": "3.14.0" + }, + "Adapter_Lib": { + "name": "NUnit3TestAdapter", + "version": "4.5.0" + } + } } } \ No newline at end of file diff --git a/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs b/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs index 06ecab12..e9735c58 100644 --- a/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs +++ b/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs @@ -3,9 +3,10 @@ namespace Reqnroll.VisualStudio.Wizards.Infrastructure; public interface INewProjectMetaDataProvider { IEnumerable TestFrameworks { get; } - string DependenciesOf(string testFramework); + IDictionary DependenciesOf(string testFramework); } -public record TestFrameworkInfoModel(string description, string dependencies); +public record NugetPackageDescriptor(string name, string version); +public record TestFrameworkInfoModel(string description, Dictionary dependencies); [Export(typeof(INewProjectMetaDataProvider))] public class NewProjectMetaDataProvider : INewProjectMetaDataProvider @@ -58,10 +59,10 @@ public IEnumerable TestFrameworks } } - public string DependenciesOf(string testFramework) + public IDictionary DependenciesOf(string testFramework) { var descriptors = _resolvedTestFrameworkDescriptors.Value; - return descriptors[testFramework].dependencies.Replace("\\n", Environment.NewLine); + return descriptors[testFramework].dependencies; } private Dictionary FinishRetrievalOfTestFrameworkDescriptors() diff --git a/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs b/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs index 69f216e3..6c0d0494 100644 --- a/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs +++ b/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs @@ -32,10 +32,19 @@ public bool RunStarted(WizardRunParameters wizardRunParameters) _monitoringService.MonitorProjectTemplateWizardCompleted(viewModel.DotNetFramework, viewModel.UnitTestFramework, viewModel.FluentAssertionsIncluded); - var packageReferencesToInclude = _newProjectMetaDataProvider.DependenciesOf(viewModel.UnitTestFramework); + + var dependencies = _newProjectMetaDataProvider.DependenciesOf(viewModel.UnitTestFramework); + var keys = new List() { "Reqnroll_Lib", "TestFramework_Lib", "Adapter_Lib" }; // Add custom parameters. + foreach(string k in keys) + { + var package = dependencies[k]; + var name = package.name; + var version = package.version; + wizardRunParameters.ReplacementsDictionary.Add($"${k}$",$""); + } + wizardRunParameters.ReplacementsDictionary.Add("$dotnetframework$", viewModel.DotNetFramework); - wizardRunParameters.ReplacementsDictionary.Add("$unittestframework$", packageReferencesToInclude); wizardRunParameters.ReplacementsDictionary.Add("$fluentassertionsincluded$", viewModel.FluentAssertionsIncluded.ToString(CultureInfo.InvariantCulture)); From 1e8d88dd3c9dc302d7bf30f9f58d861131f9f3ed Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Fri, 6 Jun 2025 13:46:26 -0500 Subject: [PATCH 03/14] Working substitution model with all lowercase and no underscores --- .../ProjectTemplate.csproj | 7 +++---- .../Resources/TestFrameworkDescriptors.json | 18 +++++++++--------- .../Wizards/ReqnrollProjectWizard.cs | 2 +- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj index 3525fdcd..582c4d28 100644 --- a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj +++ b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj @@ -8,10 +8,9 @@ - $Reqnroll_Lib$ - $TestFramework_Lib$ - $Adapter_Lib$ - $if$ ('$fluentassertionsincluded$' == 'True') + $reqnrolllib$ + $testframeworklib$ + $adapterlib$$if$ ('$fluentassertionsincluded$' == 'True') $endif$ diff --git a/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json b/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json index 10944a18..2f9773b3 100644 --- a/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json +++ b/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json @@ -2,15 +2,15 @@ "xUnit": { "description": "Use xUnit v2 test executor with Reqnroll", "dependencies": { - "Reqnroll_Lib": { + "reqnrolllib": { "name": "Reqnroll.xUnit", "version": "2.4.1" }, - "TestFramework_Lib": { + "testframeworklib": { "name": "xunit", "version": "2.8.1" }, - "Adapter_Lib": { + "adapterlib": { "name": "xunit.runner.visualstudio", "version": "2.8.1" } @@ -19,15 +19,15 @@ "MsTest": { "description": "Use MsTest v3 test executor with Reqnroll", "dependencies": { - "Reqnroll_Lib": { + "reqnrolllib": { "name": "Reqnroll.MsTest", "version": "2.4.1" }, - "TestFramework_Lib": { + "testframeworklib": { "name": "MSTest.TestFramework", "version": "3.4.3" }, - "Adapter_Lib": { + "adapterlib": { "name": "MSTest.TestAdapter", "version": "3.4.3" } @@ -36,15 +36,15 @@ "NUnit": { "description": "Use NUnit v3 test executor with Reqnroll", "dependencies": { - "Reqnroll_Lib": { + "reqnrolllib": { "name": "Reqnroll.NUnit", "version": "2.4.1" }, - "TestFramework_Lib": { + "testframeworklib": { "name": "nunit", "version": "3.14.0" }, - "Adapter_Lib": { + "adapterlib": { "name": "NUnit3TestAdapter", "version": "4.5.0" } diff --git a/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs b/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs index 6c0d0494..b2bf73c9 100644 --- a/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs +++ b/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs @@ -34,7 +34,7 @@ public bool RunStarted(WizardRunParameters wizardRunParameters) viewModel.FluentAssertionsIncluded); var dependencies = _newProjectMetaDataProvider.DependenciesOf(viewModel.UnitTestFramework); - var keys = new List() { "Reqnroll_Lib", "TestFramework_Lib", "Adapter_Lib" }; + var keys = new List() { "reqnrolllib", "testframeworklib", "adapterlib" }; // Add custom parameters. foreach(string k in keys) { From d09cdbe118407634b256c8395ff8265d59784405 Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Sat, 7 Jun 2025 10:08:33 -0500 Subject: [PATCH 04/14] Working example using a fixed number of slots for packages. --- .../ProjectTemplate.csproj | 17 ++++++---- .../Resources/TestFrameworkDescriptors.json | 32 +++++++++---------- .../NewProjectMetaDataProvider.cs | 21 ++++++------ .../Wizards/ReqnrollProjectWizard.cs | 28 +++++++++++++--- 4 files changed, 61 insertions(+), 37 deletions(-) diff --git a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj index 582c4d28..33fbf9c9 100644 --- a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj +++ b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj @@ -6,12 +6,17 @@ enable - - - $reqnrolllib$ - $testframeworklib$ - $adapterlib$$if$ ('$fluentassertionsincluded$' == 'True') - $endif$ + $if$ ('$packagerefhasvalue0$' == 'True') + $endif$$if$ ('$packagerefhasvalue1$' == 'True') + $endif$$if$ ('$packagerefhasvalue2$' == 'True') + $endif$$if$ ('$packagerefhasvalue3$' == 'True') + $endif$$if$ ('$packagerefhasvalue4$' == 'True') + $endif$$if$ ('$packagerefhasvalue5$' == 'True') + $endif$$if$ ('$packagerefhasvalue6$' == 'True') + $endif$$if$ ('$packagerefhasvalue7$' == 'True') + $endif$$if$ ('$packagerefhasvalue8$' == 'True') + $endif$$if$ ('$packagerefhasvalue9$' == 'True') + $endif$ diff --git a/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json b/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json index 2f9773b3..f3c09490 100644 --- a/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json +++ b/Reqnroll.VisualStudio/Resources/TestFrameworkDescriptors.json @@ -1,53 +1,53 @@ { "xUnit": { "description": "Use xUnit v2 test executor with Reqnroll", - "dependencies": { - "reqnrolllib": { + "dependencies": [ + { "name": "Reqnroll.xUnit", "version": "2.4.1" }, - "testframeworklib": { + { "name": "xunit", "version": "2.8.1" }, - "adapterlib": { + { "name": "xunit.runner.visualstudio", "version": "2.8.1" } - } + ] }, "MsTest": { "description": "Use MsTest v3 test executor with Reqnroll", - "dependencies": { - "reqnrolllib": { + "dependencies": [ + { "name": "Reqnroll.MsTest", "version": "2.4.1" }, - "testframeworklib": { + { "name": "MSTest.TestFramework", "version": "3.4.3" }, - "adapterlib": { + { "name": "MSTest.TestAdapter", "version": "3.4.3" } - } + ] }, "NUnit": { "description": "Use NUnit v3 test executor with Reqnroll", - "dependencies": { - "reqnrolllib": { + "dependencies": [ + { "name": "Reqnroll.NUnit", "version": "2.4.1" }, - "testframeworklib": { + { "name": "nunit", "version": "3.14.0" }, - "adapterlib": { + { "name": "NUnit3TestAdapter", "version": "4.5.0" } - } + ] } -} \ No newline at end of file +} diff --git a/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs b/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs index e9735c58..aa6d0540 100644 --- a/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs +++ b/Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaDataProvider.cs @@ -3,22 +3,22 @@ namespace Reqnroll.VisualStudio.Wizards.Infrastructure; public interface INewProjectMetaDataProvider { IEnumerable TestFrameworks { get; } - IDictionary DependenciesOf(string testFramework); + IEnumerable DependenciesOf(string testFramework); } public record NugetPackageDescriptor(string name, string version); -public record TestFrameworkInfoModel(string description, Dictionary dependencies); +public record TestFrameworkInfoModel(string description, IEnumerable dependencies); [Export(typeof(INewProjectMetaDataProvider))] public class NewProjectMetaDataProvider : INewProjectMetaDataProvider { - private Dictionary _testFrameworkDescriptors = new(); + private Dictionary _fallbackTestFrameworkDescriptors = new(); private Task> _httpTask; private Lazy> _resolvedTestFrameworkDescriptors; [ImportingConstructor] public NewProjectMetaDataProvider() { - // read static metadata from a resource file, deserialize the resulting json, storing it in the _testFrameworkDescriptors field + // read static metadata from a resource file, deserialize the resulting json, storing it in the _fallbackTestFrameworkDescriptors field var resourceName = "Reqnroll.VisualStudio.Resources.TestFrameworkDescriptors.json"; using (var stream = typeof(NewProjectMetaDataProvider).Assembly.GetManifestResourceStream(resourceName)) using (var reader = new StreamReader(stream)) @@ -26,7 +26,7 @@ public NewProjectMetaDataProvider() var json = reader.ReadToEnd(); var data = JsonSerialization.DeserializeObject>(json); if (data != null) - _testFrameworkDescriptors = data; + _fallbackTestFrameworkDescriptors = data; } // launch a task to read metadata from http resource and deserialize the resulting json, save the Task to a field @@ -59,7 +59,7 @@ public IEnumerable TestFrameworks } } - public IDictionary DependenciesOf(string testFramework) + public IEnumerable DependenciesOf(string testFramework) { var descriptors = _resolvedTestFrameworkDescriptors.Value; return descriptors[testFramework].dependencies; @@ -69,20 +69,21 @@ private Dictionary FinishRetrievalOfTestFramewor { // Wait for the HTTP task to complete if (_httpTask == null) - return _testFrameworkDescriptors; + return _fallbackTestFrameworkDescriptors; try { var result = _httpTask.GetAwaiter().GetResult(); if (result != null) { - _testFrameworkDescriptors = result; + return result; } } catch { - // Ignore exceptions, keep existing _testFrameworkDescriptors + // Ignore exceptions, keep existing _fallbackTestFrameworkDescriptors } - return _testFrameworkDescriptors; + // If we've gotten to this point, the http end point returned no result or failed. So, we fall back. + return _fallbackTestFrameworkDescriptors; } } diff --git a/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs b/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs index b2bf73c9..f69463a8 100644 --- a/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs +++ b/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs @@ -33,21 +33,39 @@ public bool RunStarted(WizardRunParameters wizardRunParameters) _monitoringService.MonitorProjectTemplateWizardCompleted(viewModel.DotNetFramework, viewModel.UnitTestFramework, viewModel.FluentAssertionsIncluded); + int packageIndex = 0; + + // insert set of replacement variables for the SDK package + AddPackageToReplacementDictionary(wizardRunParameters, "Microsoft.NET.Test.Sdk", "17.10.0", packageIndex); + var dependencies = _newProjectMetaDataProvider.DependenciesOf(viewModel.UnitTestFramework); - var keys = new List() { "reqnrolllib", "testframeworklib", "adapterlib" }; - // Add custom parameters. - foreach(string k in keys) + + foreach (var package in dependencies) { - var package = dependencies[k]; + packageIndex++; var name = package.name; var version = package.version; - wizardRunParameters.ReplacementsDictionary.Add($"${k}$",$""); + AddPackageToReplacementDictionary(wizardRunParameters, name, version, packageIndex); } + if (viewModel.FluentAssertionsIncluded) + AddPackageToReplacementDictionary(wizardRunParameters, "FluentAssertions", "6.12.0", packageIndex+1); + wizardRunParameters.ReplacementsDictionary.Add("$dotnetframework$", viewModel.DotNetFramework); wizardRunParameters.ReplacementsDictionary.Add("$fluentassertionsincluded$", viewModel.FluentAssertionsIncluded.ToString(CultureInfo.InvariantCulture)); return true; + + static void AddPackageToReplacementDictionary(WizardRunParameters wizardRunParameters, string name, string version, int packageIndex) + { + string packagename = "packagerefname"; + string packageversion = "packagerefversion"; + string packagehasvalue = "packagerefhasvalue"; + + wizardRunParameters.ReplacementsDictionary.Add($"${packagehasvalue}{packageIndex}$", true.ToString(CultureInfo.InvariantCulture)); + wizardRunParameters.ReplacementsDictionary.Add($"${packagename}{packageIndex}$", name); + wizardRunParameters.ReplacementsDictionary.Add($"${packageversion}{packageIndex}$", version); + } } } From b28fd7c5d94c1e13601a161289d7333b94851081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1sp=C3=A1r=20Nagy?= Date: Tue, 10 Jun 2025 15:21:06 +0200 Subject: [PATCH 05/14] dummy implementation for single template param reference substitution --- .../ProjectTemplate.csproj | 4 +++ .../Wizards/ReqnrollProjectWizard.cs | 28 ++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj index 33fbf9c9..04ce7696 100644 --- a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj +++ b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj @@ -19,6 +19,10 @@ $endif$ + + $foo$ + + diff --git a/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs b/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs index f69463a8..f5ef839c 100644 --- a/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs +++ b/Reqnroll.VisualStudio/Wizards/ReqnrollProjectWizard.cs @@ -59,13 +59,27 @@ public bool RunStarted(WizardRunParameters wizardRunParameters) static void AddPackageToReplacementDictionary(WizardRunParameters wizardRunParameters, string name, string version, int packageIndex) { - string packagename = "packagerefname"; - string packageversion = "packagerefversion"; - string packagehasvalue = "packagerefhasvalue"; - - wizardRunParameters.ReplacementsDictionary.Add($"${packagehasvalue}{packageIndex}$", true.ToString(CultureInfo.InvariantCulture)); - wizardRunParameters.ReplacementsDictionary.Add($"${packagename}{packageIndex}$", name); - wizardRunParameters.ReplacementsDictionary.Add($"${packageversion}{packageIndex}$", version); + var refText = $""; + const string key = "$foo$"; + if (wizardRunParameters.ReplacementsDictionary.TryGetValue(key, out string existingValue)) + { + wizardRunParameters.ReplacementsDictionary[key] = + existingValue + + "\r\n " + + refText; + } + else + { + wizardRunParameters.ReplacementsDictionary.Add(key, refText); + } + + //string packagename = "packagerefname"; + //string packageversion = "packagerefversion"; + //string packagehasvalue = "packagerefhasvalue"; + + //wizardRunParameters.ReplacementsDictionary.Add($"${packagehasvalue}{packageIndex}$", true.ToString(CultureInfo.InvariantCulture)); + //wizardRunParameters.ReplacementsDictionary.Add($"${packagename}{packageIndex}$", name); + //wizardRunParameters.ReplacementsDictionary.Add($"${packageversion}{packageIndex}$", version); } } } From b3faa4bb88121dfc51e90357b38662f0f6f13ca0 Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Fri, 13 Jun 2025 09:58:23 -0500 Subject: [PATCH 06/14] Now fetching descriptors from URL. EnvironmentVariable is available to override the URL for testing purposes. Added Description and HyperLink content to the dialog box. --- .../ProjectTemplate.csproj | 15 +- .../Dialogs/AddNewReqnrollProjectDialog.xaml | 365 +++++++++--------- .../AddNewReqnrollProjectDialog.xaml.cs | 10 +- .../Resources/TestFrameworkDescriptors.json | 168 +++++--- .../AddNewReqnrollProjectViewModel.cs | 83 +++- .../Infrastructure/HttpClientWrapper.cs | 15 + .../Wizards/Infrastructure/IHttpClient.cs | 5 + .../Infrastructure/NewProjectMetaData.cs | 26 ++ .../NewProjectMetaDataProvider.cs | 97 ++--- .../Infrastructure/NewProjectModels.cs | 28 ++ .../Wizards/ReqnrollProjectWizard.cs | 32 +- 11 files changed, 510 insertions(+), 334 deletions(-) create mode 100644 Reqnroll.VisualStudio/Wizards/Infrastructure/HttpClientWrapper.cs create mode 100644 Reqnroll.VisualStudio/Wizards/Infrastructure/IHttpClient.cs create mode 100644 Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectMetaData.cs create mode 100644 Reqnroll.VisualStudio/Wizards/Infrastructure/NewProjectModels.cs diff --git a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj index 04ce7696..4dd793d7 100644 --- a/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj +++ b/Reqnroll.VisualStudio.ProjectTemplate/ProjectTemplate.csproj @@ -6,21 +6,8 @@ enable - $if$ ('$packagerefhasvalue0$' == 'True') - $endif$$if$ ('$packagerefhasvalue1$' == 'True') - $endif$$if$ ('$packagerefhasvalue2$' == 'True') - $endif$$if$ ('$packagerefhasvalue3$' == 'True') - $endif$$if$ ('$packagerefhasvalue4$' == 'True') - $endif$$if$ ('$packagerefhasvalue5$' == 'True') - $endif$$if$ ('$packagerefhasvalue6$' == 'True') - $endif$$if$ ('$packagerefhasvalue7$' == 'True') - $endif$$if$ ('$packagerefhasvalue8$' == 'True') - $endif$$if$ ('$packagerefhasvalue9$' == 'True') - $endif$ - - - $foo$ + $nugetpackagereferences$ diff --git a/Reqnroll.VisualStudio.UI/Dialogs/AddNewReqnrollProjectDialog.xaml b/Reqnroll.VisualStudio.UI/Dialogs/AddNewReqnrollProjectDialog.xaml index db226e1a..78938961 100644 --- a/Reqnroll.VisualStudio.UI/Dialogs/AddNewReqnrollProjectDialog.xaml +++ b/Reqnroll.VisualStudio.UI/Dialogs/AddNewReqnrollProjectDialog.xaml @@ -18,172 +18,173 @@ AllowDrop="True" TextOptions.TextFormattingMode="Display" HasDialogFrame="False" WindowStyle="None"> - - + - - - - - - - - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + - - - - .NET Framework 4.6.2 - .NET Framework 4.7 - .NET Framework 4.7.1 - .NET Framework 4.7.2 - .NET Framework 4.8 - .NET Framework 4.8.1 - .NET 6.0 - .NET 7.0 - .NET 8.0 - .NET 9.0 - - + + + + - - - + + - + + + + + - - + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + + + - - - - + - - - + + - + - - - + + - - + + @@ -259,25 +259,25 @@ - + - - - - - - - - - - - + + + + + + + + + + -