265 lines
7.0 KiB
PowerShell
265 lines
7.0 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Local CI Runner for Windows
|
|
PowerShell wrapper for local-ci.sh
|
|
|
|
.DESCRIPTION
|
|
Unified local CI/CD testing runner for StellaOps on Windows.
|
|
This script wraps the Bash implementation via WSL2 or Git Bash.
|
|
|
|
.PARAMETER Mode
|
|
The testing mode to run:
|
|
- smoke : Quick smoke test (unit tests only, ~2 min)
|
|
- pr : Full PR-gating suite (all required checks, ~15 min)
|
|
- module : Module-specific tests (auto-detect or specified)
|
|
- workflow : Simulate specific workflow via act
|
|
- release : Release simulation (dry-run)
|
|
- full : All tests including extended categories (~45 min)
|
|
|
|
.PARAMETER Category
|
|
Specific test category to run (Unit, Architecture, Contract, Integration, Security, Golden)
|
|
|
|
.PARAMETER Module
|
|
Specific module to test (Scanner, Concelier, Authority, etc.)
|
|
|
|
.PARAMETER Workflow
|
|
Specific workflow to simulate (for workflow mode)
|
|
|
|
.PARAMETER Docker
|
|
Force Docker execution mode
|
|
|
|
.PARAMETER Native
|
|
Force native execution mode
|
|
|
|
.PARAMETER Act
|
|
Force act execution mode
|
|
|
|
.PARAMETER Parallel
|
|
Number of parallel test runners (default: auto-detect)
|
|
|
|
.PARAMETER Verbose
|
|
Enable verbose output
|
|
|
|
.PARAMETER DryRun
|
|
Show what would run without executing
|
|
|
|
.PARAMETER Rebuild
|
|
Force rebuild of CI Docker image
|
|
|
|
.PARAMETER NoServices
|
|
Skip starting CI services
|
|
|
|
.PARAMETER KeepServices
|
|
Don't stop services after tests
|
|
|
|
.EXAMPLE
|
|
.\local-ci.ps1 smoke
|
|
Quick validation before push
|
|
|
|
.EXAMPLE
|
|
.\local-ci.ps1 pr
|
|
Full PR check
|
|
|
|
.EXAMPLE
|
|
.\local-ci.ps1 module -Module Scanner
|
|
Test specific module
|
|
|
|
.EXAMPLE
|
|
.\local-ci.ps1 workflow -Workflow test-matrix
|
|
Simulate specific workflow
|
|
|
|
.NOTES
|
|
Requires WSL2 or Git Bash to execute the underlying Bash script.
|
|
For full feature support, use WSL2 with Ubuntu.
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Position = 0)]
|
|
[ValidateSet('smoke', 'pr', 'module', 'workflow', 'release', 'full')]
|
|
[string]$Mode = 'smoke',
|
|
|
|
[string]$Category,
|
|
[string]$Module,
|
|
[string]$Workflow,
|
|
|
|
[switch]$Docker,
|
|
[switch]$Native,
|
|
[switch]$Act,
|
|
|
|
[int]$Parallel,
|
|
|
|
[switch]$Verbose,
|
|
[switch]$DryRun,
|
|
[switch]$Rebuild,
|
|
[switch]$NoServices,
|
|
[switch]$KeepServices,
|
|
|
|
[switch]$Help
|
|
)
|
|
|
|
# Script location
|
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$RepoRoot = Split-Path -Parent (Split-Path -Parent $ScriptDir)
|
|
|
|
# Show help if requested
|
|
if ($Help) {
|
|
Get-Help $MyInvocation.MyCommand.Path -Detailed
|
|
exit 0
|
|
}
|
|
|
|
function Write-ColoredOutput {
|
|
param(
|
|
[string]$Message,
|
|
[ConsoleColor]$Color = [ConsoleColor]::White
|
|
)
|
|
$originalColor = $Host.UI.RawUI.ForegroundColor
|
|
$Host.UI.RawUI.ForegroundColor = $Color
|
|
Write-Host $Message
|
|
$Host.UI.RawUI.ForegroundColor = $originalColor
|
|
}
|
|
|
|
function Write-Info { Write-ColoredOutput "[INFO] $args" -Color Cyan }
|
|
function Write-Success { Write-ColoredOutput "[OK] $args" -Color Green }
|
|
function Write-Warning { Write-ColoredOutput "[WARN] $args" -Color Yellow }
|
|
function Write-Error { Write-ColoredOutput "[ERROR] $args" -Color Red }
|
|
|
|
# Find Bash executable
|
|
function Find-BashExecutable {
|
|
# Priority: WSL2 > Git Bash > Windows Subsystem for Linux (legacy)
|
|
|
|
# Check for WSL
|
|
$wsl = Get-Command wsl -ErrorAction SilentlyContinue
|
|
if ($wsl) {
|
|
# Verify WSL is working
|
|
$wslCheck = & wsl --status 2>&1
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Info "Using WSL2 for Bash execution"
|
|
return @{ Type = 'wsl'; Path = 'wsl' }
|
|
}
|
|
}
|
|
|
|
# Check for Git Bash
|
|
$gitBashPaths = @(
|
|
"C:\Program Files\Git\bin\bash.exe",
|
|
"C:\Program Files (x86)\Git\bin\bash.exe",
|
|
"$env:LOCALAPPDATA\Programs\Git\bin\bash.exe"
|
|
)
|
|
|
|
foreach ($path in $gitBashPaths) {
|
|
if (Test-Path $path) {
|
|
Write-Info "Using Git Bash for execution"
|
|
return @{ Type = 'gitbash'; Path = $path }
|
|
}
|
|
}
|
|
|
|
# Check PATH for bash
|
|
$bashInPath = Get-Command bash -ErrorAction SilentlyContinue
|
|
if ($bashInPath) {
|
|
Write-Info "Using Bash from PATH"
|
|
return @{ Type = 'path'; Path = $bashInPath.Source }
|
|
}
|
|
|
|
return $null
|
|
}
|
|
|
|
# Convert Windows path to Unix path for WSL
|
|
function Convert-ToUnixPath {
|
|
param([string]$WindowsPath)
|
|
|
|
if ($WindowsPath -match '^([A-Za-z]):(.*)$') {
|
|
$drive = $Matches[1].ToLower()
|
|
$rest = $Matches[2] -replace '\\', '/'
|
|
return "/mnt/$drive$rest"
|
|
}
|
|
return $WindowsPath -replace '\\', '/'
|
|
}
|
|
|
|
# Build argument list
|
|
function Build-Arguments {
|
|
$args = @($Mode)
|
|
|
|
if ($Category) { $args += "--category"; $args += $Category }
|
|
if ($Module) { $args += "--module"; $args += $Module }
|
|
if ($Workflow) { $args += "--workflow"; $args += $Workflow }
|
|
if ($Docker) { $args += "--docker" }
|
|
if ($Native) { $args += "--native" }
|
|
if ($Act) { $args += "--act" }
|
|
if ($Parallel) { $args += "--parallel"; $args += $Parallel }
|
|
if ($Verbose) { $args += "--verbose" }
|
|
if ($DryRun) { $args += "--dry-run" }
|
|
if ($Rebuild) { $args += "--rebuild" }
|
|
if ($NoServices) { $args += "--no-services" }
|
|
if ($KeepServices) { $args += "--keep-services" }
|
|
|
|
return $args
|
|
}
|
|
|
|
# Main execution
|
|
Write-Host ""
|
|
Write-Host "=========================================" -ForegroundColor Magenta
|
|
Write-Host " StellaOps Local CI Runner (Windows) " -ForegroundColor Magenta
|
|
Write-Host "=========================================" -ForegroundColor Magenta
|
|
Write-Host ""
|
|
|
|
# Find Bash
|
|
$bash = Find-BashExecutable
|
|
if (-not $bash) {
|
|
Write-Error "Bash not found. Please install one of the following:"
|
|
Write-Host " - WSL2: https://docs.microsoft.com/en-us/windows/wsl/install"
|
|
Write-Host " - Git for Windows: https://git-scm.com/download/win"
|
|
exit 1
|
|
}
|
|
|
|
# Build script path
|
|
$scriptPath = Join-Path $ScriptDir "local-ci.sh"
|
|
if (-not (Test-Path $scriptPath)) {
|
|
Write-Error "Script not found: $scriptPath"
|
|
exit 1
|
|
}
|
|
|
|
# Build arguments
|
|
$bashArgs = Build-Arguments
|
|
|
|
Write-Info "Mode: $Mode"
|
|
Write-Info "Bash: $($bash.Type)"
|
|
Write-Info "Repository: $RepoRoot"
|
|
Write-Host ""
|
|
|
|
# Execute based on Bash type
|
|
try {
|
|
switch ($bash.Type) {
|
|
'wsl' {
|
|
$unixScript = Convert-ToUnixPath $scriptPath
|
|
Write-Info "Executing: wsl bash $unixScript $($bashArgs -join ' ')"
|
|
& wsl bash $unixScript @bashArgs
|
|
}
|
|
'gitbash' {
|
|
# Git Bash uses its own path conversion
|
|
$unixScript = $scriptPath -replace '\\', '/'
|
|
Write-Info "Executing: $($bash.Path) $unixScript $($bashArgs -join ' ')"
|
|
& $bash.Path $unixScript @bashArgs
|
|
}
|
|
'path' {
|
|
Write-Info "Executing: bash $scriptPath $($bashArgs -join ' ')"
|
|
& bash $scriptPath @bashArgs
|
|
}
|
|
}
|
|
|
|
$exitCode = $LASTEXITCODE
|
|
}
|
|
catch {
|
|
Write-Error "Execution failed: $_"
|
|
$exitCode = 1
|
|
}
|
|
|
|
# Report result
|
|
Write-Host ""
|
|
if ($exitCode -eq 0) {
|
|
Write-Success "Local CI completed successfully!"
|
|
} else {
|
|
Write-Error "Local CI failed with exit code: $exitCode"
|
|
}
|
|
|
|
exit $exitCode
|