diff --git a/.github/workflows/windows-release.yml b/.github/workflows/windows-release.yml index 4e896c6b292..b95e1cf9270 100644 --- a/.github/workflows/windows-release.yml +++ b/.github/workflows/windows-release.yml @@ -22,6 +22,14 @@ on: description: Force fresh dependency/native rebuild type: boolean default: false + native_jobs: + description: Native rebuild parallelism for node-gyp + type: string + default: "2" + native_package_concurrency: + description: Number of native packages to rebuild at once + type: string + default: "3" tag: description: Release tag type: string @@ -51,6 +59,8 @@ jobs: if ('${{ inputs.zip }}' -eq 'true') { $buildArgs['Zip'] = $true } if ('${{ inputs.installer }}' -eq 'true') { $buildArgs['Installer'] = $true } if ('${{ inputs.fresh }}' -eq 'true') { $buildArgs['Fresh'] = $true } + $buildArgs['NativeJobs'] = '${{ inputs.native_jobs }}' + $buildArgs['NativePackageConcurrency'] = [int]'${{ inputs.native_package_concurrency }}' & .\scripts\build-pointer-release.ps1 @buildArgs - name: Upload artifacts diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 19688d91aa6..5163992d85c 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -88,6 +88,8 @@ Vor einem öffentlichen Release siehe zusätzlich `docs/LAUNCH_CHECKLIST.md`. | `--Fresh` | Komplett-Neuinstallation aller Dependencies | | `--Installer` | Inno Setup Installer erstellen | | `--Zip` | ZIP-Archiv der portablen App erstellen | +| `--NativeJobs max` | MSBuild-Parallelität pro Native Package (CI kann höher gehen; lokal konservativ lassen) | +| `--NativePackageConcurrency 3` | Mehrere Native Packages parallel rebuilden (für CI empfohlen; lokal konservativ lassen) | ### Beispiel: Frischer Build mit Installer und ZIP diff --git a/scripts/build-pointer-release.ps1 b/scripts/build-pointer-release.ps1 index b86290c33be..f882d81d0fd 100644 --- a/scripts/build-pointer-release.ps1 +++ b/scripts/build-pointer-release.ps1 @@ -6,6 +6,8 @@ param( [switch]$Fresh, [switch]$Installer, [switch]$Zip, + [string]$NativeJobs = '1', + [int]$NativePackageConcurrency = 1, [switch]$InVsDevShell ) @@ -232,6 +234,10 @@ function Restart-InVsDevShell { if ($Fresh) { $args += '-Fresh' } if ($Installer) { $args += '-Installer' } if ($Zip) { $args += '-Zip' } + $args += '-NativeJobs' + $args += $NativeJobs + $args += '-NativePackageConcurrency' + $args += $NativePackageConcurrency $cmd = "call `"$vsDevCmd`" -arch=$Arch -host_arch=x64 && set `"PATH=$NodeDir;%PATH%`" && powershell.exe $($args -join ' ')" & cmd.exe /d /s /c $cmd @@ -248,6 +254,59 @@ function Invoke-Npm { Invoke-ProcessLogged -Name $Name -FilePath $NpmCmd -Arguments $Arguments -WorkingDirectory $WorkingDirectory } +function Start-NpmProcessLogged { + param( + [Parameter(Mandatory = $true)][string]$Name, + [Parameter(Mandatory = $true)][string[]]$Arguments, + [string]$WorkingDirectory = $Root + ) + + $logPath = Get-StepLogPath $Name + $runSuffix = ([DateTime]::UtcNow.ToString('yyyyMMddHHmmssfff')) + $stdoutPath = Join-Path $RunLogDir "$Name.$runSuffix.stdout.tmp" + $stderrPath = Join-Path $RunLogDir "$Name.$runSuffix.stderr.tmp" + + Write-Step $Name + Write-Host "Log: $logPath" + + Remove-Item -LiteralPath $stdoutPath, $stderrPath, $logPath -Force -ErrorAction SilentlyContinue + + $process = Start-Process -FilePath $NpmCmd ` + -ArgumentList $Arguments ` + -WorkingDirectory $WorkingDirectory ` + -RedirectStandardOutput $stdoutPath ` + -RedirectStandardError $stderrPath ` + -PassThru ` + -NoNewWindow + + return [PSCustomObject]@{ + Name = $Name + LogPath = $logPath + StdoutPath = $stdoutPath + StderrPath = $stderrPath + Process = $process + } +} + +function Complete-NpmProcessLogged { + param([Parameter(Mandatory = $true)]$ProcessInfo) + + $ProcessInfo.Process.WaitForExit() + + New-Item -ItemType File -Force -Path $ProcessInfo.LogPath | Out-Null + foreach ($path in @($ProcessInfo.StdoutPath, $ProcessInfo.StderrPath)) { + if (Test-Path $path) { + Get-Content -LiteralPath $path | Tee-Object -FilePath $ProcessInfo.LogPath -Append + } + } + + Remove-Item -LiteralPath $ProcessInfo.StdoutPath, $ProcessInfo.StderrPath -Force -ErrorAction SilentlyContinue + + if ($ProcessInfo.Process.ExitCode -ne 0) { + throw "Step '$($ProcessInfo.Name)' failed with exit code $($ProcessInfo.Process.ExitCode). See $($ProcessInfo.LogPath)" + } +} + function Repair-NpmDirectory { param( [string]$RelativeDirectory, @@ -430,12 +489,30 @@ function Rebuild-NativePackages { '@vscode/ripgrep' ) - foreach ($packageName in $nativePackages) { + $packagesToRebuild = @($nativePackages | Where-Object { Test-Path (Get-PackagePath -Prefix $Prefix -PackageName $_) }) + if ($NativePackageConcurrency -le 1) { + foreach ($packageName in $packagesToRebuild) { + $safeName = ($packageName -replace '[@/]', '_').Trim('_') + Invoke-Npm -Name "$LogPrefix-rebuild-$safeName" -Arguments @('rebuild', '--prefix', $Prefix, $packageName, '--foreground-scripts', "--jobs=$NativeJobs") + } + return + } + + $running = @() + foreach ($packageName in $packagesToRebuild) { if (Test-Path (Get-PackagePath -Prefix $Prefix -PackageName $packageName)) { $safeName = ($packageName -replace '[@/]', '_').Trim('_') - Invoke-Npm -Name "$LogPrefix-rebuild-$safeName" -Arguments @('rebuild', '--prefix', $Prefix, $packageName, '--foreground-scripts', '--jobs=1') + $running += Start-NpmProcessLogged -Name "$LogPrefix-rebuild-$safeName" -Arguments @('rebuild', '--prefix', $Prefix, $packageName, '--foreground-scripts', "--jobs=$NativeJobs") + if ($running.Count -ge $NativePackageConcurrency) { + Complete-NpmProcessLogged -ProcessInfo $running[0] + $running = @($running | Select-Object -Skip 1) + } } } + + foreach ($processInfo in $running) { + Complete-NpmProcessLogged -ProcessInfo $processInfo + } } function Install-NpmDirectory {