Private/GitHub/Get-CgrGitHubPagesPlanEvidence.ps1
|
function Get-CgrGitHubPagesPlanEvidence { <# .SYNOPSIS Captures immutable GitHub Pages evidence for migration planning. .DESCRIPTION Reads source GitHub-side Pages configuration only when Pages restoration was requested. The returned object separates transferable configuration from external/asynchronous readiness evidence and records whether the exact reviewed configuration is representable under the selected Git-content mode. #> [CmdletBinding()] param( [Parameter(Mandatory)] [psobject] $Repository, [Parameter(Mandatory)] [ValidateSet('Snapshot', 'FullHistory')] [string] $ContentMode, [Parameter(Mandatory)] [psobject] $SourceState, [ValidateNotNullOrEmpty()] [string] $HostName = 'github.com' ) $result = Invoke-CgrGitHubApiReadRequest ` -ArgumentList @('api', '--hostname', $HostName, "repos/$($Repository.FullName)/pages") if ($result.ExitCode -ne 0) { if ([string] $result.ErrorText -match '(?i)404|not found') { return [pscustomobject] @{ PSTypeName = 'CopyGitHubRepo.GitHubPagesPlanEvidence' SchemaVersion = 1 Status = 'NotConfigured' Configured = $false BuildType = $null Source = $null CustomDomain = $null HttpsEnforced = $null Representability = [pscustomobject] @{ Status = 'NotApplicable' IsRepresentable = $true Reason = 'Source Pages is not configured.' } ExternalReadiness = [pscustomobject] @{ DomainVerification = 'NotApplicable' Certificate = 'NotApplicable' Dns = 'ExternalNotQueried' } DriftEvidence = [pscustomobject] @{ Configured = $false BuildType = $null Branch = $null Path = $null CustomDomain = $null HttpsEnforced = $null } CapturedAtUtc = [DateTimeOffset]::UtcNow.ToString('o') } } $diagnostic = Protect-CgrDiagnosticText -Text ([string] $result.ErrorText) $message = "GitHub CLI failed to read Pages configuration for '$($Repository.FullName)'. $diagnostic" $exception = [System.InvalidOperationException]::new($message.Trim()) $errorRecord = [System.Management.Automation.ErrorRecord]::new( $exception, 'SourceGitHubPagesReadFailed', [System.Management.Automation.ErrorCategory]::ReadError, $Repository.FullName ) $PSCmdlet.ThrowTerminatingError($errorRecord) } $json = ($result.Output | ForEach-Object { [string] $_ }) -join "`n" if ([string]::IsNullOrWhiteSpace($json)) { $exception = [System.InvalidOperationException]::new("GitHub returned an empty Pages response for '$($Repository.FullName)'.") $errorRecord = [System.Management.Automation.ErrorRecord]::new( $exception, 'SourceGitHubPagesResponseEmpty', [System.Management.Automation.ErrorCategory]::InvalidData, $Repository.FullName ) $PSCmdlet.ThrowTerminatingError($errorRecord) } $pages = $json | ConvertFrom-Json -Depth 100 $buildType = [string] (Get-CgrObjectProperty -InputObject $pages -Name 'build_type') $sourceObject = Get-CgrObjectProperty -InputObject $pages -Name 'source' $branch = if ($sourceObject) { [string] (Get-CgrObjectProperty -InputObject $sourceObject -Name 'branch') } else { $null } $path = if ($sourceObject) { [string] (Get-CgrObjectProperty -InputObject $sourceObject -Name 'path') } else { $null } $customDomain = Get-CgrObjectProperty -InputObject $pages -Name 'cname' $httpsEnforced = Get-CgrObjectProperty -InputObject $pages -Name 'https_enforced' $protectedDomainState = Get-CgrObjectProperty -InputObject $pages -Name 'protected_domain_state' $pendingDomainUnverifiedAt = Get-CgrObjectProperty -InputObject $pages -Name 'pending_domain_unverified_at' $httpsCertificate = Get-CgrObjectProperty -InputObject $pages -Name 'https_certificate' $representable = $true $representabilityStatus = 'Supported' $representabilityReason = 'The reviewed Pages configuration is representable under the selected content mode.' switch ($buildType) { 'workflow' { } 'legacy' { if ([string]::IsNullOrWhiteSpace($branch) -or $path -notin @('/', '/docs')) { $representable = $false $representabilityStatus = 'Unsupported' $representabilityReason = 'Branch/path Pages requires an exact publishing branch and a supported source path of / or /docs.' break } $branchAvailable = if ($ContentMode -eq 'Snapshot') { $branch -eq [string] (Get-CgrObjectProperty -InputObject $SourceState -Name 'DefaultBranch') } else { $approvedRefs = @(Get-CgrObjectProperty -InputObject $SourceState -Name 'Refs') @($approvedRefs | Where-Object { [string] $_ -match "^refs/heads/$([regex]::Escape($branch))(?:\s|$)" }).Count -gt 0 } if (-not $branchAvailable) { $representable = $false $representabilityStatus = 'Unrepresentable' $representabilityReason = "Reviewed Pages publishing branch '$branch' is not preserved by the selected $ContentMode content plan." } } default { $representable = $false $representabilityStatus = 'Unsupported' $representabilityReason = "GitHub Pages build type '$buildType' is not supported by the migration contract." } } [pscustomobject] @{ PSTypeName = 'CopyGitHubRepo.GitHubPagesPlanEvidence' SchemaVersion = 1 Status = if ($representable) { 'Configured' } else { $representabilityStatus } Configured = $true BuildType = $buildType Source = if ($buildType -eq 'legacy') { [pscustomobject] @{ Branch = $branch Path = $path } } else { $null } CustomDomain = if ([string]::IsNullOrWhiteSpace([string] $customDomain)) { $null } else { [string] $customDomain } HttpsEnforced = if ($null -eq $httpsEnforced) { $null } else { [bool] $httpsEnforced } Representability = [pscustomobject] @{ Status = $representabilityStatus IsRepresentable = $representable Reason = $representabilityReason } ExternalReadiness = [pscustomobject] @{ DomainVerification = if ($null -ne $protectedDomainState) { [string] $protectedDomainState } elseif ($null -ne $pendingDomainUnverifiedAt) { 'Pending' } else { 'NotReportedByGitHub' } PendingDomainUnverifiedAt = $pendingDomainUnverifiedAt Certificate = if ($null -ne $httpsCertificate) { $httpsCertificate } else { 'NotReportedByGitHub' } Dns = 'ExternalNotQueried' } DriftEvidence = [pscustomobject] @{ Configured = $true BuildType = $buildType Branch = $branch Path = $path CustomDomain = if ([string]::IsNullOrWhiteSpace([string] $customDomain)) { $null } else { [string] $customDomain } HttpsEnforced = if ($null -eq $httpsEnforced) { $null } else { [bool] $httpsEnforced } } CapturedAtUtc = [DateTimeOffset]::UtcNow.ToString('o') } } |