1
+ <#
2
+ . SYNOPSIS
3
+ Prepares a Clean Architecture solution as a template.
4
+
5
+ . DESCRIPTION
6
+ This script prepares the Clean Architecture solution as a template by
7
+ tokenizing namespace references and setting up the structure for packaging.
8
+ It does NOT create the actual NuGet package - this is handled separately.
9
+
10
+ . PARAMETER SourceDirectory
11
+ The directory containing the source code to templatize. Default is the current directory.
12
+
13
+ . PARAMETER TemplateNamespace
14
+ The current namespace prefix used in the solution that will be tokenized. Default is "Contact".
15
+
16
+ . PARAMETER OutputDirectory
17
+ The directory where the prepared template will be created. Default is ".\template-output".
18
+ #>
19
+
20
+ param (
21
+ [string ]$SourceDirectory = " ." ,
22
+ [string ]$TemplateNamespace = " Contact" ,
23
+ [string ]$OutputDirectory = " .\template-output"
24
+ )
25
+
26
+ # Create a timestamp for logging purposes
27
+ $timestamp = Get-Date - Format " yyyy-MM-dd HH:mm:ss"
28
+ Write-Host " [$timestamp ] Template preparation process started"
29
+
30
+ # Ensure output directory exists and is empty
31
+ if (Test-Path $OutputDirectory ) {
32
+ Write-Host " [$timestamp ] Cleaning existing output directory..."
33
+ Remove-Item - Path " $OutputDirectory \*" - Recurse - Force - ErrorAction SilentlyContinue
34
+ } else {
35
+ Write-Host " [$timestamp ] Creating output directory..."
36
+ New-Item - Path $OutputDirectory - ItemType Directory | Out-Null
37
+ }
38
+
39
+ # Create template structure directories
40
+ $templateConfigDir = Join-Path $OutputDirectory " .template.config"
41
+ New-Item - Path $templateConfigDir - ItemType Directory - Force | Out-Null
42
+
43
+ # Copy all solution files to the output directory
44
+ Write-Host " [$timestamp ] Copying solution files..."
45
+ $excludedItems = @ (
46
+ " bin" , " obj" , " node_modules" , " .vs" , " .vscode" , " dist" , " .git" ,
47
+ " .angular" , " package-lock.json" , " yarn.lock" , " .env" ,
48
+ " appsettings.Development.json" , " CreateTemplate.ps1" , " nupkg"
49
+ )
50
+
51
+ # Get all directories in the source directory except excluded ones
52
+ Get-ChildItem - Path $SourceDirectory - Directory |
53
+ Where-Object { $excludedItems -notcontains $_.Name } |
54
+ ForEach-Object {
55
+ Copy-Item - Path $_.FullName - Destination $OutputDirectory - Recurse - Force
56
+ }
57
+
58
+ # Get all files in the source directory except excluded ones or hidden files
59
+ Get-ChildItem - Path $SourceDirectory - File |
60
+ Where-Object {
61
+ -not $_.Name.StartsWith (' .' ) -and
62
+ $_.Name -ne " CreateTemplate.ps1" -and
63
+ $_.Extension -ne " .nupkg"
64
+ } |
65
+ ForEach-Object {
66
+ Copy-Item - Path $_.FullName - Destination $OutputDirectory - Force
67
+ }
68
+
69
+ # Clean up binary files from the output directory
70
+ Write-Host " [$timestamp ] Cleaning up binary and temporary files..."
71
+ Get-ChildItem - Path $OutputDirectory - Include @ (" bin" , " obj" , " node_modules" , " .vs" , " .vscode" , " dist" , " .git" , " .angular" , " .github" ) - Recurse - Directory |
72
+ ForEach-Object {
73
+ Write-Host " Removing $ ( $_.FullName ) "
74
+ Remove-Item - Path $_.FullName - Recurse - Force - ErrorAction SilentlyContinue
75
+ }
76
+
77
+ # Find and replace namespace references in C# files
78
+ Write-Host " [$timestamp ] Tokenizing namespace references..."
79
+ $filesToProcess = Get-ChildItem - Path $OutputDirectory - Include @ (" *.cs" , " *.csproj" , " *.sln" ) - Recurse - File
80
+
81
+ foreach ($file in $filesToProcess ) {
82
+ Write-Host " Processing $ ( $file.FullName ) "
83
+ $content = Get-Content - Path $file.FullName - Raw
84
+
85
+ # Replace namespace references
86
+ if ($file.Extension -eq " .cs" ) {
87
+ $content = $content -replace " namespace\s+$TemplateNamespace \." , " namespace ${TemplateNamespace} ."
88
+ $content = $content -replace " using\s+$TemplateNamespace \." , " using ${TemplateNamespace} ."
89
+ }
90
+ elseif ($file.Extension -eq " .csproj" ) {
91
+ $content = $content -replace " <RootNamespace>$TemplateNamespace \." , " <RootNamespace>${TemplateNamespace} ."
92
+ $content = $content -replace " <AssemblyName>$TemplateNamespace \." , " <AssemblyName>${TemplateNamespace} ."
93
+ }
94
+ elseif ($file.Name -eq " *.sln" ) {
95
+ $content = $content -replace " $TemplateNamespace \." , " ${TemplateNamespace} ."
96
+ }
97
+
98
+ # Write the modified content back to the file
99
+ Set-Content - Path $file.FullName - Value $content - NoNewline
100
+ }
101
+
102
+ # Create template.json configuration file
103
+ Write-Host " [$timestamp ] Creating template configuration..."
104
+ $templateJson = @ {
105
+ ' $schema' = " http://json.schemastore.org/template"
106
+ author = " Template Author" # This will be overridden in the GitHub Action
107
+ classifications = @ (" Web" , " API" , " Angular" , " Clean Architecture" , " Full-Stack" )
108
+ identity = " CleanArchitecture.FullStack.Template"
109
+ name = " Clean Architecture Full-Stack Solution"
110
+ shortName = " cleanarch-fullstack"
111
+ tags = @ {
112
+ language = " C#"
113
+ type = " project"
114
+ }
115
+ sourceName = $TemplateNamespace
116
+ preferNameDirectory = $true
117
+ symbols = @ {
118
+ Framework = @ {
119
+ type = " parameter"
120
+ description = " The target framework for the project."
121
+ datatype = " choice"
122
+ choices = @ (
123
+ @ {
124
+ choice = " net9.0"
125
+ description = " .NET 9.0"
126
+ }
127
+ )
128
+ defaultValue = " net9.0"
129
+ }
130
+ Organization = @ {
131
+ type = " parameter"
132
+ datatype = " string"
133
+ description = " Organization name to use in the project"
134
+ defaultValue = " YourCompany"
135
+ replaces = $TemplateNamespace
136
+ }
137
+ SkipRestore = @ {
138
+ type = " parameter"
139
+ datatype = " bool"
140
+ description = " If specified, skips the automatic restore of the project on create."
141
+ defaultValue = $false
142
+ }
143
+ IncludeAngular = @ {
144
+ type = " parameter"
145
+ datatype = " bool"
146
+ description = " If specified, includes the Angular frontend project."
147
+ defaultValue = $true
148
+ }
149
+ }
150
+ sources = @ (
151
+ @ {
152
+ source = " backend/"
153
+ target = " backend/"
154
+ }
155
+ @ {
156
+ source = " frontend/"
157
+ target = " frontend/"
158
+ condition = " IncludeAngular"
159
+ }
160
+ @ {
161
+ source = " docker-compose.yml"
162
+ target = " docker-compose.yml"
163
+ }
164
+ @ {
165
+ source = " .env-example"
166
+ target = " .env-example"
167
+ }
168
+ @ {
169
+ source = " README.md"
170
+ target = " README.md"
171
+ }
172
+ )
173
+ postActions = @ (
174
+ @ {
175
+ condition = " (!SkipRestore)"
176
+ description = " Restore NuGet packages required by this project."
177
+ manualInstructions = @ (
178
+ @ {
179
+ text = " Run 'dotnet restore' in the backend directory"
180
+ }
181
+ )
182
+ actionId = " 210D431B-A78B-4D2F-B762-4ED3E3EA9025"
183
+ continueOnError = $true
184
+ }
185
+ )
186
+ }
187
+
188
+ # Convert the template configuration to JSON
189
+ $templateJsonContent = $templateJson | ConvertTo-Json - Depth 10
190
+ Set-Content - Path (Join-Path $templateConfigDir " template.json" ) - Value $templateJsonContent
191
+
192
+ Write-Host " [$timestamp ] Template preparation completed successfully."
193
+ Write-Host " Template output directory: $OutputDirectory "
0 commit comments