cleanarch-new.ps1
|
#Requires -Version 5.1 [CmdletBinding(PositionalBinding=$false)] param( [string]$ProjectName = "", [ValidateSet("Dapper","EFCore","Hybrid","")] [string]$OrmMode = "", [string[]]$Entities = @("User", "Product"), [ValidateSet("MSSQL","Postgres")] [string]$DbProvider = "", [string]$OutputRootPath = "", [switch]$SkipFrontend, [switch]$SkipAiGuide, [switch]$SkipTests, [switch]$SkipCi, [switch]$DryRun, [string]$IdeConfig = "VSCode", [switch]$Observability, [switch]$NonInteractive, [string]$Language = "tr", [ValidateSet("Web","Mobile","Both","")] [string]$Platform = "", [ValidateSet("Layered","FeatureSliced")] [string]$Architecture = "Layered", [switch]$SkipNpm, [switch]$Version, [Alias("h")] [switch]$Help ) $FrontendMode = "ReactTS" $MobileTooling = "Expo" $ConnectionString = "" [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $ModulesDir = Join-Path $ScriptDir "modules" # --- UTF-8 encoding (Türkçe karakter desteği) --- [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 $OutputEncoding = [System.Text.Encoding]::UTF8 # --- Performance Optimizations (DotNet CLI) --- $env:DOTNET_CLI_TELEMETRY_OPTOUT = "1" $env:DOTNET_NOLOGO = "1" $env:NUGET_XMLDOC_MODE = "skip" $Global:DryRun = $DryRun . "$ModulesDir\core\Utils.ps1" . "$ModulesDir\core\Invoke-TuiMenu.ps1" . "$ModulesDir\core\Get-Locale.ps1" $L = Get-Locale -Language $Language # Dil dogrulama if ($Language -notin @('tr','en')) { Write-Host "" Write-Host "ERROR: Invalid language '$Language'. Use 'tr' for Turkish or 'en' for English." -ForegroundColor Red Write-Host "HATA: Gecersiz dil '$Language'. 'tr' (Turkce) veya 'en' (Ingilizce) kullanin." -ForegroundColor Red Write-Host "" Write-Host " cleanarch-new -Help" -ForegroundColor DarkGray Write-Host " cleanarch-new -h" -ForegroundColor DarkGray return } if ($Help) { Write-Host "" Write-Host " Clean Architecture Template Generator (cleanarch)" -ForegroundColor Cyan Write-Host " ------------------------------------------------" -ForegroundColor DarkCyan Write-Host "" Write-Host " USAGE / KULLANIM:" -ForegroundColor Yellow Write-Host " cleanarch-new -ProjectName <Name/Ad> -Platform Web|Mobile|Both [options]" -ForegroundColor White Write-Host " cleanarch-new # Interactive TUI / Etkilesimli menu" -ForegroundColor DarkGray Write-Host " cleanarch-new -h # This help / Bu yardim" -ForegroundColor DarkGray Write-Host "" Write-Host " PARAMETERS / PARAMETRELER:" -ForegroundColor Yellow Write-Host " -ProjectName <Name/Ad> : Project name / Proje adi" -ForegroundColor White Write-Host " -Platform <Web|Mobile|Both> : Target platform / Hedef platform" -ForegroundColor White Write-Host " -OrmMode <Dapper|EFCore|Hybrid> : ORM mode / ORM modu" -ForegroundColor White Write-Host " -DbProvider <MSSQL|Postgres> : Database provider / Veritabani saglayicisi" -ForegroundColor White Write-Host " -Entities <List> : Comma-separated entities / Virgulle ayrilmis entity listesi (default: User,Product)" -ForegroundColor White Write-Host " -Architecture <Layered|FeatureSliced> : Architecture style / Mimari yapi (default: Layered)" -ForegroundColor White Write-Host " -OutputRootPath <Path> : Output directory / Cikti dizini" -ForegroundColor White Write-Host " -Language <tr|en> : Interface language / Arayuz dili (default: tr)" -ForegroundColor White Write-Host " -IdeConfig <VSCode|None> : IDE configuration / IDE ayarları (default: VSCode)" -ForegroundColor White Write-Host "" Write-Host " OPTIONAL FLAGS / OPSIYONEL BAYRAKLAR:" -ForegroundColor Yellow Write-Host " -SkipFrontend : Skip frontend generation / Frontend olusturmayi atla" -ForegroundColor White Write-Host " -SkipTests : Skip test projects / Test projelerini atla" -ForegroundColor White Write-Host " -SkipCi : Skip CI/CD pipeline / CI/CD pipeline'ini atla" -ForegroundColor White Write-Host " -SkipAiGuide : Skip AI developer guide / AI rehberini atla" -ForegroundColor White Write-Host " -SkipNpm : Skip npm install (faster) / npm install calistirmayi atla (daha hizli)" -ForegroundColor White Write-Host " -DryRun : Simulate only / Sadece simulasyon yap" -ForegroundColor White Write-Host " -NonInteractive : Skip TUI menus, use defaults / Menuleri atla ve varsayilanlari kullan" -ForegroundColor White Write-Host " -Observability : Add Serilog + OpenTelemetry / Serilog ve OpenTelemetry destegi ekle" -ForegroundColor White Write-Host "" Write-Host " OTHER COMMANDS / DIGER KOMUTLAR:" -ForegroundColor Yellow Write-Host " cleanarch-version : Show version / Versiyon bilgisi" -ForegroundColor White Write-Host " cleanarch-update : Update to latest / Son surume guncelle" -ForegroundColor White Write-Host " cleanarch-uninstall : Remove from system / Sistemden kaldir" -ForegroundColor White Write-Host "" Write-Host " EXAMPLES / ORNEKLER:" -ForegroundColor Yellow Write-Host " cleanarch-new -ProjectName MyApp -Platform Web -OrmMode EFCore -DbProvider Postgres" -ForegroundColor DarkGray Write-Host " cleanarch-new -ProjectName MyApp -Platform Both -OrmMode Hybrid -DbProvider MSSQL -Language en" -ForegroundColor DarkGray Write-Host "" return } if ($Version) { $v = & "$ModulesDir\core\cleanarch-version.ps1" -OnlyVersion Write-Host "Clean Architecture Template Generator v$v" return } $TotalSw = [System.Diagnostics.Stopwatch]::StartNew() if (-not $NonInteractive) { Clear-Host } Write-Host "================================================" -ForegroundColor DarkCyan Write-Host " Clean Architecture Template Generator " -ForegroundColor Cyan Write-Host "================================================" -ForegroundColor DarkCyan Write-Host "" # --- Proje adi --- if (-not $ProjectName) { if ($NonInteractive) { Write-Err $L.tuiNameRequired "E001"; exit 1 } $ProjectName = Read-Host $L.tuiProjectName } if (-not $ProjectName -or $ProjectName -match '[\s\\/]' -or $ProjectName -notmatch '^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*$') { Write-Err $L.tuiInvalidName "E001" return } # --- Platform secimi --- if (-not $Platform) { if ($NonInteractive) { $Platform = "Web" } else { $options = @( $L.tuiPlatformWeb, $L.tuiPlatformMobile, $L.tuiPlatformBoth ) $choice = Invoke-TuiMenu -Title $L.tuiSelectPlatform -Options $options $Platform = switch ($choice) { 0 { "Web" } 1 { "Mobile" } 2 { "Both" } } } } # --- Architecture secimi --- if (-not $Architecture) { if ($NonInteractive) { $Architecture = "Layered" } else { $options = @( $L.tuiArchLayered, $L.tuiArchFeature ) $choice = Invoke-TuiMenu -Title $L.tuiSelectArch -Options $options $Architecture = switch ($choice) { 0 { "Layered" } 1 { "FeatureSliced" } } } } # --- ORM secimi --- if (-not $OrmMode) { if ($NonInteractive) { $OrmMode = "EFCore" } else { $options = @( $L.tuiOrmDapper, $L.tuiOrmEfCore, $L.tuiOrmHybrid ) $choice = Invoke-TuiMenu -Title $L.tuiSelectOrm -Options $options $OrmMode = switch ($choice) { 0 { "Dapper" } 1 { "EFCore" } 2 { "Hybrid" } } } } # --- Database secimi --- if (-not $DbProvider) { if ($NonInteractive) { $DbProvider = "Postgres" } else { $options = @("MS SQL Server", "PostgreSQL") $choice = Invoke-TuiMenu -Title $L.tuiSelectDb -Options $options $DbProvider = switch ($choice) { 0 { "MSSQL" } 1 { "Postgres" } } } } $CiProvider = "GitHub" # --- Entities string split (virgülle geçilen "Product,Order" -> @("Product","Order")) --- if ($Entities.Count -eq 1 -and $Entities[0] -match ',') { $Entities = $Entities[0] -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' } } # --- 'User' entity'si Auth icin zorunludur --- if ($Entities -notcontains "User") { $Entities += "User" } # --- Cikti koku --- if (-not $OutputRootPath) { $currentDir = (Get-Location).Path if ($NonInteractive) { $OutputRootPath = $currentDir } else { Write-Host "" Write-Host ($L.tuiProjectDir -f $currentDir) -ForegroundColor DarkGray $inputRoot = Read-Host $L.tuiDirPrompt $OutputRootPath = if ($inputRoot.Trim()) { $inputRoot.Trim() } else { $currentDir } } } if (-not $Global:DryRun -and -not (Test-Path $OutputRootPath)) { New-Item -ItemType Directory -Path $OutputRootPath -Force | Out-Null } $OutputRootPath = [System.IO.Path]::GetFullPath($OutputRootPath) $OutputPath = Join-Path $OutputRootPath $ProjectName if (-not $Global:DryRun -and (Test-Path $OutputPath)) { Write-Err ($L.tuiDirExists -f $OutputPath) "E002" return } # Params Splatting $Params = @{ ProjectName = $ProjectName OrmMode = $OrmMode DbProvider = $DbProvider OutputPath = $OutputPath FrontendMode = $FrontendMode SkipFrontend = $SkipFrontend SkipAiGuide = $SkipAiGuide SkipTests = $SkipTests SkipCi = $SkipCi CiProvider = $CiProvider DryRun = $DryRun Entities = $Entities IdeConfig = $IdeConfig Observability = $Observability Language = $Language Platform = $Platform Architecture = $Architecture MobileTooling = $MobileTooling SkipNpm = $SkipNpm } # --- Adimlar --- & "$ModulesDir\core\Test-Prerequisites.ps1" -FrontendMode $FrontendMode -Language $Language if ($LASTEXITCODE -ne 0) { exit 1 } try { $BackendParams = $Params.Clone() $BackendParams.OutputPath = Join-Path $OutputPath "$ProjectName-backend" Invoke-Step $L.logCreatingSolution { & "$ModulesDir\solution\Initialize-Solution.ps1" @BackendParams } Invoke-Step $L.logInstallingNuget { & "$ModulesDir\solution\Install-Packages.ps1" @BackendParams } Invoke-Step $L.logDomain { & "$ModulesDir\backend\Write-DomainLayer.ps1" @BackendParams } Invoke-Step $L.logApplication { & "$ModulesDir\backend\Write-ApplicationLayer.ps1" @BackendParams } Invoke-Step $L.logInfrastructure { & "$ModulesDir\backend\Write-InfrastructureLayer.ps1" @BackendParams } Invoke-Step $L.logPersistence { & "$ModulesDir\backend\Write-Persistence-Shared.ps1" @BackendParams & "$ModulesDir\backend\Write-Persistence-Dapper.ps1" @BackendParams & "$ModulesDir\backend\Write-Persistence-EFCore.ps1" @BackendParams & "$ModulesDir\backend\Write-Persistence-Hybrid.ps1" @BackendParams } Invoke-Step $L.logWebApi { & "$ModulesDir\backend\Write-WebApiLayer.ps1" @BackendParams } if (-not $SkipTests) { Invoke-Step $L.logTests { & "$ModulesDir\testing\Write-TestLayer.ps1" @BackendParams } } if (-not $SkipFrontend) { $setupMsg = switch ($Platform) { "Web" { $L.logFrontendSetup } "Mobile" { $L.logMobileSetup } "Both" { $L.logBothSetup } default { $L.logFrontendSetup } } $writeMsg = switch ($Platform) { "Web" { $L.logFrontendFiles } "Mobile" { $L.logMobileFiles } "Both" { $L.logBothFiles } default { $L.logFrontendFiles } } Invoke-Step $setupMsg { & "$ModulesDir\solution\Install-Frontend.ps1" @Params } Invoke-Step $writeMsg { & "$ModulesDir\frontend\Write-Frontend.ps1" @Params } } Invoke-Step $L.logDocker { & "$ModulesDir\devops\Write-Docker.ps1" @Params } if ($IdeConfig -ne "None") { Invoke-Step "$IdeConfig configuration" { & "$ModulesDir\devops\Write-IdeConfig.ps1" @Params } } if (-not $SkipCi) { Invoke-Step $L.logCiCd { & "$ModulesDir\devops\Write-CiPipeline.ps1" @Params } } Invoke-Step $L.logMigrations { & "$ModulesDir\devops\Write-MigrationScript.ps1" @Params } Invoke-Step $L.logReadme { & "$ModulesDir\solution\Write-Readme.ps1" @Params } if (-not $SkipAiGuide) { Invoke-Step $L.logAiGuide { & "$ModulesDir\ai-guide\Write-AiGuide-Core.ps1" @Params & "$ModulesDir\ai-guide\Write-AiGuide-Domain.ps1" @Params & "$ModulesDir\ai-guide\Write-AiGuide-Application.ps1" @Params & "$ModulesDir\ai-guide\Write-AiGuide-Persistence.ps1" @Params & "$ModulesDir\ai-guide\Write-AiGuide-WebApi.ps1" @Params if ($Platform -match "Web|Both" -and -not $SkipFrontend) { & "$ModulesDir\ai-guide\Write-AiGuide-Web.ps1" @Params } if ($Platform -match "Mobile|Both" -and -not $SkipFrontend) { & "$ModulesDir\ai-guide\Write-AiGuide-Mobile.ps1" @Params } } } # Summary Write-Host "" Write-Host "================================================" -ForegroundColor Green Write-Host (" " + ($L.tuiReady -f $ProjectName)) -ForegroundColor Green Write-Host (" " + ($L.tuiTotalTime -f $TotalSw.Elapsed.TotalSeconds)) -ForegroundColor Green Write-Host "================================================" -ForegroundColor Green Write-Host "" Write-Host "$($L.tuiLocation) : $OutputPath" Write-Host "Platform : $Platform" Write-Host "ORM : $OrmMode" Write-Host "Database : $DbProvider" if ($Platform -match "Web|Both") { Write-Host "Frontend : $(if($SkipFrontend){'None'}else{$FrontendMode})" } if ($Platform -match "Mobile|Both") { Write-Host "Mobile : $(if($SkipFrontend){'None'}else{$MobileTooling})" } Write-Host "IDE : $IdeConfig" Write-Host "" } catch { Write-Err ($L.tuiErrorOccurred -f $_) "E003" if (-not $Global:DryRun) { Write-Warn $L.tuiCleaningUp Remove-Item $OutputPath -Recurse -Force -ErrorAction SilentlyContinue } return } |