param( [switch]$Windows, [switch]$Linux, [string[]]$LinuxRuntimes = @("linux-x64", "linux-arm64"), [switch]$LinuxSelfContained, [ValidateSet("Release", "Debug")] [string]$Configuration = "Release", [switch]$SkipWindowsInnoSetup, [switch]$SkipWindowsVersionBump ) $ErrorActionPreference = "Stop" $ScriptPath = $PSScriptRoot $WebDir = Join-Path $ScriptPath "src\Hua.Todo.Web" $publishWindowsScript = Join-Path $ScriptPath "publish-windows.ps1" $publishLinuxScript = Join-Path $ScriptPath "publish-linux.ps1" $DirectoryBuildProps = Join-Path $ScriptPath "Directory.Build.props" function Stop-ProjectProcesses { Write-Host "Shutting down dotnet build servers..." -ForegroundColor Yellow dotnet build-server shutdown | Out-Null Write-Host "Checking for running processes to prevent file locks..." -ForegroundColor Yellow $processesToKill = Get-Process | Where-Object { $_.ProcessName -like "*Hua.Todo*" -or $_.ProcessName -eq "MSBuild" -or ($_.ProcessName -eq "dotnet" -and ($_.CommandLine -like "*Hua.Todo*" -or $_.CommandLine -like "*msbuild*")) } if ($processesToKill) { Write-Host "Stopping $($processesToKill.Count) running processes..." -ForegroundColor Yellow foreach ($p in $processesToKill) { try { Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue } catch { Write-Warning "Failed to stop process $($p.ProcessName) (ID: $($p.Id))" } } Start-Sleep -Seconds 2 } else { Write-Host "No conflicting processes found." -ForegroundColor Green } } function Build-Web { Write-Host "Building Web artifacts..." -ForegroundColor Cyan if (!(Test-Path $WebDir)) { Write-Error "Web directory not found: $WebDir" exit 1 } if (!(Test-Path (Join-Path $WebDir "node_modules"))) { Write-Host "Installing npm dependencies..." -ForegroundColor Yellow Push-Location $WebDir npm install Pop-Location } Write-Host "Running Web builds in parallel..." -ForegroundColor Yellow $webJobs = @() $webJobs += Start-Job -ScriptBlock { param($dir) Set-Location $dir npm run build } -ArgumentList $WebDir $webJobs += Start-Job -ScriptBlock { param($dir) Set-Location $dir npm run build -- --mode maui } -ArgumentList $WebDir $webJobs | Wait-Job | Receive-Job } function Bump-Version { if (Test-Path $DirectoryBuildProps) { [xml]$props = Get-Content $DirectoryBuildProps -Raw $versionNode = $props.SelectSingleNode("//Version") if ($null -ne $versionNode -and -not [string]::IsNullOrWhiteSpace($versionNode.InnerText)) { $currentVersion = $versionNode.InnerText.Trim() $versionMatch = [regex]::Match($currentVersion, '^(?\d+)\.(?\d+)\.(?\d+)$') if ($versionMatch.Success) { $newVersion = "{0}.{1}.{2}" -f $versionMatch.Groups["major"].Value, $versionMatch.Groups["minor"].Value, ([int]$versionMatch.Groups["patch"].Value + 1) $propsContent = Get-Content $DirectoryBuildProps -Raw $propsContent = $propsContent -replace "[^<]*", "$newVersion" Set-Content $DirectoryBuildProps -Value $propsContent -Encoding UTF8 Write-Host "Bumped version in Directory.Build.props: $currentVersion -> $newVersion" -ForegroundColor Green } } } } if ($Configuration -ne "Release") { Write-Host "⚠️ WARNING: You are publishing in $Configuration configuration!" -ForegroundColor Yellow Write-Host " Typically, production artifacts MUST be in Release configuration." -ForegroundColor Yellow Write-Host "" } $shouldPublishWindows = $Windows.IsPresent $shouldPublishLinux = $Linux.IsPresent if (!$shouldPublishWindows -and !$shouldPublishLinux) { $shouldPublishWindows = $true $shouldPublishLinux = $true } # 1. Cleanup Stop-ProjectProcesses # 2. Build Web Build-Web # 3. App Publishing # NOTE: To avoid file locks in 'obj' and 'bin' folders, we publish the .NET apps sequentially. # However, we can parallelize the Inno Setup packaging later if needed. Write-Host "Starting app publishing..." -ForegroundColor Cyan if ($shouldPublishWindows) { Write-Host "Publishing Windows Apps..." -ForegroundColor Cyan # Maui Windows (Skip ISS here, we'll do it later if parallel is needed, or just let it run) & $publishWindowsScript -AppType Maui -Configuration $Configuration -SkipInnoSetup:$SkipWindowsInnoSetup -SkipVersionBump -SkipProcessStop # Avalonia Windows & $publishWindowsScript -AppType Avalonia -Configuration $Configuration -SkipInnoSetup:$SkipWindowsInnoSetup -SkipVersionBump -SkipProcessStop } if ($shouldPublishLinux) { Write-Host "Publishing Linux Apps..." -ForegroundColor Cyan foreach ($rid in $LinuxRuntimes) { & $publishLinuxScript -RuntimeIdentifier $rid -SelfContained:$LinuxSelfContained -Configuration $Configuration -SkipProcessStop } } # 4. Finalizing if (!$SkipWindowsVersionBump.IsPresent) { Bump-Version } Write-Host "All publishing tasks completed!" -ForegroundColor Green