diff --git a/Standardly.Tests.Unit/Standardly.Tests.Unit.csproj b/Standardly.Tests.Unit/Standardly.Tests.Unit.csproj index 901806b..4cfdc53 100644 --- a/Standardly.Tests.Unit/Standardly.Tests.Unit.csproj +++ b/Standardly.Tests.Unit/Standardly.Tests.Unit.csproj @@ -10,13 +10,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Standardly/.vsextension/string-resources.json b/Standardly/.vsextension/string-resources.json index 7ad79ab..7396b3f 100644 --- a/Standardly/.vsextension/string-resources.json +++ b/Standardly/.vsextension/string-resources.json @@ -5,5 +5,6 @@ "Standardly.ShowMyUsageStats.DisplayName": "Show My Usage Stats", "Standardly.ShowTemplatesFolderCommand.DisplayName": "Show Template Folder", "Standardly.ShowLicenseCommand.DisplayName": "Show License", + "Standardly.ShowConfigurationCommand.DisplayName": "Show Configuration Settings", "Standardly.ToolWindows.GenerateCodeToolWindowCommand.DisplayName": "Standardly - Generate Code" } diff --git a/Standardly/Brokers/CodeGenerationBroker.GenerateCode.cs b/Standardly/Brokers/CodeGenerationBroker.GenerateCode.cs index e04f720..3555cd4 100644 --- a/Standardly/Brokers/CodeGenerationBroker.GenerateCode.cs +++ b/Standardly/Brokers/CodeGenerationBroker.GenerateCode.cs @@ -13,7 +13,7 @@ internal partial class CodeGenerationBroker { public async ValueTask GenerateCodeAsync(TemplateGenerationInfo templateGenerationInfo) { - await this.standardlyClient.GenerationClient.GenerateCodeAsync(templateGenerationInfo); + await this.standardlyClient.CodeGenerations.GenerateCodeAsync(templateGenerationInfo); } } } diff --git a/Standardly/Brokers/CodeGenerationBroker.Templates.cs b/Standardly/Brokers/CodeGenerationBroker.Templates.cs index 70c56eb..17cd996 100644 --- a/Standardly/Brokers/CodeGenerationBroker.Templates.cs +++ b/Standardly/Brokers/CodeGenerationBroker.Templates.cs @@ -20,7 +20,7 @@ public async ValueTask> FindAllTemplatesAsync() string templateFolderPath = Path.Combine(Path.GetDirectoryName(assembly), @"Templates"); string templateDefinitionFileName = "Template.json"; - return await this.standardlyClient.TemplateClient + return await this.standardlyClient.Templates .FindAllTemplatesAsync(templateFolderPath, templateDefinitionFileName); } } diff --git a/Standardly/Commands/GenerateCodeCommand.cs b/Standardly/Commands/GenerateCodeCommand.cs index b26c783..b4e3ca5 100644 --- a/Standardly/Commands/GenerateCodeCommand.cs +++ b/Standardly/Commands/GenerateCodeCommand.cs @@ -4,12 +4,20 @@ // See License.txt in the project root for license information. // --------------------------------------------------------------- +using System; +using System.Collections.Generic; using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft; +using Microsoft.Extensions.Configuration; using Microsoft.VisualStudio.Extensibility; using Microsoft.VisualStudio.Extensibility.Commands; +using Microsoft.VisualStudio.ProjectSystem.Query; +using Standardly.Models.Configurations; using Standardly.ToolWindows; namespace Standardly.Commands @@ -56,8 +64,149 @@ public override Task InitializeAsync(CancellationToken cancellationToken) /// public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) { + string assemblyLocation = Assembly.GetExecutingAssembly().Location; + string extensionFolder = Path.GetDirectoryName(assemblyLocation); + string appSettingsRelativePath = "appsettings.json"; + string appSettingsPath = Path.Combine(extensionFolder, appSettingsRelativePath); + + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(extensionFolder) + .AddJsonFile(appSettingsPath, optional: true, reloadOnChange: true); + + var configuration = configurationBuilder.Build(); + + var standardlyConfiguration = configuration + .GetSection("standardlyConfiguration") + .Get(); + + var structureInfo = await GetSettings(context, cancellationToken); + try + { + var standardlyClient = new Core.Clients.StandardlyClient(); + } + catch (Exception ex) + { + throw; + } + + //var frmGenerate = new frmGenerate(structureInfo, standardlyClient); + //frmGenerate.ShowDialog(); + await this.Extensibility.Shell() .ShowToolWindowAsync(activate: true, cancellationToken); } + + private async ValueTask GetSettings( + IClientContext context, + CancellationToken cancellationToken) + { + ISolutionSnapshot? solution = (await context.Extensibility.Workspaces().QuerySolutionAsync(solution => + { + return solution + .With(x => x.Path) + .With(x => x.BaseName) + .With(x => x.Directory) + .With(x => x.FileName); + }, + cancellationToken)).FirstOrDefault(); + + List projects = (await context.Extensibility.Workspaces().QueryProjectsAsync(projects => + { + return projects + .With(x => x.Path) + .With(x => x.Name) + .With(x => x.Type) + .With(x => x.ProjectReferences) + .With(x => x.DefaultNamespace) + .With(x => x.Properties) + .With(x => x.Folders) + .With(x => x.Capabilities) + .With(x => x.Kind); + }, + cancellationToken)).ToList(); + + IProjectSnapshot? activeProject = await context.GetActiveProjectAsync(project => + { + return project + .With(x => x.Path) + .With(x => x.Name) + .With(x => x.Type) + .With(x => x.ProjectReferences) + .With(x => x.DefaultNamespace) + .With(x => x.Properties) + .With(x => x.Folders) + .With(x => x.Capabilities) + .With(x => x.Kind); + }, + new CancellationToken()); + + IProjectSnapshot? project = activeProject ?? projects.FirstOrDefault(); + + if (project == null) + { + throw new Exception("No project found."); + } + + var structureInfo = new StructureInfo(); + string assumeProjectName = project.Name; + + switch (project.Name) + { + case string s when s.Contains(".Tests"): + { + assumeProjectName = project.Name + .Substring(0, Math.Max(project.Name.IndexOf(".Tests"), 0)); + + project = projects.FirstOrDefault(project => project.Name == assumeProjectName); + break; + } + case string s when s.Contains(".Infrastructure"): + { + assumeProjectName = project.Name + .Substring(0, Math.Max(project.Name.IndexOf(".Infrastructure"), 0)); + + project = projects.FirstOrDefault(project => project.Name == assumeProjectName); + break; + } + } + + IProjectSnapshot? unitTestProject = projects + .FirstOrDefault(project => project.Name == $"{assumeProjectName}.Tests.Unit"); + + IProjectSnapshot? acceptanceTestProject = projects + .FirstOrDefault(project => project.Name == $"{assumeProjectName}.Tests.Acceptance"); + + IProjectSnapshot? integrationTestProject = projects + .FirstOrDefault(project => project.Name == $"{assumeProjectName}.Tests.Integration"); + + IProjectSnapshot? infrastructureProject = projects + .FirstOrDefault(project => project.Name == $"{assumeProjectName}.Infrastructure"); + + + structureInfo.SolutionFolder = solution.Directory; + structureInfo.RootNameSpace = project.Name; + + structureInfo.Project = project != null + ? new ProjectInfo(projectName: project.Name, projectPath: project.Path) + : null; + + structureInfo.UnitTestProject = unitTestProject != null + ? new ProjectInfo(projectName: unitTestProject.Name, projectPath: unitTestProject.Path) + : null; + + structureInfo.AcceptanceTestProject = acceptanceTestProject != null + ? new ProjectInfo(projectName: acceptanceTestProject.Name, projectPath: acceptanceTestProject.Path) + : null; + + structureInfo.IntegrationTestProject = integrationTestProject != null + ? new ProjectInfo(projectName: integrationTestProject.Name, projectPath: integrationTestProject.Path) + : null; + + structureInfo.InfrastructureProject = infrastructureProject != null + ? new ProjectInfo(projectName: infrastructureProject.Name, projectPath: infrastructureProject.Path) + : null; + + return structureInfo; + } } } diff --git a/Standardly/Commands/ShowConfigurationCommand.cs b/Standardly/Commands/ShowConfigurationCommand.cs new file mode 100644 index 0000000..d40d6be --- /dev/null +++ b/Standardly/Commands/ShowConfigurationCommand.cs @@ -0,0 +1,65 @@ +// --------------------------------------------------------------- +// Copyright (c) Christo du Toit. All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft; +using Microsoft.VisualStudio.Extensibility; +using Microsoft.VisualStudio.Extensibility.Commands; + +namespace Standardly.Commands +{ + /// + /// ShowConfigurationCommand handler. + /// + [VisualStudioContribution] + internal class ShowConfigurationCommand : Command + { + private readonly TraceSource logger; + + /// + /// Initializes a new instance of the class. + /// + /// Extensibility object. + /// Trace source instance to utilize. + public ShowConfigurationCommand(VisualStudioExtensibility extensibility, TraceSource traceSource) + : base(extensibility) + { + // This optional TraceSource can be used for logging in the command. You can use dependency injection + // to access other services here as well. + this.logger = Requires.NotNull(traceSource, nameof(traceSource)); + } + + /// + public override CommandConfiguration CommandConfiguration => + new(displayName: "%Standardly.ShowConfigurationCommand.DisplayName%") + { + Icon = new(ImageMoniker.KnownValues.Extension, IconSettings.IconAndText), + }; + + /// + public override Task InitializeAsync(CancellationToken cancellationToken) + { + // Use InitializeAsync for any one-time setup or initialization. + return base.InitializeAsync(cancellationToken); + } + + /// + public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) + { + await Task.Run(() => + { + string assembly = Assembly.GetExecutingAssembly().Location; + string licensePath = Path.Combine(Path.GetDirectoryName(assembly), "appsettings.json"); + + Process.Start("notepad.exe", licensePath); + }); + } + } +} diff --git a/Standardly/Commands/ShowMyUsageStats.cs b/Standardly/Commands/ShowMyUsageStats.cs index 2db07b5..aa1f1ed 100644 --- a/Standardly/Commands/ShowMyUsageStats.cs +++ b/Standardly/Commands/ShowMyUsageStats.cs @@ -52,7 +52,7 @@ public override Task InitializeAsync(CancellationToken cancellationToken) /// public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) { - await context.ShowPromptAsync("Hello from an extension!", PromptOptions.OK, cancellationToken); + await this.Extensibility.Shell().ShowPromptAsync("Hello from an extension!", PromptOptions.OK, cancellationToken); } } } diff --git a/Standardly/ExtensionEntrypoint.cs b/Standardly/ExtensionEntrypoint.cs index 328c508..d98859f 100644 --- a/Standardly/ExtensionEntrypoint.cs +++ b/Standardly/ExtensionEntrypoint.cs @@ -1,6 +1,8 @@ -// ---------------------------------------------------------------------------------- -// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers -// ---------------------------------------------------------------------------------- +// --------------------------------------------------------------- +// Copyright (c) Christo du Toit. All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.Extensibility; @@ -10,7 +12,7 @@ namespace Standardly { /// - /// Extension entrypoint for the VisualStudio.Extensibility extension. + /// Extension entry point for the VisualStudio.Extensibility extension. /// [VisualStudioContribution] internal class ExtensionEntrypoint : Extension @@ -22,7 +24,8 @@ internal class ExtensionEntrypoint : Extension id: "Standardly.4f725561-953f-4998-99c2-ec58132d8d48", version: this.ExtensionAssemblyVersion, publisherName: "Christo du Toit", - displayName: "Standardly"), + displayName: "Standardly", + description: "Standardly - Your Code Generation Engine"), }; /// @@ -47,8 +50,8 @@ protected override void InitializeServices(IServiceCollection serviceCollection) MenuChild.Command(), MenuChild.Command(), MenuChild.Command(), + MenuChild.Command(), }, - Priority = 1000, }; } } diff --git a/Standardly/Models/Configurations/ProjectInfo.cs b/Standardly/Models/Configurations/ProjectInfo.cs new file mode 100644 index 0000000..0bdb4b4 --- /dev/null +++ b/Standardly/Models/Configurations/ProjectInfo.cs @@ -0,0 +1,30 @@ +// --------------------------------------------------------------- +// Copyright (c) Christo du Toit. All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +using System.IO; + +namespace Standardly.Models.Configurations +{ + internal class ProjectInfo + { + public ProjectInfo() + { } + + public ProjectInfo(string projectName, string projectPath) + { + ProjectName = projectName; + ProjectFullPath = projectPath; + FileInfo fileInfo = new FileInfo(projectPath); + ProjectFolder = fileInfo?.Directory?.FullName ?? string.Empty; + ProjectFile = fileInfo?.Name ?? string.Empty; + } + + public string ProjectName { get; set; } = string.Empty; + public string ProjectFullPath { get; set; } = string.Empty; + public string ProjectFolder { get; set; } = string.Empty; + public string ProjectFile { get; set; } = string.Empty; + } +} diff --git a/Standardly/Models/Configurations/StructureInfo.cs b/Standardly/Models/Configurations/StructureInfo.cs new file mode 100644 index 0000000..ee53520 --- /dev/null +++ b/Standardly/Models/Configurations/StructureInfo.cs @@ -0,0 +1,19 @@ +// --------------------------------------------------------------- +// Copyright (c) Christo du Toit. All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +namespace Standardly.Models.Configurations +{ + internal class StructureInfo + { + public string? SolutionFolder { get; set; } + public string? RootNameSpace { get; set; } + public ProjectInfo? Project { get; set; } + public ProjectInfo? UnitTestProject { get; set; } + public ProjectInfo? AcceptanceTestProject { get; set; } + public ProjectInfo? IntegrationTestProject { get; set; } + public ProjectInfo? InfrastructureProject { get; set; } + } +} diff --git a/Standardly/Standardly.csproj b/Standardly/Standardly.csproj index 3f0b078..530c086 100644 --- a/Standardly/Standardly.csproj +++ b/Standardly/Standardly.csproj @@ -1,7 +1,7 @@  - net7.0-windows + net8.0-windows disable enable true @@ -11,9 +11,16 @@ - - - + + + + + + + + + + @@ -23,14 +30,26 @@ - - - MSBuild:Compile - - + + + + + + + + Always + + + + + + MSBuild:Compile + + + + + + + - - - - diff --git a/Standardly/ToolWindows/GenerateCodeToolWindow.cs b/Standardly/ToolWindows/GenerateCodeToolWindow.cs index 31673ea..c952ca8 100644 --- a/Standardly/ToolWindows/GenerateCodeToolWindow.cs +++ b/Standardly/ToolWindows/GenerateCodeToolWindow.cs @@ -29,7 +29,7 @@ public class GenerateCodeToolWindow : ToolWindow public GenerateCodeToolWindow(VisualStudioExtensibility extensibility) : base(extensibility) { - this.Title = "My Tool Window"; + this.Title = "Standardly - Generate Code"; } /// diff --git a/Standardly/ToolWindows/GenerateCodeToolWindowCommand.cs b/Standardly/ToolWindows/GenerateCodeToolWindowCommand.cs index 185bff0..f38ee4a 100644 --- a/Standardly/ToolWindows/GenerateCodeToolWindowCommand.cs +++ b/Standardly/ToolWindows/GenerateCodeToolWindowCommand.cs @@ -22,23 +22,18 @@ public class GenerateCodeToolWindowCommand : Command /// Extensibility object instance. public GenerateCodeToolWindowCommand(VisualStudioExtensibility extensibility) : base(extensibility) - { - } + { } /// - public override CommandConfiguration CommandConfiguration => new(displayName: "%Standardly.ToolWindows.GenerateCodeToolWindowCommand.DisplayName%") - { - // Use this object initializer to set optional parameters for the command. The required parameter, - // displayName, is set above. To localize the displayName, add an entry in .vsextension\string-resources.json - // and reference it here by passing "%Standardly.ToolWindows.GenerateCodeToolWindowCommand.DisplayName%" as a constructor parameter. - Placements = new[] { CommandPlacement.KnownPlacements.ExtensionsMenu }, - Icon = new(ImageMoniker.KnownValues.Extension, IconSettings.IconAndText), - }; + public override CommandConfiguration CommandConfiguration => + new(displayName: "Standardly.ToolWindows.GenerateCodeToolWindowCommand.DisplayName%") + { }; /// public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) { - await this.Extensibility.Shell().ShowToolWindowAsync(activate: true, cancellationToken); + await this.Extensibility.Shell() + .ShowToolWindowAsync(activate: true, cancellationToken); } } } diff --git a/Standardly/appsettings.json b/Standardly/appsettings.json new file mode 100644 index 0000000..cf15228 --- /dev/null +++ b/Standardly/appsettings.json @@ -0,0 +1,28 @@ +{ + "standardlyConfiguration": { + "general": { + "addEditorConfigFile": true, + "addGitIgnoreFile": true, + "addGitAttributesFile": true, + "addReadmeFile": true, + "addLicenseFile": true, + "licenseType": "MIT" + }, + "user": { + "name": "", + "githubEmail": "", + "githubUsername": "" + }, + "locations": { + "brokers": "Brokers", + "controllers": "Controllers", + "clients": "Clients", + "coordinationServices": "Coordinations", + "foundationServices": "Foundations", + "models": "Models", + "orchestrationServices": "Orchestrations", + "processingServices": "Processings", + "services": "Services" + } + } +} diff --git a/Standardly/models/configurations/General.cs b/Standardly/models/configurations/General.cs new file mode 100644 index 0000000..4197304 --- /dev/null +++ b/Standardly/models/configurations/General.cs @@ -0,0 +1,18 @@ +// --------------------------------------------------------------- +// Copyright (c) Christo du Toit. All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +namespace Standardly.Models.Configurations +{ + internal class General + { + public bool addEditorConfigFile { get; set; } + public bool addGitIgnoreFile { get; set; } + public bool addGitAttributesFile { get; set; } + public bool addReadmeFile { get; set; } + public bool addLicenseFile { get; set; } + public string LicenseType { get; set; } + } +} diff --git a/Standardly/models/configurations/Locations.cs b/Standardly/models/configurations/Locations.cs new file mode 100644 index 0000000..070bf8f --- /dev/null +++ b/Standardly/models/configurations/Locations.cs @@ -0,0 +1,21 @@ +// --------------------------------------------------------------- +// Copyright (c) Christo du Toit. All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +namespace Standardly.Models.Configurations +{ + internal class Locations + { + public string Brokers { get; set; } + public string Controllers { get; set; } + public string Clients { get; set; } + public string CoordinationServices { get; set; } + public string FoundationServices { get; set; } + public string Models { get; set; } + public string OrchestrationServices { get; set; } + public string ProcessingServices { get; set; } + public string Services { get; set; } + } +} diff --git a/Standardly/models/configurations/StandardlyConfiguration.cs b/Standardly/models/configurations/StandardlyConfiguration.cs new file mode 100644 index 0000000..494001c --- /dev/null +++ b/Standardly/models/configurations/StandardlyConfiguration.cs @@ -0,0 +1,15 @@ +// --------------------------------------------------------------- +// Copyright (c) Christo du Toit. All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +namespace Standardly.Models.Configurations +{ + internal class StandardlyConfiguration + { + public General General { get; set; } + public User User { get; set; } + public Locations Locations { get; set; } + } +} diff --git a/Standardly/models/configurations/User.cs b/Standardly/models/configurations/User.cs new file mode 100644 index 0000000..724a45e --- /dev/null +++ b/Standardly/models/configurations/User.cs @@ -0,0 +1,15 @@ +// --------------------------------------------------------------- +// Copyright (c) Christo du Toit. All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +namespace Standardly.Models.Configurations +{ + internal class User + { + public string Name { get; set; } + public string GithubEmail { get; set; } + public string GithubUsername { get; set; } + } +}