feat: migrate 26eac54 state to Matrix42 26.1
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Matrix42.Extensions.Scaffolder.Core\Matrix42.Extensions.Scaffolder.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,61 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core;
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.ConsoleApp
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory()) // required for appsettings.json
|
||||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||
.Build();
|
||||
|
||||
var extensionPath = config["Scaffolder:ExtensionPath"];
|
||||
var extensionIdStr = config["Scaffolder:ExtensionId"];
|
||||
var extensionNamespace = config["Scaffolder:ExtensionNamespace"];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(extensionPath))
|
||||
throw new Exception("Scaffolder:ExtensionPath is missing in appsettings.json");
|
||||
|
||||
var extensionId = Guid.TryParse(extensionIdStr, out var gid) ? gid : Guid.NewGuid();
|
||||
|
||||
var options = new ExtensionScaffoldingOptions
|
||||
{
|
||||
ExtensionPath = extensionPath,
|
||||
ExtensionId = extensionId,
|
||||
ExtensionNamespace = extensionNamespace,
|
||||
Projects = [
|
||||
new ProjectDefinition
|
||||
{
|
||||
Prefix = "Services",
|
||||
Runtimes = RuntimeTargets.WinCore | RuntimeTargets.LinuxCore,
|
||||
Functionality = ProjectFunctionality.WebApi
|
||||
},
|
||||
|
||||
new ProjectDefinition
|
||||
{
|
||||
Prefix = "Contracts",
|
||||
Runtimes = RuntimeTargets.All,
|
||||
Functionality = ProjectFunctionality.Custom
|
||||
},
|
||||
new ProjectDefinition
|
||||
{
|
||||
Prefix = "BizLogic",
|
||||
Runtimes = RuntimeTargets.All,
|
||||
Functionality = ProjectFunctionality.Custom
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var scaffolder = new ExtensionScaffolder();
|
||||
var projects = scaffolder.Generate(options);
|
||||
|
||||
Console.WriteLine("Generated projects:");
|
||||
foreach (var p in projects)
|
||||
Console.WriteLine(" - " + p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"Scaffolder": {
|
||||
"ExtensionPath": "C:\\Projects\\Matrix42\\Titan_Linux\\ESM-FieldServiceManagement-Extension_demo",
|
||||
"ExtensionId": "c55407f9-9b46-4483-8b65-1bc1c3827efc",
|
||||
"ExtensionNamespace": "Matrix42.FieldServiceManagement"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!--
|
||||
Layout assumptions
|
||||
|
||||
This .targets file lives in:
|
||||
{ExtensionPath}\Extension.Assemblies.targets
|
||||
|
||||
We want to copy to:
|
||||
BasePackage\Assemblies\
|
||||
→ {ExtensionPath}\BasePackage\Assemblies\
|
||||
|
||||
Root\InstalledPackages\Assemblies\{ExtensionId}\
|
||||
→ {ExtensionPath}\..\Root\InstalledPackages\Assemblies\{ExtensionId}\
|
||||
|
||||
Properties:
|
||||
- M42BasePackageAssembliesDir (can override in csproj)
|
||||
- M42RootAssembliesDir (needs M42ExtensionId)
|
||||
- M42AssemblyPattern (default: $(MSBuildProjectName)*.*)
|
||||
- M42DefaultRids (default: win-x64;linux-x64)
|
||||
- M42ExtensionId (set in csproj)
|
||||
- M42EnableRidBuild (true for net8.0 w/ RIDs, false for netstandard)
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<!-- BasePackage under extension root -->
|
||||
<M42BasePackageAssembliesDir Condition="'$(M42BasePackageAssembliesDir)' == ''">$(MSBuildThisFileDirectory)BasePackage\Assemblies\</M42BasePackageAssembliesDir>
|
||||
|
||||
<!-- Root one level above extension root -->
|
||||
<M42RootAssembliesDir Condition="'$(M42RootAssembliesDir)' == '' AND '$(M42ExtensionId)' != ''">$(MSBuildThisFileDirectory)..\Root\InstalledPackages\Assemblies\$(M42ExtensionId)\</M42RootAssembliesDir>
|
||||
|
||||
<!-- Pattern & default RIDs -->
|
||||
<M42AssemblyPattern Condition="'$(M42AssemblyPattern)' == ''">$(MSBuildProjectName)*.*</M42AssemblyPattern>
|
||||
<M42DefaultRids Condition="'$(M42DefaultRids)' == ''">win-x64;linux-x64</M42DefaultRids>
|
||||
|
||||
<!-- Enable multi-RID builds per project; can be set to false in csproj -->
|
||||
<M42EnableRidBuild Condition="'$(M42EnableRidBuild)' == ''">true</M42EnableRidBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<!--
|
||||
M42_BuildAllRids
|
||||
|
||||
Local only: if no RID was specified AND we're not in Azure DevOps,
|
||||
build all default RIDs (M42DefaultRids) by re-invoking MSBuild
|
||||
with RuntimeIdentifier and AppendRuntimeIdentifierToOutputPath=true.
|
||||
|
||||
This prevents the outer RID-less build by setting SkipBuild=true.
|
||||
|
||||
Skipped when M42EnableRidBuild=false (e.g. netstandard projects).
|
||||
-->
|
||||
<Target Name="M42_BuildAllRids"
|
||||
BeforeTargets="Build"
|
||||
Condition="'$(RuntimeIdentifier)' == ''
|
||||
AND ( '$(TF_BUILD)' != 'True' OR '$(M42BuildAllRidsOnCI)' == 'true' )
|
||||
AND '$(M42EnableRidBuild)' == 'true'">
|
||||
|
||||
<ItemGroup>
|
||||
<_M42RidList Include="$(M42DefaultRids)" />
|
||||
</ItemGroup>
|
||||
|
||||
<MSBuild Projects="$(MSBuildProjectFullPath)"
|
||||
Targets="Restore;Build"
|
||||
Properties="RuntimeIdentifier=%(_M42RidList.Identity);Configuration=$(Configuration);AppendRuntimeIdentifierToOutputPath=true"
|
||||
BuildInParallel="true" />
|
||||
|
||||
<PropertyGroup>
|
||||
<SkipBuild>true</SkipBuild>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
|
||||
<!--
|
||||
M42_PostBuild_CopyRidless
|
||||
|
||||
For RID-less builds (RuntimeIdentifier == ''), copy top-level output files
|
||||
that match M42AssemblyPattern directly from $(TargetDir) to:
|
||||
|
||||
1) BasePackage\Assemblies\
|
||||
2) Root\InstalledPackages\Assemblies\{ExtId}\ (if configured)
|
||||
|
||||
Useful for projects that don't support RID-specific builds (e.g. netstandard),
|
||||
or when M42EnableRidBuild=false.
|
||||
-->
|
||||
<Target Name="M42_PostBuild_CopyRidless"
|
||||
AfterTargets="Build"
|
||||
Condition="'$(RuntimeIdentifier)' == ''">
|
||||
|
||||
<Message Text="M42: RID-less copy from $(TargetDir) → $(M42BasePackageAssembliesDir)" Importance="high" />
|
||||
|
||||
<ItemGroup>
|
||||
<_M42FlatRootRidless Include="$(TargetDir)$(M42AssemblyPattern)" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- BasePackage flat copy -->
|
||||
<MakeDir Directories="$(M42BasePackageAssembliesDir)"
|
||||
Condition="!Exists('$(M42BasePackageAssembliesDir)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42FlatRootRidless)"
|
||||
DestinationFolder="$(M42BasePackageAssembliesDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
Condition="Exists('$(TargetDir)')" />
|
||||
|
||||
<!-- Root flat copy (if configured) -->
|
||||
<Message Text="M42: RID-less copy to Root → $(M42RootAssembliesDir)" Importance="high"
|
||||
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||
|
||||
<MakeDir Directories="$(M42RootAssembliesDir)"
|
||||
Condition="'$(M42RootAssembliesDir)' != '' AND !Exists('$(M42RootAssembliesDir)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42FlatRootRidless)"
|
||||
DestinationFolder="$(M42RootAssembliesDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
Condition="'$(M42RootAssembliesDir)' != '' AND Exists('$(TargetDir)')" />
|
||||
|
||||
</Target>
|
||||
|
||||
|
||||
<!--
|
||||
M42_PostBuild_CopyRID
|
||||
|
||||
After each RID-specific build, copy assemblies to:
|
||||
|
||||
1) BasePackage\Assemblies\ (FLAT, from RID-less bin\...\netX\)
|
||||
2) BasePackage\Assemblies\<RID>\... (RECURSIVE, from current RID build)
|
||||
|
||||
And, if M42RootAssembliesDir is set:
|
||||
|
||||
3) Root\InstalledPackages\Assemblies\{ExtId}\ (FLAT)
|
||||
4) Root\InstalledPackages\Assemblies\{ExtId}\<RID>\ (RECURSIVE)
|
||||
-->
|
||||
<Target Name="M42_PostBuild_CopyRID"
|
||||
AfterTargets="Build"
|
||||
Condition="'$(RuntimeIdentifier)' != ''">
|
||||
|
||||
<Message Text="M42: RID=$(RuntimeIdentifier) TargetDir=$(TargetDir)" Importance="high" />
|
||||
|
||||
<!-- Parent of ...\netX\<rid>\ -->
|
||||
<PropertyGroup>
|
||||
<M42_RidlessTargetDir>$([System.IO.Path]::GetFullPath('$(TargetDir)..\'))</M42_RidlessTargetDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- 1) FLAT copy from rid-less netX to BasePackage\Assemblies -->
|
||||
<Message Text="M42: flat copy from $(M42_RidlessTargetDir) → $(M42BasePackageAssembliesDir)" Importance="high" />
|
||||
|
||||
<ItemGroup>
|
||||
<_M42FlatRoot Include="$(M42_RidlessTargetDir)$(M42AssemblyPattern)" />
|
||||
</ItemGroup>
|
||||
|
||||
<MakeDir Directories="$(M42BasePackageAssembliesDir)"
|
||||
Condition="!Exists('$(M42BasePackageAssembliesDir)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42FlatRoot)"
|
||||
DestinationFolder="$(M42BasePackageAssembliesDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
Condition="Exists('$(M42_RidlessTargetDir)')" />
|
||||
|
||||
|
||||
<!-- 1b) FLAT copy to Root if configured -->
|
||||
<Message Text="M42: flat copy to Root → $(M42RootAssembliesDir)" Importance="high"
|
||||
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||
|
||||
<MakeDir Directories="$(M42RootAssembliesDir)"
|
||||
Condition="'$(M42RootAssembliesDir)' != '' AND !Exists('$(M42RootAssembliesDir)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42FlatRoot)"
|
||||
DestinationFolder="$(M42RootAssembliesDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
Condition="'$(M42RootAssembliesDir)' != '' AND Exists('$(M42_RidlessTargetDir)')" />
|
||||
|
||||
|
||||
<!-- 2) RID copy to BasePackage\Assemblies\<RID>\... -->
|
||||
<Message Text="M42: RID copy → $(M42BasePackageAssembliesDir)$(RuntimeIdentifier)\" Importance="high" />
|
||||
|
||||
<ItemGroup>
|
||||
<_M42Rid Include="$(TargetDir)**\$(M42AssemblyPattern)" />
|
||||
</ItemGroup>
|
||||
|
||||
<MakeDir Directories="$(M42BasePackageAssembliesDir)$(RuntimeIdentifier)"
|
||||
Condition="!Exists('$(M42BasePackageAssembliesDir)$(RuntimeIdentifier)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42Rid)"
|
||||
DestinationFolder="$(M42BasePackageAssembliesDir)$(RuntimeIdentifier)\%(RecursiveDir)"
|
||||
SkipUnchangedFiles="true" />
|
||||
|
||||
|
||||
<!-- 2b) RID copy to Root\...\<RID>\... -->
|
||||
<Message Text="M42: RID copy to Root → $(M42RootAssembliesDir)$(RuntimeIdentifier)\" Importance="high"
|
||||
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||
|
||||
<MakeDir Directories="$(M42RootAssembliesDir)$(RuntimeIdentifier)"
|
||||
Condition="'$(M42RootAssembliesDir)' != '' AND !Exists('$(M42RootAssembliesDir)$(RuntimeIdentifier)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42Rid)"
|
||||
DestinationFolder="$(M42RootAssembliesDir)$(RuntimeIdentifier)\%(RecursiveDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,232 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.ProjectGenerators;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core;
|
||||
|
||||
public sealed class ExtensionScaffolder : IExtensionScaffolder
|
||||
{
|
||||
private readonly DefaultProjectGenerator _projectGenerator = new();
|
||||
|
||||
public IReadOnlyList<string> Generate(ExtensionScaffoldingOptions options)
|
||||
{
|
||||
if (options is null)
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.ExtensionPath)) throw new ArgumentException("ExtensionPath must be set.", nameof(options));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.ExtensionNamespace)) throw new ArgumentException("ExtensionNamespace must be set.", nameof(options));
|
||||
|
||||
if (options.Projects == null) throw new ArgumentException("Projects must be set.", nameof(options));
|
||||
|
||||
var result = new List<string>();
|
||||
|
||||
PrepareRootStructure(options);
|
||||
PrepareBasePackage(options);
|
||||
var solutionDir = PrepareSolutionFolder(options);
|
||||
PrepareRootArtifacts(options);
|
||||
PrepareSolutionFiles(options, solutionDir);
|
||||
|
||||
foreach (var def in options.Projects)
|
||||
{
|
||||
var csprojPath = _projectGenerator.GenerateProject(options, def);
|
||||
result.Add(csprojPath);
|
||||
}
|
||||
|
||||
GenerateSolutionFile(options, solutionDir, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void PrepareRootStructure(ExtensionScaffoldingOptions options)
|
||||
{
|
||||
Directory.CreateDirectory(options.ExtensionPath);
|
||||
}
|
||||
|
||||
private void PrepareBasePackage(ExtensionScaffoldingOptions options)
|
||||
{
|
||||
var basePackageDir = Path.Combine(options.ExtensionPath, "BasePackage");
|
||||
Directory.CreateDirectory(basePackageDir);
|
||||
|
||||
var packageJsonPath = Path.Combine(basePackageDir, "package.json");
|
||||
if (!File.Exists(packageJsonPath))
|
||||
{
|
||||
var json = GetDefaultPackageJson(options);
|
||||
File.WriteAllText(packageJsonPath, json);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates /Solutions/{ns} and returns that path (solution-level folder).
|
||||
/// </summary>
|
||||
private string PrepareSolutionFolder(ExtensionScaffoldingOptions options)
|
||||
{
|
||||
var solutionDir = Path.Combine(options.ExtensionPath, "Solutions", options.ExtensionNamespace);
|
||||
Directory.CreateDirectory(solutionDir);
|
||||
return solutionDir;
|
||||
}
|
||||
|
||||
private void PrepareRootArtifacts(ExtensionScaffoldingOptions options)
|
||||
{
|
||||
/*var azurePath = Path.Combine(options.ExtensionPath, "azure-pipelines-ci.yml");
|
||||
if (!File.Exists(azurePath))
|
||||
{
|
||||
File.WriteAllText(azurePath, Templates.AzurePipelinesYml);
|
||||
}*/
|
||||
|
||||
var azurePath = Path.Combine(options.ExtensionPath, "azure-pipelines-ci.yaml");
|
||||
if (!File.Exists(azurePath))
|
||||
{
|
||||
var repoName = new DirectoryInfo(options.ExtensionPath).Name;
|
||||
|
||||
var content = Templates.GetAzurePiplineCi();
|
||||
var replacedContent = content.Replace("{repoName}", repoName).Replace("{ns}", options.ExtensionNamespace);
|
||||
File.WriteAllText(azurePath, replacedContent);
|
||||
}
|
||||
|
||||
var gitignorePath = Path.Combine(options.ExtensionPath, ".gitignore");
|
||||
if (!File.Exists(gitignorePath))
|
||||
{
|
||||
File.WriteAllText(gitignorePath, Templates.Gitignore);
|
||||
}
|
||||
|
||||
/*var veracodePath = Path.Combine(options.ExtensionPath, "PrepareVeracodeScan.cmd");
|
||||
if (!File.Exists(veracodePath))
|
||||
{
|
||||
var content = Templates.PrepareVeracodeScanCmd.Replace("{ns}", options.ExtensionNamespace);
|
||||
File.WriteAllText(veracodePath, content);
|
||||
}*/
|
||||
|
||||
var targetsPath = Path.Combine(options.ExtensionPath, "Extension.Assemblies.targets");
|
||||
if (!File.Exists(targetsPath))
|
||||
{
|
||||
var content = Templates.GetMatrix42AssembliesTargets();
|
||||
File.WriteAllText(targetsPath, content);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Solution-level files that should live next to the .sln (e.g. BuildEvent.cmd).
|
||||
/// </summary>
|
||||
private void PrepareSolutionFiles(ExtensionScaffoldingOptions options, string solutionDir)
|
||||
{
|
||||
var buildEventPath = Path.Combine(solutionDir, "BuildEvent.cmd");
|
||||
if (!File.Exists(buildEventPath))
|
||||
{
|
||||
var content = Templates.BuildEventCmdTemplate.Replace("{ns}", options.ExtensionNamespace);
|
||||
File.WriteAllText(buildEventPath, content);
|
||||
}
|
||||
|
||||
// If later you want to actually create the .sln here (for console scenario),
|
||||
// this is the right place as well.
|
||||
}
|
||||
|
||||
private static string GetDefaultPackageJson(ExtensionScaffoldingOptions options) =>
|
||||
$@"{{
|
||||
""Id"": ""{options.ExtensionId}"",
|
||||
""Vendor"": ""Not Specified"",
|
||||
""Name"": ""{options.ExtensionNamespace}"",
|
||||
""Version"": ""1.0"",
|
||||
""Prerequisites"": {{
|
||||
""MinimalRequiredProductVersion"": ""26.1.0"",
|
||||
""DependentPackages"": []
|
||||
}},
|
||||
""SetupDirectives"": {{
|
||||
""MaintenanceMode"": false,
|
||||
""RecycleWebApplication"": false,
|
||||
""RestartM42WindowsServices"": false
|
||||
}},
|
||||
""Sandboxed"": true
|
||||
}}";
|
||||
|
||||
/// <summary>
|
||||
/// Creates {ns}.sln under solutionDir and adds all csproj files to it.
|
||||
/// </summary>
|
||||
private void GenerateSolutionFile(
|
||||
ExtensionScaffoldingOptions options,
|
||||
string solutionDir,
|
||||
IReadOnlyList<string> projectPaths)
|
||||
{
|
||||
if (projectPaths == null || projectPaths.Count == 0)
|
||||
return;
|
||||
|
||||
var solutionName = options.ExtensionNamespace;
|
||||
var slnPath = Path.Combine(solutionDir, solutionName + ".sln");
|
||||
|
||||
// Basic VS solution header
|
||||
var lines = new List<string>();
|
||||
lines.Add("Microsoft Visual Studio Solution File, Format Version 12.00");
|
||||
lines.Add("# Visual Studio Version 17");
|
||||
lines.Add("VisualStudioVersion = 17.0.31912.275");
|
||||
lines.Add("MinimumVisualStudioVersion = 10.0.40219.1");
|
||||
|
||||
// C# project type GUID
|
||||
const string csProjTypeGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
|
||||
|
||||
// Collect project GUIDs
|
||||
var projectEntries = new List<Tuple<string, string, string>>();
|
||||
// (projGuid, projName, relativePath)
|
||||
|
||||
foreach (var projPath in projectPaths)
|
||||
{
|
||||
var projName = Path.GetFileNameWithoutExtension(projPath);
|
||||
var relativePath = GetRelativePath(solutionDir, projPath);
|
||||
var projGuid = "{" + Guid.NewGuid().ToString().ToUpperInvariant() + "}";
|
||||
|
||||
projectEntries.Add(Tuple.Create(projGuid, projName, relativePath));
|
||||
|
||||
lines.Add(string.Format(
|
||||
"Project(\"{0}\") = \"{1}\", \"{2}\", \"{3}\"",
|
||||
csProjTypeGuid,
|
||||
projName,
|
||||
relativePath,
|
||||
projGuid));
|
||||
lines.Add("EndProject");
|
||||
}
|
||||
|
||||
// Global section (configs + project configs)
|
||||
lines.Add("Global");
|
||||
lines.Add("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
|
||||
lines.Add("\t\tDebug|Any CPU = Debug|Any CPU");
|
||||
lines.Add("\t\tRelease|Any CPU = Release|Any CPU");
|
||||
lines.Add("\tEndGlobalSection");
|
||||
|
||||
lines.Add("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
|
||||
foreach (var entry in projectEntries)
|
||||
{
|
||||
var guid = entry.Item1;
|
||||
lines.Add(string.Format("\t\t{0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", guid));
|
||||
lines.Add(string.Format("\t\t{0}.Debug|Any CPU.Build.0 = Debug|Any CPU", guid));
|
||||
lines.Add(string.Format("\t\t{0}.Release|Any CPU.ActiveCfg = Release|Any CPU", guid));
|
||||
lines.Add(string.Format("\t\t{0}.Release|Any CPU.Build.0 = Release|Any CPU", guid));
|
||||
}
|
||||
lines.Add("\tEndGlobalSection");
|
||||
|
||||
lines.Add("\tGlobalSection(SolutionProperties) = preSolution");
|
||||
lines.Add("\t\tHideSolutionNode = FALSE");
|
||||
lines.Add("\tEndGlobalSection");
|
||||
|
||||
lines.Add("EndGlobal");
|
||||
|
||||
File.WriteAllLines(slnPath, lines);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple helper to get relative path from one folder to a file.
|
||||
/// </summary>
|
||||
private static string GetRelativePath(string basePath, string fullPath)
|
||||
{
|
||||
var baseUri = new Uri(AppendDirectorySeparatorChar(basePath));
|
||||
var fullUri = new Uri(fullPath);
|
||||
var relative = baseUri.MakeRelativeUri(fullUri).ToString();
|
||||
|
||||
return relative.Replace('/', Path.DirectorySeparatorChar);
|
||||
}
|
||||
|
||||
private static string AppendDirectorySeparatorChar(string path)
|
||||
{
|
||||
return !path.EndsWith(Path.DirectorySeparatorChar.ToString()) ? path + Path.DirectorySeparatorChar : path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core
|
||||
{
|
||||
public sealed class ExtensionScaffoldingOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Absolute path where scaffolding should be created.
|
||||
/// Typically solution directory from VS or some folder from CLI.
|
||||
/// </summary>
|
||||
public string ExtensionPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Extension id (Guid) – used in package.json or other metadata.
|
||||
/// </summary>
|
||||
public Guid ExtensionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Root namespace, e.g. "Matrix42.MyAwesomeExtension".
|
||||
/// </summary>
|
||||
public string ExtensionNamespace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Projects to create.
|
||||
/// </summary>
|
||||
public IReadOnlyList<ProjectDefinition> Projects { get; set; } = Array.Empty<ProjectDefinition>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.Functionality
|
||||
{
|
||||
public interface IProjectFunctionalityDefinition
|
||||
{
|
||||
ProjectFunctionality Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Files to create for this functionality (relative paths, template content).
|
||||
/// </summary>
|
||||
IEnumerable<TemplateFile> GetFiles(ExtensionScaffoldingOptions options, ProjectDefinition project);
|
||||
|
||||
/// <summary>
|
||||
/// References to add to the csproj.
|
||||
/// </summary>
|
||||
IEnumerable<ProjectReferenceDefinition> GetReferences(ExtensionScaffoldingOptions options, ProjectDefinition project);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.Functionality
|
||||
{
|
||||
public sealed class WebApiFunctionalityDefinition : IProjectFunctionalityDefinition
|
||||
{
|
||||
public ProjectFunctionality Kind => ProjectFunctionality.WebApi;
|
||||
|
||||
public IEnumerable<TemplateFile> GetFiles(
|
||||
ExtensionScaffoldingOptions options,
|
||||
ProjectDefinition project)
|
||||
{
|
||||
var ns = options.ExtensionNamespace;
|
||||
|
||||
yield return new TemplateFile
|
||||
{
|
||||
RelativePath = @"Controllers\TestController.cs",
|
||||
Content = WebApi_TestControllerTemplate.Replace("{ns}", ns),
|
||||
CreateIfMissingOnly = true
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<ProjectReferenceDefinition> GetReferences(ExtensionScaffoldingOptions options, ProjectDefinition project)
|
||||
{
|
||||
yield return new ProjectReferenceDefinition
|
||||
{
|
||||
Include = "Matrix42.WebApi.Contracts",
|
||||
HintPath = @"..\..\..\..\Root\bin\Matrix42.WebApi.Contracts.dll"
|
||||
};
|
||||
|
||||
yield return new ProjectReferenceDefinition
|
||||
{
|
||||
Include = "Matrix42.Hosting.Contracts",
|
||||
HintPath = @"..\..\..\..\Root\bin\Matrix42.Hosting.Contracts.dll"
|
||||
};
|
||||
}
|
||||
|
||||
private const string WebApi_TestControllerTemplate =
|
||||
@"
|
||||
using Matrix42.WebApi.Contracts;
|
||||
using Matrix42.Hosting.Contracts;
|
||||
|
||||
namespace {ns}.Services
|
||||
{
|
||||
[RoutePrefix(""api/test"")]
|
||||
public class TestController : ApiController
|
||||
{
|
||||
private readonly IDependencyResolver _resolver;
|
||||
|
||||
public TestController(IDependencyResolver resolver)
|
||||
{
|
||||
_resolver = resolver;
|
||||
}
|
||||
|
||||
[HttpPost, Route(""test"")]
|
||||
public string TestMethod()
|
||||
{
|
||||
// TODO: implement your test method logic
|
||||
return ""OK"";
|
||||
}
|
||||
}
|
||||
}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core;
|
||||
|
||||
public interface IExtensionScaffolder
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates all files/folders according to options and returns the list of generated csproj paths.
|
||||
/// </summary>
|
||||
IReadOnlyList<string> Generate(ExtensionScaffoldingOptions options);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>11.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Extension.Assemblies.targets" />
|
||||
<EmbeddedResource Include="azure-pipelines-ci.yaml" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
|
||||
public class ProjectDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// E.g. "Services", "BizLogic", etc.
|
||||
/// If empty, project name will be equal to ExtensionNamespace.
|
||||
/// </summary>
|
||||
public string Prefix { get; set; } = string.Empty;
|
||||
|
||||
public RuntimeTargets Runtimes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Combination of functionality flags: WebApi, Engine, Behavior, Connector, Custom.
|
||||
/// </summary>
|
||||
public ProjectFunctionality Functionality { get; set; } = ProjectFunctionality.None;
|
||||
|
||||
public string Display => $"Prefix: {Prefix} - Runtimes: {Runtimes} - Functionality: {Functionality}";
|
||||
|
||||
public string GetProjectName(string extensionNamespace)
|
||||
{
|
||||
var pfx = Prefix?.Trim();
|
||||
return string.IsNullOrWhiteSpace(pfx)
|
||||
? extensionNamespace
|
||||
: $"{extensionNamespace}.{pfx}";
|
||||
}
|
||||
|
||||
public string GetNamespace(string extensionNamespace) => GetProjectName(extensionNamespace);
|
||||
|
||||
public bool DoesSupportAllRuntimes() => Runtimes.HasFlag(RuntimeTargets.All);
|
||||
|
||||
public string GetRuntimeIdentifiers()
|
||||
{
|
||||
if (DoesSupportAllRuntimes())
|
||||
{
|
||||
return "netstandard2.0";
|
||||
}
|
||||
|
||||
var list = new List<string>();
|
||||
if (Runtimes.HasFlag(RuntimeTargets.Win) || Runtimes.HasFlag(RuntimeTargets.WinCore))
|
||||
{
|
||||
list.Add("win-x64");
|
||||
}
|
||||
|
||||
if (Runtimes.HasFlag(RuntimeTargets.LinuxCore))
|
||||
{
|
||||
list.Add("linux-x64");
|
||||
}
|
||||
|
||||
return string.Join(";", list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
|
||||
[Flags]
|
||||
public enum ProjectFunctionality
|
||||
{
|
||||
None = 0,
|
||||
WebApi = 1,
|
||||
Engine = 2,
|
||||
Behavior = 4,
|
||||
Connector = 8,
|
||||
Custom = 16
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum RuntimeTargets
|
||||
{
|
||||
Win = 1,
|
||||
WinCore = 2,
|
||||
LinuxCore = 4,
|
||||
All = 8
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.Project
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a single extra reference to put in the csproj.
|
||||
/// </summary>
|
||||
public sealed class ProjectReferenceDefinition
|
||||
{
|
||||
public string Include { get; set; }
|
||||
public string HintPath { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.Functionality;
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.ProjectGenerators
|
||||
{
|
||||
internal class DefaultProjectGenerator
|
||||
{
|
||||
private readonly IReadOnlyList<IProjectFunctionalityDefinition> _functionalityDefinitions;
|
||||
|
||||
public DefaultProjectGenerator()
|
||||
{
|
||||
_functionalityDefinitions = new IProjectFunctionalityDefinition[]
|
||||
{
|
||||
new WebApiFunctionalityDefinition(),
|
||||
// new EngineFunctionalityDefinition(),
|
||||
// new BehaviorFunctionalityDefinition(),
|
||||
// new ConnectorFunctionalityDefinition(),
|
||||
// new CustomFunctionalityDefinition(),
|
||||
};
|
||||
}
|
||||
|
||||
public string GenerateProject(ExtensionScaffoldingOptions options, ProjectDefinition def)
|
||||
{
|
||||
var ns = options.ExtensionNamespace;
|
||||
var projectName = def.GetProjectName(ns); // e.g. Matrix42.MyExt.Services
|
||||
|
||||
var solutionDir = Path.Combine(options.ExtensionPath, "Solutions", options.ExtensionNamespace);
|
||||
Directory.CreateDirectory(solutionDir);
|
||||
|
||||
var projectDir = Path.Combine(solutionDir, projectName);
|
||||
Directory.CreateDirectory(projectDir);
|
||||
|
||||
var csprojPath = Path.Combine(projectDir, $"{projectName}.csproj");
|
||||
|
||||
GenerateCsproj(csprojPath, def, options, projectName, ns, CollectFunctionalityReferences(options, def));
|
||||
GenerateHostFile(projectDir, projectName);
|
||||
GenerateFiles(projectDir, CollectFunctionalityFiles(options, def));
|
||||
|
||||
return csprojPath;
|
||||
}
|
||||
|
||||
#region Csproj / Host
|
||||
|
||||
protected virtual void GenerateCsproj(
|
||||
string csprojPath,
|
||||
ProjectDefinition def,
|
||||
ExtensionScaffoldingOptions options,
|
||||
string projectName,
|
||||
string rootNamespace,
|
||||
IReadOnlyList<ProjectReferenceDefinition> extraReferences)
|
||||
{
|
||||
var allRuntimes = def.DoesSupportAllRuntimes();
|
||||
|
||||
var tfm = allRuntimes ? def.GetRuntimeIdentifiers() : "net8.0"; // Todo: dynamic based on runtimes
|
||||
var runtimeIds = def.GetRuntimeIdentifiers();
|
||||
|
||||
var anyRids = !allRuntimes && !string.IsNullOrWhiteSpace(runtimeIds);
|
||||
var ridBlock = anyRids ? $"<RuntimeIdentifiers>{runtimeIds}</RuntimeIdentifiers>{Environment.NewLine}" : string.Empty;
|
||||
|
||||
var referencesXml = BuildReferencesXml(extraReferences);
|
||||
|
||||
var content =
|
||||
$@"<Project Sdk=""Microsoft.NET.Sdk"">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>{tfm}</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>{rootNamespace}</RootNamespace>
|
||||
{ridBlock}
|
||||
<AppendRuntimeIdentifierToOutputPath>true</AppendRuntimeIdentifierToOutputPath>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<LangVersion>latestmajor</LangVersion>
|
||||
<BasePackageAssembliesDir>$(MSBuildProjectDirectory)\..\..\..\BasePackage\Assemblies\</BasePackageAssembliesDir>
|
||||
</PropertyGroup>
|
||||
|
||||
{referencesXml}
|
||||
|
||||
<PropertyGroup>
|
||||
<M42ExtensionId>{options.ExtensionId}</M42ExtensionId>
|
||||
<M42AssemblyPattern>$(MSBuildProjectName)*.*</M42AssemblyPattern>
|
||||
<M42EnableRidBuild>{anyRids.ToString().ToLowerInvariant()}</M42EnableRidBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project=""..\..\..\Extension.Assemblies.targets"" Condition=""Exists('..\..\..\Extension.Assemblies.targets')"" />
|
||||
</Project>
|
||||
";
|
||||
|
||||
File.WriteAllText(csprojPath, content);
|
||||
}
|
||||
|
||||
protected virtual void GenerateHostFile(string projectDir, string projectName)
|
||||
{
|
||||
var hostFileName = $"{projectName}.dll.host";
|
||||
var hostPath = Path.Combine(projectDir, hostFileName);
|
||||
|
||||
if (!File.Exists(hostPath))
|
||||
{
|
||||
File.WriteAllText(hostPath, Templates.DefaultHostFileContent);
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildReferencesXml(IEnumerable<ProjectReferenceDefinition> refs)
|
||||
{
|
||||
var list = refs?.ToList() ?? new List<ProjectReferenceDefinition>();
|
||||
if (list.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(" <ItemGroup>");
|
||||
|
||||
foreach (var r in list)
|
||||
{
|
||||
sb.AppendLine($@" <Reference Include=""{r.Include}"">");
|
||||
if (!string.IsNullOrWhiteSpace(r.HintPath))
|
||||
{
|
||||
sb.AppendLine($@" <HintPath>{r.HintPath}</HintPath>");
|
||||
}
|
||||
sb.AppendLine(" </Reference>");
|
||||
}
|
||||
|
||||
sb.AppendLine(" </ItemGroup>");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Functionality integration (files + references)
|
||||
|
||||
/// <summary>
|
||||
/// Collects files to generate from all enabled functionalities.
|
||||
/// </summary>
|
||||
protected virtual IReadOnlyList<TemplateFile> CollectFunctionalityFiles(
|
||||
ExtensionScaffoldingOptions options, ProjectDefinition def)
|
||||
{
|
||||
var result = new List<TemplateFile>();
|
||||
var flags = def.Functionality;
|
||||
|
||||
foreach (var defn in _functionalityDefinitions)
|
||||
{
|
||||
if (!flags.HasFlag(defn.Kind))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.AddRange(defn.GetFiles(options, def));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collects references to add to csproj from all enabled functionalities.
|
||||
/// </summary>
|
||||
protected virtual IReadOnlyList<ProjectReferenceDefinition> CollectFunctionalityReferences(
|
||||
ExtensionScaffoldingOptions options, ProjectDefinition def)
|
||||
{
|
||||
var result = new List<ProjectReferenceDefinition>();
|
||||
var flags = def.Functionality;
|
||||
|
||||
foreach (var defn in _functionalityDefinitions)
|
||||
{
|
||||
if (!flags.HasFlag(defn.Kind))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.AddRange(defn.GetReferences(options, def));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected virtual void GenerateFiles(string projectDir, IReadOnlyList<TemplateFile> files)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
var targetPath = Path.Combine(projectDir, file.RelativePath);
|
||||
var targetDir = Path.GetDirectoryName(targetPath);
|
||||
if (!string.IsNullOrEmpty(targetDir))
|
||||
{
|
||||
Directory.CreateDirectory(targetDir);
|
||||
}
|
||||
|
||||
if (file.CreateIfMissingOnly && File.Exists(targetPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
File.WriteAllText(targetPath, file.Content);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.ProjectGenerators;
|
||||
|
||||
internal interface IProjectGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates the project and returns the path to the created .csproj file.
|
||||
/// </summary>
|
||||
string GenerateProject(ExtensionScaffoldingOptions options, ProjectDefinition def);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Matrix42.Extensions.Scaffolder.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a single file to generate from a template.
|
||||
/// </summary>
|
||||
public sealed class TemplateFile
|
||||
{
|
||||
/// <summary>
|
||||
/// Path relative to project folder (for project files)
|
||||
/// or ExtensionPath (for root-level files).
|
||||
/// Example: "Controllers\\TestController.cs" or "BuildEvent.cmd".
|
||||
/// </summary>
|
||||
public string RelativePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Template content (with tokens like {ns}, {projectName} etc.).
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, file is only created if it doesn't exist.
|
||||
/// If false, it will be overwritten.
|
||||
/// </summary>
|
||||
public bool CreateIfMissingOnly { get; set; } = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core
|
||||
{
|
||||
internal static class Templates
|
||||
{
|
||||
public const string Gitignore = @"
|
||||
.idea/
|
||||
.vs/
|
||||
.vscode/
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
package-lock.json
|
||||
workspace.json
|
||||
|
||||
.vs/
|
||||
.libs/
|
||||
.build/
|
||||
|
||||
bin/
|
||||
obj/
|
||||
|
||||
*.user
|
||||
|
||||
/**/AssemblyInfoProduct.cs
|
||||
/**/_Resharper.Caches
|
||||
/Solutions/*.sln.DotSettings.user
|
||||
/Solutions/**/*.csproj.user
|
||||
/Solutions/**/packages/*.*
|
||||
/Solutions/**/**/AssemblyInfoProduct.cs
|
||||
/Solutions/TestResult/*.*
|
||||
|
||||
BasePackage/Assemblies/
|
||||
";
|
||||
|
||||
public const string PrepareVeracodeScanCmd = @"set arch=""C:\Program Files\7-Zip\7z.exe""
|
||||
echo [*] Building backend archive...
|
||||
%arch% a -tzip -mx5 -x!*.config %Build_ArtifactStagingDirectory%\{ns}.zip %BaseDir%\Solutions\{ns}\.build\*.*
|
||||
";
|
||||
|
||||
public const string DefaultHostFileContent =
|
||||
@"<?xml version=""1.0"" encoding=""utf-8"" ?>
|
||||
<host xmlns=""urn:m42/host.config"">
|
||||
<modules></modules>
|
||||
<sections></sections>
|
||||
</host>
|
||||
";
|
||||
|
||||
public const string BuildEventCmdTemplate =
|
||||
@"call %~dps0..\..\TeamBuildEvent.cmd %1 %2 %3 ""/Solutions/{ns}""";
|
||||
|
||||
internal static string GetMatrix42AssembliesTargets()
|
||||
{
|
||||
var asm = typeof(Templates).Assembly;
|
||||
const string resourceName = "Matrix42.Extensions.Scaffolder.Core.Extension.Assemblies.targets";
|
||||
|
||||
using (var stream = asm.GetManifestResourceStream(resourceName))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new FileNotFoundException($"Embedded resource '{resourceName}' not found in assembly '{asm.FullName}'.");
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetAzurePiplineCi()
|
||||
{
|
||||
var asm = typeof(Templates).Assembly;
|
||||
const string resourceName = "Matrix42.Extensions.Scaffolder.Core.azure-pipelines-ci.yaml";
|
||||
|
||||
using (var stream = asm.GetManifestResourceStream(resourceName))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new FileNotFoundException($"Embedded resource '{resourceName}' not found in assembly '{asm.FullName}'.");
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
# azure-pipelines.yml
|
||||
pr: none
|
||||
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- release_26_1_0
|
||||
paths:
|
||||
include:
|
||||
- 'Solutions/**'
|
||||
|
||||
parameters:
|
||||
- name: BaseDir
|
||||
type: string
|
||||
default: $(Build.SourcesDirectory)
|
||||
|
||||
- name: SuiteRarShare
|
||||
type: string
|
||||
default: '\\m42-sto-ffm01.matrix42.de\ServiceStore\Builds\TitanLinux Continuous'
|
||||
|
||||
- name: RepoName
|
||||
type: string
|
||||
default: '{repoName}'
|
||||
|
||||
- name: SolutionName
|
||||
type: string
|
||||
default: '{ns}'
|
||||
|
||||
variables:
|
||||
- name: BaseDir
|
||||
value: ${{ parameters.BaseDir }}
|
||||
|
||||
- name: ExtensionTarget
|
||||
value: ${{ parameters.BaseDir }}/${{ parameters.RepoName }}
|
||||
|
||||
- name: SolutionDir
|
||||
value: $(ExtensionTarget)/Solutions/{ns}
|
||||
|
||||
- name: SolutionPath
|
||||
value: $(SolutionDir)/{ns}.sln
|
||||
|
||||
# Tests
|
||||
- name: TestsDir
|
||||
value: $(SolutionDir)
|
||||
- name: TestProject
|
||||
value: '{ns}.Tests/{ns}.Tests.csproj'
|
||||
|
||||
stages:
|
||||
- stage: Build
|
||||
displayName: 'Build ${{ parameters.RepoName }}'
|
||||
jobs:
|
||||
- job: Build_Backend
|
||||
displayName: 'Build, Test, Package'
|
||||
pool:
|
||||
name: M42BPM
|
||||
demands:
|
||||
- DotNetFramework
|
||||
- vstest
|
||||
|
||||
steps:
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy extension $(ExtensionTarget) source files'
|
||||
inputs:
|
||||
SourceFolder: '${{ parameters.BaseDir }}'
|
||||
Contents: '**'
|
||||
TargetFolder: '$(ExtensionTarget)'
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy suite.rar'
|
||||
inputs:
|
||||
SourceFolder: '${{ parameters.SuiteRarShare }}'
|
||||
Contents: 'suite.rar'
|
||||
TargetFolder: '${{ parameters.BaseDir }}'
|
||||
OverWrite: true
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: 'Extract suite.rar'
|
||||
inputs:
|
||||
archiveFilePatterns: '${{ parameters.BaseDir }}/suite.rar'
|
||||
destinationFolder: '${{ parameters.BaseDir }}'
|
||||
cleanDestinationFolder: false
|
||||
overwriteExistingFiles: true
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Restore $(ExtensionTarget) solution'
|
||||
inputs:
|
||||
command: 'restore'
|
||||
projects: '$(SolutionPath)'
|
||||
|
||||
# Optional: override default RIDs globally if needed: -p:M42DefaultRids=win-x64;linux-x64
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Build {ns} solution'
|
||||
inputs:
|
||||
command: 'build'
|
||||
projects: '$(SolutionPath)'
|
||||
arguments: >
|
||||
-c Release
|
||||
--no-restore
|
||||
-p:SolutionDir=$(SolutionDir)\
|
||||
-p:M42BuildAllRidsOnCI=true
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Test (net8.0)'
|
||||
inputs:
|
||||
command: 'test'
|
||||
projects: '$(TestsDir)/$(TestProject)'
|
||||
arguments: '-c Release -f net8.0 --no-build'
|
||||
|
||||
- task: ArchiveFiles@2
|
||||
displayName: 'Zip $(ExtensionTarget) BasePackage'
|
||||
inputs:
|
||||
rootFolderOrFile: '$(ExtensionTarget)/BasePackage'
|
||||
includeRootFolder: false
|
||||
archiveType: 'zip'
|
||||
sevenZipCompression: 'normal'
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/${{ parameters.RepoName }}_1.0.zip'
|
||||
replaceExistingArchive: true
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Publish ${{ parameters.RepoName }}_1.0.zip'
|
||||
inputs:
|
||||
targetPath: '$(Build.ArtifactStagingDirectory)/${{ parameters.RepoName }}_1.0.zip'
|
||||
artifact: '${{ parameters.RepoName }}'
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion>17.0</MinimumVisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<ProjectGuid>{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Matrix42.Extensions.Scaffolder.Vsix</RootNamespace>
|
||||
<AssemblyName>Matrix42.Extensions.Scaffolder.Vsix</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<GeneratePkgDefFile>true</GeneratePkgDefFile>
|
||||
<UseCodebase>true</UseCodebase>
|
||||
<IncludeAssemblyInVSIXContainer>true</IncludeAssemblyInVSIXContainer>
|
||||
<IncludeDebugSymbolsInVSIXContainer>false</IncludeDebugSymbolsInVSIXContainer>
|
||||
<IncludeDebugSymbolsInLocalVSIXDeployment>false</IncludeDebugSymbolsInLocalVSIXDeployment>
|
||||
<CopyBuildOutputToOutputDirectory>true</CopyBuildOutputToOutputDirectory>
|
||||
<CopyOutputSymbolsToOutputDirectory>true</CopyOutputSymbolsToOutputDirectory>
|
||||
<StartAction>Program</StartAction>
|
||||
<StartProgram Condition="'$(DevEnvDir)' != ''">$(DevEnvDir)devenv.exe</StartProgram>
|
||||
<StartArguments>/rootsuffix Exp</StartArguments>
|
||||
<GeneratePkgDefFile>false</GeneratePkgDefFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Wizard\ExtensionProjectsWizard.cs" />
|
||||
<Compile Include="Wizard\ProjectDefinition.cs" />
|
||||
<Compile Include="Wizard\RuntimeTargets.cs" />
|
||||
<Compile Include="Wizard\WizardForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Wizard\WizardForm.Designer.cs">
|
||||
<DependentUpon>WizardForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ProjectTemplates\Directory.Build.props.template" />
|
||||
<None Include="ProjectTemplates\Placeholder.csproj" />
|
||||
<None Include="source.extension.vsixmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.SDK" Version="17.0.32112.339" ExcludeAssets="runtime" NoWarn="NU1604" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.TemplateWizardInterface">
|
||||
<Version>17.10.40170</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="17.14.2096" NoWarn="NU1604" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="ProjectTemplates\ExtensionSolution.vstemplate" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36310.24 d17.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Vsix", "Matrix42.Extensions.Scaffolder.Vsix.csproj", "{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|arm64 = Debug|arm64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|arm64 = Release|arm64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|arm64.ActiveCfg = Debug|arm64
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|arm64.Build.0 = Debug|arm64
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|x86.Build.0 = Debug|x86
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|arm64.ActiveCfg = Release|arm64
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|arm64.Build.0 = Release|arm64
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|x86.ActiveCfg = Release|x86
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {ECBF8D8B-3FBE-4CDA-BE52-C37D76054B09}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,21 @@
|
||||
<VSTemplate Version="3.0.0" Type="Project">
|
||||
<TemplateData>
|
||||
<Name>Matrix42 Extension Solution</Name>
|
||||
<Description>Create a new Matrix42 extension solution (WebApi / Contracts / BizLogic / Custom) using Matrix42.Extensions.SDK.</Description>
|
||||
<ProjectType>CSharp</ProjectType>
|
||||
<SortOrder>1000</SortOrder>
|
||||
<DefaultName>Matrix42.Extension</DefaultName>
|
||||
<CreateNewFolder>true</CreateNewFolder>
|
||||
<ProvideDefaultName>true</ProvideDefaultName>
|
||||
<LocationField>Enabled</LocationField>
|
||||
</TemplateData>
|
||||
|
||||
<TemplateContent>
|
||||
<Project File="Placeholder.csproj" ReplaceParameters="true" TargetFileName="$safeprojectname$.csproj" />
|
||||
</TemplateContent>
|
||||
|
||||
<WizardExtension>
|
||||
<Assembly>Matrix42.Extensions.Scaffolder.Vsix, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</Assembly>
|
||||
<FullClassName>Matrix42.Extensions.Scaffolder.Wizard.ExtensionProjectsWizard</FullClassName>
|
||||
</WizardExtension>
|
||||
</VSTemplate>
|
||||
@@ -0,0 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Matrix42.Extensions.Scaffolder.Vsix")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Matrix42.Extensions.Scaffolder.Vsix")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using EnvDTE;
|
||||
using EnvDTE80;
|
||||
using Microsoft.VisualStudio.TemplateWizard;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||
{
|
||||
public class ExtensionProjectsWizard : IWizard
|
||||
{
|
||||
private DTE2 _dte;
|
||||
private Project _placeholderProject;
|
||||
private string _extensionNamespace = string.Empty;
|
||||
private List<ProjectDefinition> _projects = new List<ProjectDefinition>();
|
||||
private string _solutionDirectory = string.Empty;
|
||||
|
||||
public void RunStarted(
|
||||
object automationObject,
|
||||
Dictionary<string, string> replacementsDictionary,
|
||||
WizardRunKind runKind,
|
||||
object[] customParams)
|
||||
{
|
||||
_dte = automationObject as DTE2
|
||||
?? throw new InvalidOperationException("DTE2 not available.");
|
||||
|
||||
using (var form = new WizardForm())
|
||||
{
|
||||
var result = form.ShowDialog();
|
||||
if (result != System.Windows.Forms.DialogResult.OK)
|
||||
throw new WizardBackoutException();
|
||||
|
||||
_extensionNamespace = form.ExtensionNamespace;
|
||||
_projects = new List<ProjectDefinition>(form.Projects);
|
||||
}
|
||||
}
|
||||
|
||||
// 🔹 This is the method that was missing
|
||||
public void BeforeOpeningFile(ProjectItem projectItem)
|
||||
{
|
||||
// We don't need to do anything before a file is opened.
|
||||
// Leave empty on purpose.
|
||||
}
|
||||
|
||||
public void ProjectFinishedGenerating(Project project)
|
||||
{
|
||||
_placeholderProject = project;
|
||||
}
|
||||
|
||||
public void ProjectItemFinishedGenerating(ProjectItem projectItem)
|
||||
{
|
||||
}
|
||||
|
||||
public void RunFinished()
|
||||
{
|
||||
var solution = _dte.Solution;
|
||||
_solutionDirectory = Path.GetDirectoryName(solution.FullName);
|
||||
|
||||
if (string.IsNullOrEmpty(_solutionDirectory))
|
||||
return;
|
||||
|
||||
// Remove placeholder project from solution and disk
|
||||
if (_placeholderProject != null)
|
||||
{
|
||||
var placeholderPath = _placeholderProject.FullName;
|
||||
solution.Remove(_placeholderProject);
|
||||
TryDeleteDirectorySafe(Path.GetDirectoryName(placeholderPath));
|
||||
}
|
||||
|
||||
// Drop Directory.Build.props
|
||||
var propsTemplatePath = Path.Combine(
|
||||
GetExtensionInstallPath(),
|
||||
"ProjectTemplates",
|
||||
"Directory.Build.props.template");
|
||||
|
||||
if (File.Exists(propsTemplatePath))
|
||||
{
|
||||
var destProps = Path.Combine(_solutionDirectory, "Directory.Build.props");
|
||||
if (!File.Exists(destProps))
|
||||
File.Copy(propsTemplatePath, destProps, overwrite: false);
|
||||
}
|
||||
|
||||
foreach (var proj in _projects)
|
||||
{
|
||||
CreateProjectFromDefinition(solution, proj);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShouldAddProjectItem(string filePath) => true;
|
||||
|
||||
private void CreateProjectFromDefinition(Solution solution, ProjectDefinition def)
|
||||
{
|
||||
var projectName = def.GetProjectName(_extensionNamespace);
|
||||
var projectNamespace = def.GetNamespace(_extensionNamespace);
|
||||
var projectDir = Path.Combine(_solutionDirectory, projectName);
|
||||
|
||||
Directory.CreateDirectory(projectDir);
|
||||
|
||||
var csprojPath = Path.Combine(projectDir, projectName + ".csproj");
|
||||
var runtimeIds = def.GetRuntimeIdentifiers();
|
||||
var tfm = "net8.0"; // default target framework
|
||||
|
||||
var csprojContent = GenerateCsproj(def.Type, tfm, runtimeIds, projectNamespace);
|
||||
File.WriteAllText(csprojPath, csprojContent);
|
||||
|
||||
var codeFilePath = Path.Combine(
|
||||
projectDir,
|
||||
def.Type == ProjectType.WebApi ? "Program.cs" : "Class1.cs");
|
||||
|
||||
var codeContent = GenerateCodeFile(def.Type, projectNamespace);
|
||||
File.WriteAllText(codeFilePath, codeContent);
|
||||
|
||||
solution.AddFromFile(csprojPath);
|
||||
}
|
||||
|
||||
private string GenerateCsproj(
|
||||
ProjectType type,
|
||||
string tfm,
|
||||
string runtimeIds,
|
||||
string rootNamespace)
|
||||
{
|
||||
var outputType = type == ProjectType.WebApi ? "Exe" : "Library";
|
||||
var sdk = type == ProjectType.WebApi ? "Microsoft.NET.Sdk.Web" : "Microsoft.NET.Sdk";
|
||||
|
||||
var ridBlock = string.IsNullOrWhiteSpace(runtimeIds)
|
||||
? string.Empty
|
||||
: $" <RuntimeIdentifiers>{runtimeIds}</RuntimeIdentifiers>{Environment.NewLine}";
|
||||
|
||||
return
|
||||
$@"<Project Sdk=""{sdk}"">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>{tfm}</TargetFramework>
|
||||
<OutputType>{outputType}</OutputType>
|
||||
<RootNamespace>{rootNamespace}</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
{ridBlock} </PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include=""Matrix42.Extensions.SDK"" Version=""1.0.0"" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
";
|
||||
}
|
||||
|
||||
private string GenerateCodeFile(ProjectType type, string ns)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ProjectType.WebApi:
|
||||
return
|
||||
$@"using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Matrix42.Extensions.SDK;
|
||||
|
||||
namespace {ns}
|
||||
{{
|
||||
public class Program
|
||||
{{
|
||||
public static void Main(string[] args)
|
||||
{{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// TODO: configure Matrix42.Extensions.SDK services
|
||||
|
||||
var app = builder.Build();
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
}}
|
||||
}}
|
||||
}}";
|
||||
case ProjectType.Contracts:
|
||||
return
|
||||
$@"namespace {ns}
|
||||
{{
|
||||
// Place your contracts (DTOs, interfaces) here
|
||||
public class SampleContract
|
||||
{{
|
||||
public string Id {{ get; set; }} = string.Empty;
|
||||
}}
|
||||
}}";
|
||||
case ProjectType.BizLogic:
|
||||
return
|
||||
$@"using Matrix42.Extensions.SDK;
|
||||
|
||||
namespace {ns}
|
||||
{{
|
||||
// Place your business logic services here
|
||||
public class SampleService
|
||||
{{
|
||||
public string SayHello() => ""Hello from {ns}"";
|
||||
}}
|
||||
}}";
|
||||
case ProjectType.Custom:
|
||||
default:
|
||||
return
|
||||
$@"namespace {ns}
|
||||
{{
|
||||
// Custom project for your extension
|
||||
public class CustomEntry
|
||||
{{
|
||||
public string Name {{ get; set; }} = ""Custom"";
|
||||
}}
|
||||
}}";
|
||||
}
|
||||
}
|
||||
|
||||
private string GetExtensionInstallPath()
|
||||
{
|
||||
var asmPath = typeof(ExtensionProjectsWizard).Assembly.Location;
|
||||
return Path.GetDirectoryName(asmPath);
|
||||
}
|
||||
|
||||
private void TryDeleteDirectorySafe(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path))
|
||||
Directory.Delete(path, recursive: true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||
{
|
||||
public enum ProjectType
|
||||
{
|
||||
WebApi,
|
||||
Contracts,
|
||||
BizLogic,
|
||||
Custom
|
||||
}
|
||||
|
||||
public class ProjectDefinition
|
||||
{
|
||||
public ProjectType Type { get; set; }
|
||||
public string Prefix { get; set; } = string.Empty; // custom for Custom type, otherwise derived
|
||||
public RuntimeTargets Runtimes { get; set; }
|
||||
|
||||
public string EffectivePrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Type == ProjectType.Custom)
|
||||
return Prefix;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ProjectType.WebApi:
|
||||
return string.IsNullOrWhiteSpace(Prefix) ? "Services" : Prefix;
|
||||
case ProjectType.Contracts:
|
||||
return string.IsNullOrWhiteSpace(Prefix) ? "Contracts" : Prefix;
|
||||
case ProjectType.BizLogic:
|
||||
return string.IsNullOrWhiteSpace(Prefix) ? "BizLogic" : Prefix;
|
||||
default:
|
||||
return Prefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Display => $"{Type} - Prefix: {EffectivePrefix} - Runtimes: {Runtimes}";
|
||||
|
||||
public string GetProjectName(string extensionNamespace)
|
||||
{
|
||||
var pfx = EffectivePrefix?.Trim();
|
||||
return string.IsNullOrWhiteSpace(pfx)
|
||||
? extensionNamespace
|
||||
: $"{extensionNamespace}.{pfx}";
|
||||
}
|
||||
|
||||
public string GetNamespace(string extensionNamespace) => GetProjectName(extensionNamespace);
|
||||
|
||||
public string GetRuntimeIdentifiers()
|
||||
{
|
||||
if (Runtimes.HasFlag(RuntimeTargets.All))
|
||||
return "win-x64;linux-x64";
|
||||
|
||||
var list = new List<string>();
|
||||
if (Runtimes.HasFlag(RuntimeTargets.Win) || Runtimes.HasFlag(RuntimeTargets.WinCore))
|
||||
list.Add("win-x64");
|
||||
if (Runtimes.HasFlag(RuntimeTargets.LinuxCore))
|
||||
list.Add("linux-x64");
|
||||
|
||||
return string.Join(";", list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||
{
|
||||
[System.Flags]
|
||||
public enum RuntimeTargets
|
||||
{
|
||||
None = 0,
|
||||
Win = 1,
|
||||
WinCore = 2,
|
||||
LinuxCore = 4,
|
||||
All = 8
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||
{
|
||||
partial class WizardForm
|
||||
{
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
private System.Windows.Forms.Label lblTitle;
|
||||
private System.Windows.Forms.Label lblExtensionNamespace;
|
||||
private System.Windows.Forms.TextBox txtExtensionNamespace;
|
||||
private System.Windows.Forms.Label lblHint;
|
||||
private System.Windows.Forms.Label lblAddProjects;
|
||||
private System.Windows.Forms.Label lblProjectType;
|
||||
private System.Windows.Forms.ComboBox cboProjectType;
|
||||
private System.Windows.Forms.Label lblProjectPrefix;
|
||||
private System.Windows.Forms.TextBox txtProjectPrefix;
|
||||
private System.Windows.Forms.Label lblRuntimes;
|
||||
private System.Windows.Forms.CheckedListBox clbRuntimes;
|
||||
private System.Windows.Forms.Button btnAddProject;
|
||||
private System.Windows.Forms.ListBox lstProjects;
|
||||
private System.Windows.Forms.Button btnRemoveSelected;
|
||||
private System.Windows.Forms.Button btnOK;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
components.Dispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.lblTitle = new System.Windows.Forms.Label();
|
||||
this.lblExtensionNamespace = new System.Windows.Forms.Label();
|
||||
this.txtExtensionNamespace = new System.Windows.Forms.TextBox();
|
||||
this.lblHint = new System.Windows.Forms.Label();
|
||||
this.lblAddProjects = new System.Windows.Forms.Label();
|
||||
this.lblProjectType = new System.Windows.Forms.Label();
|
||||
this.cboProjectType = new System.Windows.Forms.ComboBox();
|
||||
this.lblProjectPrefix = new System.Windows.Forms.Label();
|
||||
this.txtProjectPrefix = new System.Windows.Forms.TextBox();
|
||||
this.lblRuntimes = new System.Windows.Forms.Label();
|
||||
this.clbRuntimes = new System.Windows.Forms.CheckedListBox();
|
||||
this.btnAddProject = new System.Windows.Forms.Button();
|
||||
this.lstProjects = new System.Windows.Forms.ListBox();
|
||||
this.btnRemoveSelected = new System.Windows.Forms.Button();
|
||||
this.btnOK = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// lblTitle
|
||||
//
|
||||
this.lblTitle.AutoSize = true;
|
||||
this.lblTitle.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
|
||||
this.lblTitle.Location = new System.Drawing.Point(12, 9);
|
||||
this.lblTitle.Name = "lblTitle";
|
||||
this.lblTitle.Size = new System.Drawing.Size(120, 20);
|
||||
this.lblTitle.TabIndex = 0;
|
||||
this.lblTitle.Text = "Projects Wizard";
|
||||
//
|
||||
// lblExtensionNamespace
|
||||
//
|
||||
this.lblExtensionNamespace.AutoSize = true;
|
||||
this.lblExtensionNamespace.Location = new System.Drawing.Point(13, 44);
|
||||
this.lblExtensionNamespace.Name = "lblExtensionNamespace";
|
||||
this.lblExtensionNamespace.Size = new System.Drawing.Size(113, 15);
|
||||
this.lblExtensionNamespace.TabIndex = 1;
|
||||
this.lblExtensionNamespace.Text = "Extension Namespace";
|
||||
//
|
||||
// txtExtensionNamespace
|
||||
//
|
||||
this.txtExtensionNamespace.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.txtExtensionNamespace.Location = new System.Drawing.Point(16, 62);
|
||||
this.txtExtensionNamespace.Name = "txtExtensionNamespace";
|
||||
this.txtExtensionNamespace.Size = new System.Drawing.Size(444, 23);
|
||||
this.txtExtensionNamespace.TabIndex = 2;
|
||||
//
|
||||
// lblHint
|
||||
//
|
||||
this.lblHint.AutoSize = true;
|
||||
this.lblHint.Location = new System.Drawing.Point(466, 65);
|
||||
this.lblHint.Name = "lblHint";
|
||||
this.lblHint.Size = new System.Drawing.Size(121, 15);
|
||||
this.lblHint.TabIndex = 3;
|
||||
this.lblHint.Text = "aka Matrix42.MyExtension";
|
||||
//
|
||||
// lblAddProjects
|
||||
//
|
||||
this.lblAddProjects.AutoSize = true;
|
||||
this.lblAddProjects.Location = new System.Drawing.Point(13, 103);
|
||||
this.lblAddProjects.Name = "lblAddProjects";
|
||||
this.lblAddProjects.Size = new System.Drawing.Size(71, 15);
|
||||
this.lblAddProjects.TabIndex = 4;
|
||||
this.lblAddProjects.Text = "Add Projects";
|
||||
//
|
||||
// lblProjectType
|
||||
//
|
||||
this.lblProjectType.AutoSize = true;
|
||||
this.lblProjectType.Location = new System.Drawing.Point(13, 129);
|
||||
this.lblProjectType.Name = "lblProjectType";
|
||||
this.lblProjectType.Size = new System.Drawing.Size(70, 15);
|
||||
this.lblProjectType.TabIndex = 5;
|
||||
this.lblProjectType.Text = "Project Type";
|
||||
//
|
||||
// cboProjectType
|
||||
//
|
||||
this.cboProjectType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cboProjectType.FormattingEnabled = true;
|
||||
this.cboProjectType.Location = new System.Drawing.Point(16, 147);
|
||||
this.cboProjectType.Name = "cboProjectType";
|
||||
this.cboProjectType.Size = new System.Drawing.Size(150, 23);
|
||||
this.cboProjectType.TabIndex = 6;
|
||||
//
|
||||
// lblProjectPrefix
|
||||
//
|
||||
this.lblProjectPrefix.AutoSize = true;
|
||||
this.lblProjectPrefix.Location = new System.Drawing.Point(179, 129);
|
||||
this.lblProjectPrefix.Name = "lblProjectPrefix";
|
||||
this.lblProjectPrefix.Size = new System.Drawing.Size(75, 15);
|
||||
this.lblProjectPrefix.TabIndex = 7;
|
||||
this.lblProjectPrefix.Text = "Project Prefix";
|
||||
//
|
||||
// txtProjectPrefix
|
||||
//
|
||||
this.txtProjectPrefix.Location = new System.Drawing.Point(182, 147);
|
||||
this.txtProjectPrefix.Name = "txtProjectPrefix";
|
||||
this.txtProjectPrefix.Size = new System.Drawing.Size(150, 23);
|
||||
this.txtProjectPrefix.TabIndex = 8;
|
||||
//
|
||||
// lblRuntimes
|
||||
//
|
||||
this.lblRuntimes.AutoSize = true;
|
||||
this.lblRuntimes.Location = new System.Drawing.Point(345, 129);
|
||||
this.lblRuntimes.Name = "lblRuntimes";
|
||||
this.lblRuntimes.Size = new System.Drawing.Size(121, 15);
|
||||
this.lblRuntimes.TabIndex = 9;
|
||||
this.lblRuntimes.Text = "Runtimes (multiselect)";
|
||||
//
|
||||
// clbRuntimes
|
||||
//
|
||||
this.clbRuntimes.CheckOnClick = true;
|
||||
this.clbRuntimes.FormattingEnabled = true;
|
||||
this.clbRuntimes.Location = new System.Drawing.Point(348, 147);
|
||||
this.clbRuntimes.Name = "clbRuntimes";
|
||||
this.clbRuntimes.Size = new System.Drawing.Size(150, 76);
|
||||
this.clbRuntimes.TabIndex = 10;
|
||||
//
|
||||
// btnAddProject
|
||||
//
|
||||
this.btnAddProject.Location = new System.Drawing.Point(504, 147);
|
||||
this.btnAddProject.Name = "btnAddProject";
|
||||
this.btnAddProject.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnAddProject.TabIndex = 11;
|
||||
this.btnAddProject.Text = "Add";
|
||||
this.btnAddProject.UseVisualStyleBackColor = true;
|
||||
this.btnAddProject.Click += new System.EventHandler(this.btnAddProject_Click);
|
||||
//
|
||||
// lstProjects
|
||||
//
|
||||
this.lstProjects.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.lstProjects.FormattingEnabled = true;
|
||||
this.lstProjects.ItemHeight = 15;
|
||||
this.lstProjects.Location = new System.Drawing.Point(16, 236);
|
||||
this.lstProjects.Name = "lstProjects";
|
||||
this.lstProjects.Size = new System.Drawing.Size(563, 139);
|
||||
this.lstProjects.TabIndex = 12;
|
||||
//
|
||||
// btnRemoveSelected
|
||||
//
|
||||
this.btnRemoveSelected.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btnRemoveSelected.Location = new System.Drawing.Point(16, 385);
|
||||
this.btnRemoveSelected.Name = "btnRemoveSelected";
|
||||
this.btnRemoveSelected.Size = new System.Drawing.Size(120, 23);
|
||||
this.btnRemoveSelected.TabIndex = 13;
|
||||
this.btnRemoveSelected.Text = "Remove selected";
|
||||
this.btnRemoveSelected.UseVisualStyleBackColor = true;
|
||||
this.btnRemoveSelected.Click += new System.EventHandler(this.btnRemoveSelected_Click);
|
||||
//
|
||||
// btnOK
|
||||
//
|
||||
this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnOK.Location = new System.Drawing.Point(423, 385);
|
||||
this.btnOK.Name = "btnOK";
|
||||
this.btnOK.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnOK.TabIndex = 14;
|
||||
this.btnOK.Text = "Create";
|
||||
this.btnOK.UseVisualStyleBackColor = true;
|
||||
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnCancel.Location = new System.Drawing.Point(504, 385);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 15;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||
//
|
||||
// WizardForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(592, 420);
|
||||
this.Controls.Add(this.btnCancel);
|
||||
this.Controls.Add(this.btnOK);
|
||||
this.Controls.Add(this.btnRemoveSelected);
|
||||
this.Controls.Add(this.lstProjects);
|
||||
this.Controls.Add(this.btnAddProject);
|
||||
this.Controls.Add(this.clbRuntimes);
|
||||
this.Controls.Add(this.lblRuntimes);
|
||||
this.Controls.Add(this.txtProjectPrefix);
|
||||
this.Controls.Add(this.lblProjectPrefix);
|
||||
this.Controls.Add(this.cboProjectType);
|
||||
this.Controls.Add(this.lblProjectType);
|
||||
this.Controls.Add(this.lblAddProjects);
|
||||
this.Controls.Add(this.lblHint);
|
||||
this.Controls.Add(this.txtExtensionNamespace);
|
||||
this.Controls.Add(this.lblExtensionNamespace);
|
||||
this.Controls.Add(this.lblTitle);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "WizardForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Matrix42 Extension Solution Wizard";
|
||||
this.Load += new System.EventHandler(this.WizardForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||
{
|
||||
public partial class WizardForm : Form
|
||||
{
|
||||
private readonly List<ProjectDefinition> _projects = new List<ProjectDefinition>();
|
||||
|
||||
public string ExtensionNamespace => txtExtensionNamespace.Text.Trim();
|
||||
public IReadOnlyList<ProjectDefinition> Projects => _projects;
|
||||
|
||||
public WizardForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
cboProjectType.DataSource = Enum.GetValues(typeof(ProjectType));
|
||||
|
||||
clbRuntimes.Items.Add("Win");
|
||||
clbRuntimes.Items.Add("WinCore");
|
||||
clbRuntimes.Items.Add("LinuxCore");
|
||||
clbRuntimes.Items.Add("ALL");
|
||||
|
||||
cboProjectType.SelectedIndexChanged += CboProjectType_SelectedIndexChanged;
|
||||
}
|
||||
|
||||
private void WizardForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
lblHint.Text = "aka Matrix42.MyExtension";
|
||||
}
|
||||
|
||||
private void CboProjectType_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
var type = (ProjectType)cboProjectType.SelectedItem;
|
||||
switch (type)
|
||||
{
|
||||
case ProjectType.WebApi:
|
||||
txtProjectPrefix.Text = "Services";
|
||||
txtProjectPrefix.ReadOnly = false;
|
||||
break;
|
||||
case ProjectType.Contracts:
|
||||
txtProjectPrefix.Text = "Contracts";
|
||||
txtProjectPrefix.ReadOnly = false;
|
||||
break;
|
||||
case ProjectType.BizLogic:
|
||||
txtProjectPrefix.Text = "BizLogic";
|
||||
txtProjectPrefix.ReadOnly = false;
|
||||
break;
|
||||
case ProjectType.Custom:
|
||||
txtProjectPrefix.Text = string.Empty;
|
||||
txtProjectPrefix.ReadOnly = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnAddProject_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!ValidateProjectInputs())
|
||||
return;
|
||||
|
||||
var def = new ProjectDefinition
|
||||
{
|
||||
Type = (ProjectType)cboProjectType.SelectedItem,
|
||||
Prefix = txtProjectPrefix.Text.Trim(),
|
||||
Runtimes = GetSelectedRuntimes()
|
||||
};
|
||||
|
||||
_projects.Add(def);
|
||||
lstProjects.Items.Add(def.Display);
|
||||
|
||||
txtProjectPrefix.Clear();
|
||||
for (int i = 0; i < clbRuntimes.Items.Count; i++)
|
||||
clbRuntimes.SetItemChecked(i, false);
|
||||
}
|
||||
|
||||
private RuntimeTargets GetSelectedRuntimes()
|
||||
{
|
||||
RuntimeTargets result = RuntimeTargets.None;
|
||||
|
||||
foreach (var item in clbRuntimes.CheckedItems)
|
||||
{
|
||||
switch (item.ToString())
|
||||
{
|
||||
case "Win":
|
||||
result |= RuntimeTargets.Win;
|
||||
break;
|
||||
case "WinCore":
|
||||
result |= RuntimeTargets.WinCore;
|
||||
break;
|
||||
case "LinuxCore":
|
||||
result |= RuntimeTargets.LinuxCore;
|
||||
break;
|
||||
case "ALL":
|
||||
result |= RuntimeTargets.All;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool ValidateProjectInputs()
|
||||
{
|
||||
if (cboProjectType.SelectedItem == null)
|
||||
{
|
||||
MessageBox.Show("Please select project type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var type = (ProjectType)cboProjectType.SelectedItem;
|
||||
if (string.IsNullOrWhiteSpace(txtProjectPrefix.Text))
|
||||
{
|
||||
if (type == ProjectType.Custom)
|
||||
{
|
||||
MessageBox.Show("Project prefix is required for Custom project type.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (clbRuntimes.CheckedItems.Count == 0)
|
||||
{
|
||||
MessageBox.Show("Please select at least one runtime.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void btnRemoveSelected_Click(object sender, EventArgs e)
|
||||
{
|
||||
int idx = lstProjects.SelectedIndex;
|
||||
if (idx < 0 || idx >= _projects.Count)
|
||||
return;
|
||||
|
||||
_projects.RemoveAt(idx);
|
||||
lstProjects.Items.RemoveAt(idx);
|
||||
}
|
||||
|
||||
private void btnOK_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ExtensionNamespace))
|
||||
{
|
||||
MessageBox.Show("Extension Namespace is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_projects.Count == 0)
|
||||
{
|
||||
MessageBox.Show("Please add at least one project.");
|
||||
return;
|
||||
}
|
||||
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
|
||||
<Metadata>
|
||||
<Identity Id="Matrix42.Extensions.Scaffolder.Vsix.7c0f30ed-547f-4e1d-a046-8120ae21fc8b" Version="1.0" Language="en-US" Publisher="Matrix42" />
|
||||
<DisplayName>Matrix42.Extensions.Scaffolder.Vsix</DisplayName>
|
||||
<Description xml:space="preserve">Creates a new Matrix42 extension solution with multiple projects based on Matrix42.Extensions.SDK.</Description>
|
||||
</Metadata>
|
||||
<Installation>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0, 18.0)">
|
||||
<ProductArchitecture>amd64</ProductArchitecture>
|
||||
</InstallationTarget>
|
||||
</Installation>
|
||||
<Dependencies>
|
||||
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.7,)" />
|
||||
</Dependencies>
|
||||
<Prerequisites>
|
||||
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.0,18.0)" DisplayName="Visual Studio core editor" />
|
||||
</Prerequisites>
|
||||
<Assets>
|
||||
<Asset Type="Microsoft.VisualStudio.ProjectTemplate" Path="ProjectTemplates\ExtensionSolution.vstemplate" />
|
||||
</Assets>
|
||||
</PackageManifest>
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36310.24
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Core", "Matrix42.Extensions.Scaffolder.Core\Matrix42.Extensions.Scaffolder.Core.csproj", "{43E82070-2941-4589-8BF5-1FD1D427BDAE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Console", "Matrix42.Extensions.Scaffolder.Console\Matrix42.Extensions.Scaffolder.Console.csproj", "{F7979A70-0D89-46B7-814C-1E7D0B0DF441}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Vsix", "Matrix42.Extensions.Scaffolder.Vsix\Matrix42.Extensions.Scaffolder.Vsix.csproj", "{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3329054A-94A3-4953-8650-68C9B450515A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Reference in New Issue
Block a user