fix(release): unlock rolldown before npm ci in prepare-release

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-08-03 14:17:37 +08:00
parent c46ff34393
commit 10cbb3b256
+65 -2
View File
@@ -51,6 +51,62 @@ function Test-IsNpmCi([string[]]$NpmArgs) {
return ($NpmArgs.Count -eq 1 -and $NpmArgs[0] -eq 'ci')
}
# Stops Vite/Electron/dev.mjs/TTRPGPlayer that lock native .node files under node_modules
# (typical EPERM unlink on @rolldown/binding-win32-x64-msvc during npm ci).
function Stop-DndPlayerLocks {
param([string]$ProjectRoot)
Write-Host ' Stopping processes that may lock node_modules...'
$killed = [System.Collections.Generic.HashSet[int]]::new()
foreach ($name in @('TTRPGPlayer', 'electron')) {
Get-Process -Name $name -ErrorAction SilentlyContinue | ForEach-Object {
Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue
[void]$killed.Add([int]$_.Id)
}
}
Get-CimInstance Win32_Process -Filter "Name='node.exe'" -ErrorAction SilentlyContinue | ForEach-Object {
$cmd = [string]$_.CommandLine
if (-not $cmd) { return }
$touches = ($cmd -match [regex]::Escape($ProjectRoot)) -or ($cmd -match 'dnd_player')
if (-not $touches) { return }
if ($cmd -match 'dev\.mjs|vite|electron|esbuild|rolldown|tsx|scripts[/\\]dev') {
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
[void]$killed.Add([int]$_.ProcessId)
}
}
foreach ($port in @(5173, 5174)) {
try {
Get-NetTCPConnection -LocalPort $port -ErrorAction Stop | ForEach-Object {
$ownerPid = [int]$_.OwningProcess
if ($ownerPid -gt 0) {
Stop-Process -Id $ownerPid -Force -ErrorAction SilentlyContinue
[void]$killed.Add($ownerPid)
}
}
} catch {
# NetTCPIP may be unavailable in some shells — ignore
}
}
Start-Sleep -Seconds 2
$rolldownDir = Join-Path $ProjectRoot 'node_modules\@rolldown\binding-win32-x64-msvc'
if (Test-Path -LiteralPath $rolldownDir) {
try {
Remove-Item -LiteralPath $rolldownDir -Recurse -Force -ErrorAction Stop
Write-Host ' [OK] removed locked @rolldown/binding-win32-x64-msvc (npm ci will restore)'
} catch {
Write-Host " [--] rolldown binding still locked: $($_.Exception.Message)" -ForegroundColor Yellow
}
}
Write-Host " Cleared $($killed.Count) process id(s); waiting for file unlock"
Start-Sleep -Seconds 1
}
function Invoke-NpmRaw {
param(
[string[]]$NpmArgs,
@@ -101,8 +157,14 @@ function Invoke-Npm {
Write-Host " > $Label"
$exitCode = Invoke-NpmRaw -NpmArgs $NpmArgs -WorkingDirectory $WorkingDirectory
if ($exitCode -ne 0 -and (Test-IsNpmCi $NpmArgs)) {
Write-Host " [--] npm ci failed (exit $exitCode). Retrying via ffmpeg-static mirror..." -ForegroundColor Yellow
$exitCode = Invoke-NpmCiWithFfmpegMirror $WorkingDirectory
Write-Host " [--] npm ci failed (exit $exitCode). Clearing locks and retrying..." -ForegroundColor Yellow
Stop-DndPlayerLocks $WorkingDirectory
$exitCode = Invoke-NpmRaw -NpmArgs $NpmArgs -WorkingDirectory $WorkingDirectory
if ($exitCode -ne 0) {
Write-Host " [--] npm ci failed again. Retrying via ffmpeg-static mirror..." -ForegroundColor Yellow
Stop-DndPlayerLocks $WorkingDirectory
$exitCode = Invoke-NpmCiWithFfmpegMirror $WorkingDirectory
}
}
if ($exitCode -ne 0) {
throw "$Label failed (exit $exitCode)"
@@ -418,6 +480,7 @@ if ($SkipGit) {
# Step 3 - Windows build
Write-Step 3 'Build Windows (npm ci + pack:win)'
Stop-DndPlayerLocks $projectRoot
Invoke-Npm 'npm ci' @('ci') $projectRoot
Invoke-Npm 'npm run pack:win' @('run', 'pack:win') $projectRoot
Write-Ok 'Windows build finished'