Build and Publish Template Package #15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build and Publish Template Package | |
on: | |
workflow_dispatch: | |
inputs: | |
version: | |
description: 'Package version (e.g., 1.0.0)' | |
required: true | |
default: '1.0.0' | |
author: | |
description: 'Template author' | |
required: true | |
default: 'Nitin Singh' | |
description: | |
description: 'Template description' | |
required: true | |
default: 'Full-stack Clean Architecture template with .NET 9 API and Angular 19' | |
jobs: | |
build-and-publish: | |
runs-on: windows-latest | |
env: | |
TEMPLATE_VERSION: ${{ github.event.inputs.version }} | |
TEMPLATE_AUTHOR: ${{ github.event.inputs.author }} | |
TEMPLATE_DESCRIPTION: ${{ github.event.inputs.description }} | |
NUGET_AUTH_TOKEN: ${{ secrets.NUGET_API_KEY }} | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
- name: Setup .NET | |
uses: actions/setup-dotnet@v3 | |
with: | |
dotnet-version: '9.0.x' | |
- name: Setup NuGet | |
uses: NuGet/setup-nuget@v1 | |
with: | |
nuget-version: '6.x' | |
- name: Display version | |
run: echo "Building template version ${{ env.TEMPLATE_VERSION }}" | |
- name: Create output directories | |
run: | | |
mkdir template-output | |
mkdir nupkg | |
- name: Run template preparation script | |
shell: pwsh | |
run: | | |
./template-src/CreateTemplate.ps1 -SourceDirectory . -TemplateNamespace Contact -OutputDirectory ./template-output | |
- name: Copy template.json file | |
shell: pwsh | |
run: | | |
# Create template config directory | |
New-Item -Path "./template-output/.template.config" -ItemType Directory -Force | |
# Copy the existing template.json file | |
Copy-Item -Path "./template-src/template.json" -Destination "./template-output/.template.config/template.json" | |
# Update metadata in template.json | |
$templateJsonPath = "./template-output/.template.config/template.json" | |
$templateJson = Get-Content -Path $templateJsonPath -Raw | ConvertFrom-Json | |
$templateJson.author = "${{ env.TEMPLATE_AUTHOR }}" | |
$templateJson | ConvertTo-Json -Depth 10 | Set-Content -Path $templateJsonPath | |
- name: Copy README template | |
shell: pwsh | |
run: | | |
# Ensure README is properly set up for NuGet package | |
Write-Host "Setting up README for NuGet package..." | |
# Check if README template exists in template-src | |
if (Test-Path "./template-src/README.template.md") { | |
# Copy as main README.md in the template output root | |
Copy-Item -Path "./template-src/README.template.md" -Destination "./template-output/README.md" | |
Write-Host "✅ README file set up successfully at template-output/README.md" | |
# Verify the file exists and has content | |
if (Test-Path "./template-output/README.md") { | |
$fileContent = Get-Content -Path "./template-output/README.md" -Raw | |
$contentLength = $fileContent.Length | |
Write-Host "README.md file size: $contentLength bytes" | |
} else { | |
Write-Error "README.md was not copied correctly" | |
} | |
} else { | |
Write-Error "README.template.md not found in template-src directory" | |
- name: Copy and update .nuspec file | |
shell: pwsh | |
run: | | |
# Copy the .nuspec file | |
Copy-Item -Path "./template-src/CleanArchitecture.FullStack.Template.nuspec" -Destination "./template-output/CleanArchitecture.FullStack.Template.nuspec" | |
# Update metadata in the .nuspec file | |
$nuspecPath = "./template-output/CleanArchitecture.FullStack.Template.nuspec" | |
$nuspecContent = Get-Content -Path $nuspecPath -Raw | |
# Replace version, author, and description with workflow inputs | |
$nuspecContent = $nuspecContent -replace '<version>.*?</version>', "<version>${{ env.TEMPLATE_VERSION }}</version>" | |
$nuspecContent = $nuspecContent -replace '<authors>.*?</authors>', "<authors>${{ env.TEMPLATE_AUTHOR }}</authors>" | |
$nuspecContent = $nuspecContent -replace '<description>.*?</description>', "<description>${{ env.TEMPLATE_DESCRIPTION }}</description>" | |
$nuspecContent = $nuspecContent -replace '<copyright>.*?</copyright>', "<copyright>Copyright © ${{ env.TEMPLATE_AUTHOR }} $((Get-Date).Year)</copyright>" | |
Set-Content -Path $nuspecPath -Value $nuspecContent | |
- name: Verify template structure | |
shell: pwsh | |
run: | | |
Write-Host "Verifying template structure..." | |
# Check that required files exist in template-output | |
$requiredFiles = @( | |
"docker-compose.yml", | |
".env-example", | |
"README.md" | |
) | |
foreach ($file in $requiredFiles) { | |
$filePath = "./template-output/$file" | |
if (Test-Path $filePath) { | |
Write-Host "✅ $file exists" | |
} else { | |
Write-Host "❌ $file is missing" | |
# Create empty file if missing to prevent template validation errors | |
New-Item -Path $filePath -ItemType File -Force | |
} | |
} | |
# Check that required directories exist | |
$requiredDirs = @( | |
"backend", | |
"frontend" | |
) | |
foreach ($dir in $requiredDirs) { | |
$dirPath = "./template-output/$dir" | |
if (Test-Path $dirPath) { | |
Write-Host "✅ $dir directory exists" | |
} else { | |
Write-Host "❌ $dir directory is missing" | |
# Create directory if missing | |
New-Item -Path $dirPath -ItemType Directory -Force | |
} | |
} | |
Write-Host "Template structure verification completed" | |
- name: Pack template | |
run: | | |
nuget pack ./template-output/CleanArchitecture.FullStack.Template.nuspec -OutputDirectory ./nupkg | |
- name: Verify template package contents | |
shell: pwsh | |
run: | | |
# Extract and verify the NuGet package contents to ensure README is included | |
$packagePath = Get-ChildItem -Path "./nupkg/*.nupkg" | Select-Object -First 1 -ExpandProperty FullName | |
$extractPath = "./nupkg-extracted" | |
Write-Host "Extracting NuGet package to verify contents..." | |
if (Test-Path $extractPath) { | |
Remove-Item -Path $extractPath -Recurse -Force | |
} | |
New-Item -Path $extractPath -ItemType Directory | Out-Null | |
# Extract the package using NuGet | |
nuget install CleanArchitecture.FullStack.Template -Source "./nupkg" -OutputDirectory $extractPath -ExcludeVersion | |
# Verify README exists | |
$readmePath = "$extractPath/CleanArchitecture.FullStack.Template/README.md" | |
if (Test-Path $readmePath) { | |
Write-Host "✅ README.md exists in the NuGet package" | |
} else { | |
Write-Error "❌ README.md is missing from the NuGet package" | |
- name: Test template package | |
run: | | |
dotnet new install ./nupkg/CleanArchitecture.FullStack.Template.${{ env.TEMPLATE_VERSION }}.nupkg | |
mkdir test-project | |
cd test-project | |
# Verify template installed correctly | |
dotnet new --list | findstr "cleanarch" | |
# Create project from template with parameters from template.json | |
# Test both with camelCase and PascalCase to verify both work | |
dotnet new cleanarch-fullstack --Organization TestCompany --ProjectName TestProject | |
# List files to verify creation | |
dir | |
- name: Test template package with organization | |
run: | | |
mkdir test-project-with-org | |
cd test-project-with-org | |
# Create project from template with organization parameter | |
dotnet new cleanarch-fullstack --organization TestCompany --projectName TestProjectWithOrg | |
# List files to verify creation | |
dir | |
- name: Test template package without organization | |
run: | | |
mkdir test-project-no-org | |
cd test-project-no-org | |
# Create project from template without organization parameter | |
dotnet new cleanarch-fullstack --projectName TestProjectNoOrg | |
# List files to verify creation | |
dir | |
- name: Test template package without Angular | |
run: | | |
mkdir test-project-no-angular | |
cd test-project-no-angular | |
# Create project from template without Angular | |
dotnet new cleanarch-fullstack --organization TestCompany --projectName TestProjectNoAngular --includeAngular false | |
# Verify that frontend directory is not created | |
if (Test-Path "./frontend") { | |
Write-Error "Frontend directory should not exist when includeAngular is false" | |
exit 1 | |
} | |
# List files to verify creation | |
dir | |
- name: Test template package with default folder naming | |
shell: pwsh | |
run: | | |
# Test with organization - should create folder YourCompany.TestProject | |
dotnet new cleanarch-fullstack --Organization YourCompany --ProjectName TestProject | |
if (Test-Path "YourCompany.TestProject") { | |
Write-Host "✅ YourCompany.TestProject folder created successfully" | |
} else { | |
Write-Error "❌ YourCompany.TestProject folder not created" | |
exit 1 | |
} | |
# Test without organization - should create folder TestProjectNoOrg | |
dotnet new cleanarch-fullstack --ProjectName TestProjectNoOrg | |
if (Test-Path "TestProjectNoOrg") { | |
Write-Host "✅ TestProjectNoOrg folder created successfully" | |
} else { | |
Write-Error "❌ TestProjectNoOrg folder not created" | |
exit 1 | |
} | |
# Test with explicit output folder | |
dotnet new cleanarch-fullstack --Organization YourCompany --ProjectName TestProject -o CustomFolder | |
if (Test-Path "CustomFolder") { | |
Write-Host "✅ CustomFolder created successfully" | |
} else { | |
Write-Error "❌ CustomFolder not created" | |
exit 1 | |
} | |
- name: Upload package artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: nuget-package | |
path: ./nupkg/*.nupkg | |
- name: Push to NuGet | |
run: | | |
dotnet nuget push ./nupkg/CleanArchitecture.FullStack.Template.${{ env.TEMPLATE_VERSION }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json |