diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4bebe2..6ca6d51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,11 @@ jobs: shell: pwsh run: ./skills/scripts/test-bootstrap-supply-chain.ps1 + - name: Bootstrap supply-chain regression (Windows PowerShell 5.1) + if: runner.os == 'Windows' + shell: powershell + run: ./skills/scripts/test-bootstrap-supply-chain.ps1 + - name: Smoke (verify + parse + quick route) shell: pwsh run: ./skills/scripts/smoke.ps1 diff --git a/skills/scripts/lib/BootstrapSupplyChain.ps1 b/skills/scripts/lib/BootstrapSupplyChain.ps1 index 6e6c4c8..36dbd27 100644 --- a/skills/scripts/lib/BootstrapSupplyChain.ps1 +++ b/skills/scripts/lib/BootstrapSupplyChain.ps1 @@ -4,8 +4,17 @@ function Ensure-Pnpm { $pnpm = Get-NodeCommandPath -Name 'pnpm' $currentVersion = '' if ($pnpm) { - $versionLine = & $pnpm --version 2>$null | Select-Object -First 1 - if ($LASTEXITCODE -eq 0 -and $null -ne $versionLine) { + $previousErrorActionPreference = $ErrorActionPreference + try { + $ErrorActionPreference = 'Continue' + $versionOutput = @(& $pnpm --version 2>$null) + $versionExitCode = $LASTEXITCODE + } + finally { + $ErrorActionPreference = $previousErrorActionPreference + } + $versionLine = $versionOutput | Select-Object -First 1 + if ($versionExitCode -eq 0 -and $null -ne $versionLine) { $currentVersion = ([string]$versionLine).Trim() } } @@ -28,13 +37,29 @@ function Assert-GitCheckoutState { [Parameter(Mandatory = $true)][string]$PinnedCommit ) - $resolvedLine = & $GitPath -C $CheckoutPath rev-parse HEAD 2>$null | Select-Object -First 1 + $previousErrorActionPreference = $ErrorActionPreference + try { + $ErrorActionPreference = 'Continue' + $resolvedOutput = @(& $GitPath -C $CheckoutPath rev-parse HEAD 2>$null) + $resolveExitCode = $LASTEXITCODE + } + finally { + $ErrorActionPreference = $previousErrorActionPreference + } + $resolvedLine = $resolvedOutput | Select-Object -First 1 $resolvedCommit = if ($null -eq $resolvedLine) { '' } else { ([string]$resolvedLine).Trim() } - if ($LASTEXITCODE -ne 0 -or $resolvedCommit -ne $PinnedCommit) { + if ($resolveExitCode -ne 0 -or $resolvedCommit -ne $PinnedCommit) { throw "Checkout verification failed: expected $PinnedCommit, got $resolvedCommit ($CheckoutPath)" } - $status = @(& $GitPath -C $CheckoutPath status --porcelain --untracked-files=all 2>&1) - if ($LASTEXITCODE -ne 0) { + try { + $ErrorActionPreference = 'Continue' + $status = @(& $GitPath -C $CheckoutPath status --porcelain --untracked-files=all 2>$null) + $statusExitCode = $LASTEXITCODE + } + finally { + $ErrorActionPreference = $previousErrorActionPreference + } + if ($statusExitCode -ne 0) { throw "Cannot inspect checkout state: $CheckoutPath" } if ($status.Count -gt 0) { diff --git a/skills/scripts/test-bootstrap-supply-chain.ps1 b/skills/scripts/test-bootstrap-supply-chain.ps1 index a6723f8..0647a46 100644 --- a/skills/scripts/test-bootstrap-supply-chain.ps1 +++ b/skills/scripts/test-bootstrap-supply-chain.ps1 @@ -64,7 +64,7 @@ try { New-Item -ItemType Directory -Path $bin | Out-Null $env:PATH = "$bin$([IO.Path]::PathSeparator)$env:PATH" $env:BOOTSTRAP_PS_LOG = Join-Path $scratch 'commands.log' - $isWindowsHost = $env:OS -eq 'Windows_NT' + $isWindowsHost = [Environment]::OSVersion.Platform -eq [PlatformID]::Win32NT $stub = Join-Path $bin ($(if ($isWindowsHost) { 'npm.cmd' } else { 'npm' })) if ($isWindowsHost) { Set-Content $stub @' @@ -98,6 +98,10 @@ if "%1"=="--version" (echo 10.24.0) else (echo pnpm^|%*>>"%BOOTSTRAP_PS_LOG%") printf "pnpm|%s\n" "$*" >> "$BOOTSTRAP_PS_LOG" '@ } + $commandLogBefore = Get-Content -LiteralPath $env:BOOTSTRAP_PS_LOG -Raw + Ensure-Pnpm + $commandLogAfter = Get-Content -LiteralPath $env:BOOTSTRAP_PS_LOG -Raw + Assert-True ($commandLogAfter -eq $commandLogBefore) 'matching pnpm version triggered reinstall' function Approve-AnythingAnalyzerBuildScripts { param([string]$RepoDir) Set-Content (Join-Path $RepoDir 'pnpm-workspace.yaml') 'generated'; Set-Content (Join-Path $RepoDir 'package.json') '{"mutated":true}' } $dirtyRejected = $false try { Invoke-AnythingAnalyzerPinnedInstall -RepoDir $target -PnpmPath $pnpm -GitPath (Get-Command git).Source -PinnedCommit $pin } catch { $dirtyRejected = $_.Exception.Message -match 'local changes' }