Payload/scripts/kaden/harness/quality-gate/Invoke-RepositoryQualityPrePush.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Pre-push gate: reuse or re-run comprehensive Pester via the quality decision port. .DESCRIPTION Asks Invoke-RepositoryQualityDecision (evaluate-check comprehensive-pester) whether local ledger evidence is reusable for the paths in the push range. When the decision rejects reuse, runs tests/harness/run-harness-tests.ps1 and writes .harness/quality-gate/comprehensive-pester.json on success. Commit stays fast (PSA only). This script is for pre-push / npm run quality:pre-push. .PARAMETER Force Always run the Pester suite and refresh the ledger. .PARAMETER DryDecision Print the evaluate-check decision and exit without running Pester. .PARAMETER UpstreamRef Optional git revision range (e.g. origin/main..HEAD). Default: @{upstream}..HEAD. .PARAMETER RepoRoot Repository root (defaults to discovery from this script). .EXAMPLE pwsh -File scripts/kaden/harness/quality-gate/Invoke-RepositoryQualityPrePush.ps1 .EXAMPLE pwsh -File scripts/kaden/harness/quality-gate/Invoke-RepositoryQualityPrePush.ps1 -DryDecision #> [CmdletBinding()] param( [switch]$Force, [switch]$DryDecision, [string]$UpstreamRef = '', [string]$RepoRoot = '' ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $gateDir = $PSScriptRoot Import-Module (Join-Path $gateDir 'RepositoryQualityGate.psm1') -Force Import-Module (Join-Path $gateDir 'RepositoryQualityPrePush.psm1') -Force if ([string]::IsNullOrWhiteSpace($RepoRoot)) { $RepoRoot = Get-RepositoryQualityRepoRoot -StartPath $gateDir } $requestedAt = [datetime]::UtcNow $head = Get-RepositoryQualityHeadRevision -RepoRoot $RepoRoot $targets = @(Get-RepositoryQualityPesterTargetSet -RepoRoot $RepoRoot) $changed = @(Get-RepositoryQualityPushChangedPath -RepoRoot $RepoRoot -UpstreamRef $UpstreamRef) $prior = Read-RepositoryQualityPesterEvidence -RepoRoot $RepoRoot Write-Output "[quality:pre-push] HEAD=$head" Write-Output "[quality:pre-push] changed_paths=$($changed.Count) pester_targets=$($targets.Count)" if ($changed.Count -gt 0) { $preview = @($changed | Select-Object -First 12) -join ', ' Write-Output "[quality:pre-push] sample: $preview" } $evidence = New-RepositoryQualityPesterCheckEvidence ` -CurrentTargetSet $targets ` -ChangedPaths $changed ` -RequestedAt $requestedAt ` -ProtectedRevision $head ` -PriorEvidence $prior $decision = $null $mustRun = [bool]$Force if (-not $mustRun) { if ($null -eq $prior -or $null -eq $prior.CompletedAt) { $mustRun = $true Write-Output '[quality:pre-push] no local comprehensive-pester ledger; Pester required' } else { $decision = Test-RepositoryQualityPesterReuse -CheckEvidence $evidence Write-Output ("[quality:pre-push] decision CheckAccepted={0} EvidenceClass={1} Freshness={2} RequiredRun={3}" -f ` $decision.CheckAccepted, $decision.EvidenceClass, $decision.Freshness, $decision.RequiredRun) if ($decision.Reasons) { Write-Output ("[quality:pre-push] reasons: {0}" -f (($decision.Reasons | ForEach-Object { [string]$_ }) -join ', ')) } if (-not $decision.CheckAccepted) { $mustRun = $true } } } if ($DryDecision) { if ($mustRun) { Write-Output '[quality:pre-push] DryDecision: would run Pester' exit 0 } Write-Output '[quality:pre-push] DryDecision: would reuse evidence (skip Pester)' exit 0 } if (-not $mustRun) { Write-Output '[quality:pre-push] reusing comprehensive-pester evidence; Pester skipped' exit 0 } $runner = Join-Path $RepoRoot (Join-Path 'tests' (Join-Path 'harness' 'run-harness-tests.ps1')) Write-Output "[quality:pre-push] running $runner" $hostPath = $null try { Import-Module (Join-Path (Join-Path (Join-Path (Join-Path $RepoRoot 'scripts') 'kaden') 'harness') 'lib\HarnessContract.psm1') -Force -ErrorAction SilentlyContinue if (Get-Command Get-HarnessPowerShellExePath -ErrorAction SilentlyContinue) { $hostPath = Get-HarnessPowerShellExePath } } catch { $hostPath = $null } if ([string]::IsNullOrWhiteSpace($hostPath)) { $pwshCmd = Get-Command pwsh -ErrorAction SilentlyContinue if ($pwshCmd) { $hostPath = $pwshCmd.Source } else { $hostPath = (Get-Command powershell.exe -ErrorAction Stop).Source } } $proc = Start-Process -FilePath $hostPath -ArgumentList @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $runner) ` -WorkingDirectory $RepoRoot -Wait -PassThru -NoNewWindow $code = 1 if ($null -ne $proc -and $null -ne $proc.ExitCode) { $code = [int]$proc.ExitCode } if ($code -ne 0) { Write-Error "[quality:pre-push] Pester suite failed (exit $code); push blocked" exit $code } $completedAt = [datetime]::UtcNow $ledger = Write-RepositoryQualityPesterEvidence -RepoRoot $RepoRoot -TargetSet $targets ` -CompletedAt $completedAt -ProtectedRevision $head -FailedCount 0 Write-Output "[quality:pre-push] wrote evidence $ledger" exit 0 |