Public/Test-CCGitHub.ps1
|
function Test-CCGitHub { <# .SYNOPSIS Runs all GitHub configuration compliance checks. .DESCRIPTION Orchestrates all GitHub checks: branch protection, security, settings, and collaboration. Returns structured results suitable for CI pipelines. .PARAMETER Repository GitHub repository in format "owner/repo". Auto-detected from git remote if not specified. .PARAMETER Token GitHub token. Falls back to GITHUB_TOKEN, GH_TOKEN, or gh CLI. .PARAMETER Standard Standard tier: core, active, minimal. Default: core. .PARAMETER Config Path to per-repo config file (.codecompass/config.yml or .repo-health.yml). .PARAMETER FailOn Fail with exit code 1 if any check reaches this severity: Error, Warning, or None (never fail). .PARAMETER OutputFormat Output format: Console (default), Json, or Quiet (exit code only). .PARAMETER Detailed Show detailed per-check output in console mode. .PARAMETER Categories Run only specific categories. Default: all. .OUTPUTS [PSCustomObject[]] Array of all check results. .EXAMPLE Test-CCGitHub # Audits current repo using 'core' standard .EXAMPLE Test-CCGitHub -Repository 'The-Code-Kitchen/LeadForge' -Standard active .EXAMPLE Test-CCGitHub -Standard core -FailOn Error -OutputFormat Json # CI mode — JSON output, exit 1 on errors #> [CmdletBinding()] [OutputType([PSCustomObject[]])] param( [Parameter()] [string]$Repository, [Parameter()] [string]$Token, [Parameter()] [ValidateSet('core', 'active', 'minimal')] [string]$Standard = 'core', [Parameter()] [string]$Config, [Parameter()] [ValidateSet('Error', 'Warning', 'None')] [string]$FailOn = 'None', [Parameter()] [ValidateSet('Console', 'Json', 'Quiet')] [string]$OutputFormat = 'Console', [Parameter()] [switch]$Detailed, [Parameter()] [ValidateSet('BranchProtection', 'Security', 'Settings', 'Collaboration')] [string[]]$Categories ) $allResults = [System.Collections.ArrayList]::new() # Resolve common params $token = Resolve-CCToken -Token $Token if (-not $token) { throw "No GitHub token available. Set GITHUB_TOKEN, GH_TOKEN, or run 'gh auth login'." } $repo = Resolve-CCRepository -Repository $Repository if (-not $repo) { throw "Cannot determine repository. Specify -Repository 'owner/repo'." } # Auto-detect config if not specified if (-not $Config) { $candidates = @('.codecompass/config.yml', '.codecompass/config.yaml', '.repo-health.yml') foreach ($candidate in $candidates) { if (Test-Path $candidate) { $Config = $candidate; break } } } $commonParams = @{ Repository = $repo Token = $token Standard = $Standard } if ($Config) { $commonParams['Config'] = $Config } # Console header if ($OutputFormat -eq 'Console') { Write-Host "" Write-Host " CodeCompass.GitHub Audit" -ForegroundColor Cyan Write-Host " Repository: $repo" -ForegroundColor Gray Write-Host " Standard: $Standard" -ForegroundColor Gray Write-Host "" } # Run checks by category $categoriesToRun = if ($Categories) { $Categories } else { @('BranchProtection', 'Security', 'Settings', 'Collaboration') } if ('BranchProtection' -in $categoriesToRun) { if ($OutputFormat -eq 'Console') { Write-Host " Branch Protection" -ForegroundColor Yellow } $bpResults = Test-CCBranchProtection @commonParams if ($bpResults) { $bpResults | ForEach-Object { [void]$allResults.Add($_) } } if ($OutputFormat -eq 'Console') { Write-CCCategoryConsole -Results $bpResults -Detailed:$Detailed } } if ('Security' -in $categoriesToRun) { if ($OutputFormat -eq 'Console') { Write-Host " Security" -ForegroundColor Yellow } $secResults = Test-CCSecurityConfig @commonParams if ($secResults) { $secResults | ForEach-Object { [void]$allResults.Add($_) } } if ($OutputFormat -eq 'Console') { Write-CCCategoryConsole -Results $secResults -Detailed:$Detailed } } if ('Settings' -in $categoriesToRun) { if ($OutputFormat -eq 'Console') { Write-Host " Repository Settings" -ForegroundColor Yellow } $setResults = Test-CCRepoSettings @commonParams if ($setResults) { $setResults | ForEach-Object { [void]$allResults.Add($_) } } if ($OutputFormat -eq 'Console') { Write-CCCategoryConsole -Results $setResults -Detailed:$Detailed } } if ('Collaboration' -in $categoriesToRun) { if ($OutputFormat -eq 'Console') { Write-Host " Collaboration" -ForegroundColor Yellow } $colResults = Test-CCCollaboration @commonParams if ($colResults) { $colResults | ForEach-Object { [void]$allResults.Add($_) } } if ($OutputFormat -eq 'Console') { Write-CCCategoryConsole -Results $colResults -Detailed:$Detailed } } # Summary $passed = @($allResults | Where-Object Status -eq 'Pass').Count $failed = @($allResults | Where-Object Status -eq 'Fail').Count $warnings = @($allResults | Where-Object Status -eq 'Warning').Count $skipped = @($allResults | Where-Object Status -eq 'Skipped').Count if ($OutputFormat -eq 'Console') { Write-Host "" Write-Host " ─────────────────────────────────────────" -ForegroundColor Gray $summaryColor = if ($failed -gt 0) { 'Red' } elseif ($warnings -gt 0) { 'Yellow' } else { 'Green' } Write-Host " Pass: $passed | Fail: $failed | Warning: $warnings | Skipped: $skipped" -ForegroundColor $summaryColor if ($failed -eq 0 -and $warnings -eq 0) { Write-Host " All checks passed!" -ForegroundColor Green } elseif ($failed -gt 0) { Write-Host " Repository has configuration issues." -ForegroundColor Red Write-Host " Run Repair-CCGitHub to auto-fix available issues." -ForegroundColor Gray } Write-Host "" } elseif ($OutputFormat -eq 'Json') { $output = [PSCustomObject]@{ repository = $repo standard = $Standard timestamp = (Get-Date -Format 'o') summary = [PSCustomObject]@{ pass = $passed; fail = $failed; warning = $warnings; skipped = $skipped } results = $allResults.ToArray() } $output | ConvertTo-Json -Depth 5 } # FailOn logic if ($FailOn -eq 'Error' -and $failed -gt 0) { $host.SetShouldExit(1) exit 1 } elseif ($FailOn -eq 'Warning' -and ($failed -gt 0 -or $warnings -gt 0)) { $host.SetShouldExit(1) exit 1 } return $allResults.ToArray() } function Write-CCCategoryConsole { <# .SYNOPSIS Writes per-category results to console. #> param( [PSCustomObject[]]$Results, [switch]$Detailed ) if (-not $Results -or $Results.Count -eq 0) { Write-Host " (no checks)" -ForegroundColor Gray return } if ($Detailed) { foreach ($r in $Results) { $icon = switch ($r.Status) { 'Pass' { ' +' } 'Fail' { ' x' } 'Warning' { ' !' } 'Skipped' { ' -' } } $color = switch ($r.Status) { 'Pass' { 'Green' } 'Fail' { 'Red' } 'Warning' { 'Yellow' } 'Skipped' { 'Gray' } } Write-Host " $icon [$($r.CheckId)] $($r.Message)" -ForegroundColor $color } } else { $p = @($Results | Where-Object Status -eq 'Pass').Count $f = @($Results | Where-Object Status -eq 'Fail').Count $w = @($Results | Where-Object Status -eq 'Warning').Count $color = if ($f -gt 0) { 'Red' } elseif ($w -gt 0) { 'Yellow' } else { 'Green' } Write-Host " Pass: $p | Fail: $f | Warning: $w" -ForegroundColor $color } Write-Host "" } |