Private/Wizard/Invoke-CgrRepositoryCopyWizard.ps1
|
function Invoke-CgrRepositoryCopyWizard { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $HostName, [Parameter(Mandatory)] [scriptblock] $ExecutionGuard ) $cancelResult = { [pscustomobject] @{ PSTypeName = 'CopyGitHubRepo.WizardResult' Status = 'Cancelled' MutatedGitHub = $false } } $readOptionalReleaseValue = { param( [Parameter(Mandatory)] [string] $Prompt, [AllowEmptyString()] [string] $CurrentValue, [switch] $PositiveInteger ) while ($true) { Write-CgrWizardMessage Write-CgrWizardMessage -Message 'Press Enter to keep the current value. Enter - to clear it.' -Style Hint $inputText = Read-CgrWizardInput ` -Prompt $Prompt ` -DefaultValue $CurrentValue ` -AllowBack ` -AllowCancel $navigation = Resolve-CgrWizardNavigationInput ` -InputText $inputText ` -AllowBack ` -AllowNext ` -AllowCancel if ($null -ne $navigation) { if ($navigation.Action -eq 'Next') { $navigation.Value = $CurrentValue } return $navigation } $candidate = $inputText.Trim() if ($candidate -eq '-') { return ConvertTo-CgrWizardNavigationResult -Action Next -Value '' } if (-not $PositiveInteger) { return ConvertTo-CgrWizardNavigationResult -Action Next -Value $candidate } $count = 0 if ([int]::TryParse($candidate, [ref] $count) -and $count -gt 0) { return ConvertTo-CgrWizardNavigationResult -Action Next -Value $candidate } Write-CgrWizardMessage -Message 'Enter a positive whole number, -, Back, or Cancel.' -Status Warning } } Write-CgrWizardMessage -Message 'Copy GitHub Repository' -Style Heading Write-CgrWizardMessage -Message 'Discovering repositories and checking GitHub CLI access...' -Style Hint $repositories = @(Get-GitHubRepository -HostName $HostName) $sourceRepository = $null $destinationRepository = $null $contentMode = 'Snapshot' $commitMessage = 'Initial repository commit' $destinationVisibility = $null $settingsBehavior = 'Restore' $restorePages = $false $archiveRepositoryName = $null $sameNameConfirmation = $null $existingDestinationArchiveName = $null $existingDestinationConfirmation = $null $snapshotReleaseOptions = [pscustomobject] @{ IncludeReleases = $false ReleaseTag = '' ReleaseExcludeTag = '' IncludePrerelease = $false IncludeDraftReleases = $false ReleaseCount = '' } $step = 0 while ($true) { switch ($step) { 0 { $result = Select-CgrWizardRepository -Repositories $repositories -CurrentValue $sourceRepository -AllowCancel if ($result.Action -eq 'Cancel') { return & $cancelResult } $previousSource = $sourceRepository $sourceRepository = $result.Value if ($null -eq $sourceRepository) { continue } if ($null -eq $previousSource -or $previousSource.FullName -ne $sourceRepository.FullName) { $destinationVisibility = $null $archiveRepositoryName = $null $sameNameConfirmation = $null $existingDestinationArchiveName = $null $existingDestinationConfirmation = $null } $step = 1 } 1 { $result = Resolve-CgrWizardDestinationRepository -Repositories $repositories -CurrentValue $destinationRepository -AllowBack -AllowCancel if ($result.Action -eq 'Cancel') { return & $cancelResult } if ($result.Action -eq 'Back') { $step = 0; continue } if ($destinationRepository -ne $result.Value) { $destinationRepository = [string] $result.Value $archiveRepositoryName = $null $sameNameConfirmation = $null $existingDestinationArchiveName = $null $existingDestinationConfirmation = $null } if ($destinationRepository -ne $sourceRepository.FullName -and (Test-CgrGitHubRepositoryExistence -Repository $destinationRepository -HostName $HostName)) { Write-CgrWizardMessage -Message "Destination '$destinationRepository' already exists." -Status Warning $conflictResult = Read-CgrWizardChoice ` -Title 'Existing destination' ` -Choices @('Choose another destination', 'Archive and replace existing destination', 'Cancel') ` -DefaultValue 'Choose another destination' ` -HelpTopic ExistingDestination ` -AllowBack ` -AllowCancel if ($conflictResult.Action -eq 'Cancel' -or $conflictResult.Value -eq 'Cancel') { return & $cancelResult } if ($conflictResult.Action -eq 'Back') { $step = 0; continue } if ($conflictResult.Value -eq 'Choose another destination') { $destinationRepository = $null $existingDestinationArchiveName = $null $existingDestinationConfirmation = $null continue } if ([string]::IsNullOrWhiteSpace($existingDestinationArchiveName)) { $existingDestinationArchiveName = Get-CgrDefaultArchiveRepositoryName -Repository $destinationRepository } while ($true) { $archiveResult = Read-CgrWizardRepositoryName -Kind Archive -CurrentValue $existingDestinationArchiveName -AllowBack -AllowCancel if ($archiveResult.Action -eq 'Cancel') { return & $cancelResult } if ($archiveResult.Action -eq 'Back') { $existingDestinationArchiveName = $null $existingDestinationConfirmation = $null break } $candidateArchiveName = [string] $archiveResult.Value $destinationOwner = $destinationRepository.Split('/', 2)[0] $candidateArchive = "$destinationOwner/$candidateArchiveName" if (Test-CgrGitHubRepositoryExistence -Repository $candidateArchive -HostName $HostName) { Write-CgrWizardMessage -Message "Archive repository '$candidateArchive' already exists. Choose another archive name." -Status Warning $existingDestinationArchiveName = $candidateArchiveName continue } if ($existingDestinationArchiveName -ne $candidateArchiveName) { $existingDestinationConfirmation = $null } $existingDestinationArchiveName = $candidateArchiveName break } if ([string]::IsNullOrWhiteSpace($existingDestinationArchiveName)) { continue } } else { $existingDestinationArchiveName = $null $existingDestinationConfirmation = $null } $step = 2 } 2 { $result = Read-CgrWizardChoice ` -Title 'Content mode' ` -Choices @('Snapshot', 'FullHistory') ` -DefaultValue Snapshot ` -CurrentValue $contentMode ` -HelpTopic ContentMode ` -AllowBack ` -AllowCancel if ($result.Action -eq 'Cancel') { return & $cancelResult } if ($result.Action -eq 'Back') { $step = 1; continue } $contentMode = [string] $result.Value $step = 3 } 3 { $visibilityChoices = @($sourceRepository.Visibility, 'public', 'private', 'internal') | Select-Object -Unique $result = Read-CgrWizardChoice ` -Title 'Destination visibility' ` -Choices $visibilityChoices ` -DefaultValue $sourceRepository.Visibility ` -CurrentValue $destinationVisibility ` -HelpTopic DestinationVisibility ` -AllowBack ` -AllowCancel if ($result.Action -eq 'Cancel') { return & $cancelResult } if ($result.Action -eq 'Back') { $step = 2; continue } $destinationVisibility = [string] $result.Value $step = 4 } 4 { Write-CgrWizardMessage -Message 'GitHub Pages is GitHub-side state and is restored only when explicitly selected.' -Style Hint $currentSettingsChoice = if ($restorePages) { if ($settingsBehavior -eq 'Skip') { 'Skip settings + restore GitHub Pages' } else { 'Restore settings + GitHub Pages' } } else { $settingsBehavior } $result = Read-CgrWizardChoice ` -Title 'Supported repository settings' ` -Choices @('Restore', 'Skip', 'Restore settings + GitHub Pages', 'Skip settings + restore GitHub Pages') ` -DefaultValue Restore ` -CurrentValue $currentSettingsChoice ` -HelpTopic SupportedSettings ` -AllowBack ` -AllowCancel if ($result.Action -eq 'Cancel') { return & $cancelResult } if ($result.Action -eq 'Back') { $step = 3; continue } $settingsChoice = [string] $result.Value $settingsBehavior = if ($settingsChoice -like 'Skip*') { 'Skip' } else { 'Restore' } $restorePages = $settingsChoice -match 'GitHub Pages' $step = if ($destinationRepository -eq $sourceRepository.FullName) { 5 } else { 6 } } 5 { $archiveResult = Read-CgrWizardRepositoryName -Kind Archive -CurrentValue $archiveRepositoryName -AllowBack -AllowCancel if ($archiveResult.Action -eq 'Cancel') { return & $cancelResult } if ($archiveResult.Action -eq 'Back') { $step = 4; continue } if ($archiveRepositoryName -ne $archiveResult.Value) { $archiveRepositoryName = [string] $archiveResult.Value $sameNameConfirmation = $null } $step = 6 } 6 { if ($contentMode -eq 'Snapshot') { $commitMessageResult = Read-CgrWizardTextValue ` -Title 'Snapshot commit message' ` -DefaultValue 'Initial repository commit' ` -CurrentValue $commitMessage ` -HelpTopic SnapshotCommitMessage ` -AllowBack ` -AllowCancel if ($commitMessageResult.Action -eq 'Cancel') { return & $cancelResult } if ($commitMessageResult.Action -eq 'Back') { $step = if ($destinationRepository -eq $sourceRepository.FullName) { 5 } else { 4 } continue } $commitMessage = [string] $commitMessageResult.Value $releaseScreen = -1 $returnToCommitMessage = $false while ($releaseScreen -le 4) { switch ($releaseScreen) { -1 { Write-CgrWizardMessage Write-CgrWizardMessage -Message 'Snapshot release preservation creates new checkpoint commits from selected release states.' -Style Hint Write-CgrWizardMessage -Message 'It does not preserve original commit identities or ancestry; selected tags are recreated against the new Snapshot checkpoints.' -Style Hint $currentReleaseChoice = if ($snapshotReleaseOptions.IncludeReleases) { 'Preserve selected releases' } else { 'Skip' } $releaseResult = Read-CgrWizardChoice ` -Title 'Snapshot release preservation' ` -Choices @('Skip', 'Preserve selected releases') ` -DefaultValue Skip ` -CurrentValue $currentReleaseChoice ` -AllowBack ` -AllowCancel if ($releaseResult.Action -eq 'Cancel') { return & $cancelResult } if ($releaseResult.Action -eq 'Back') { $returnToCommitMessage = $true; break } $snapshotReleaseOptions.IncludeReleases = $releaseResult.Value -eq 'Preserve selected releases' if (-not $snapshotReleaseOptions.IncludeReleases) { break } $releaseScreen = 0 } 0 { Write-CgrWizardMessage -Message 'Optional include patterns use the same PowerShell wildcard tag filtering as Copy-GitHubRepository. Separate multiple patterns with commas.' -Style Hint $filterResult = & $readOptionalReleaseValue -Prompt 'Release tag include patterns' -CurrentValue $snapshotReleaseOptions.ReleaseTag if ($filterResult.Action -eq 'Cancel') { return & $cancelResult } if ($filterResult.Action -eq 'Back') { $releaseScreen = -1; continue } $snapshotReleaseOptions.ReleaseTag = [string] $filterResult.Value $releaseScreen = 1 } 1 { Write-CgrWizardMessage -Message 'Optional exclude patterns are applied after include filtering. Separate multiple patterns with commas.' -Style Hint $filterResult = & $readOptionalReleaseValue -Prompt 'Release tag exclude patterns' -CurrentValue $snapshotReleaseOptions.ReleaseExcludeTag if ($filterResult.Action -eq 'Cancel') { return & $cancelResult } if ($filterResult.Action -eq 'Back') { $releaseScreen = 0; continue } $snapshotReleaseOptions.ReleaseExcludeTag = [string] $filterResult.Value $releaseScreen = 2 } 2 { $prereleaseChoice = if ($snapshotReleaseOptions.IncludePrerelease) { 'Include prereleases' } else { 'Exclude prereleases' } $filterResult = Read-CgrWizardChoice ` -Title 'Prerelease filtering' ` -Choices @('Exclude prereleases', 'Include prereleases') ` -DefaultValue 'Exclude prereleases' ` -CurrentValue $prereleaseChoice ` -AllowBack ` -AllowCancel if ($filterResult.Action -eq 'Cancel') { return & $cancelResult } if ($filterResult.Action -eq 'Back') { $releaseScreen = 1; continue } $snapshotReleaseOptions.IncludePrerelease = $filterResult.Value -eq 'Include prereleases' $releaseScreen = 3 } 3 { $draftChoice = if ($snapshotReleaseOptions.IncludeDraftReleases) { 'Include draft releases' } else { 'Exclude draft releases' } $filterResult = Read-CgrWizardChoice ` -Title 'Draft release filtering' ` -Choices @('Exclude draft releases', 'Include draft releases') ` -DefaultValue 'Exclude draft releases' ` -CurrentValue $draftChoice ` -AllowBack ` -AllowCancel if ($filterResult.Action -eq 'Cancel') { return & $cancelResult } if ($filterResult.Action -eq 'Back') { $releaseScreen = 2; continue } $snapshotReleaseOptions.IncludeDraftReleases = $filterResult.Value -eq 'Include draft releases' $releaseScreen = 4 } 4 { Write-CgrWizardMessage -Message 'Optionally limit the reviewed selection to the newest N releases after the other filters are applied.' -Style Hint $filterResult = & $readOptionalReleaseValue -Prompt 'Release count limit' -CurrentValue $snapshotReleaseOptions.ReleaseCount -PositiveInteger if ($filterResult.Action -eq 'Cancel') { return & $cancelResult } if ($filterResult.Action -eq 'Back') { $releaseScreen = 3; continue } $snapshotReleaseOptions.ReleaseCount = [string] $filterResult.Value $releaseScreen = 5 } } if ($returnToCommitMessage -or -not $snapshotReleaseOptions.IncludeReleases) { break } } if ($returnToCommitMessage) { continue } } $planParameters = @{ SourceRepository = $sourceRepository.FullName DestinationRepository = $destinationRepository ContentMode = $contentMode HostName = $HostName PlanOnly = $true } if ($contentMode -eq 'Snapshot') { $planParameters.CommitMessage = $commitMessage if ($snapshotReleaseOptions.IncludeReleases) { $planParameters.IncludeReleases = $true $releaseTags = @($snapshotReleaseOptions.ReleaseTag -split ',' | ForEach-Object { $_.Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) $releaseExcludeTags = @($snapshotReleaseOptions.ReleaseExcludeTag -split ',' | ForEach-Object { $_.Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) if ($releaseTags.Count -gt 0) { $planParameters.ReleaseTag = $releaseTags } if ($releaseExcludeTags.Count -gt 0) { $planParameters.ReleaseExcludeTag = $releaseExcludeTags } if ($snapshotReleaseOptions.IncludePrerelease) { $planParameters.IncludePrerelease = $true } if ($snapshotReleaseOptions.IncludeDraftReleases) { $planParameters.IncludeDraftReleases = $true } if (-not [string]::IsNullOrWhiteSpace($snapshotReleaseOptions.ReleaseCount)) { $planParameters.ReleaseCount = [int] $snapshotReleaseOptions.ReleaseCount } } } if ($destinationVisibility -ne $sourceRepository.Visibility) { $planParameters.DestinationVisibility = $destinationVisibility } if ($settingsBehavior -eq 'Skip') { $planParameters.SkipSettings = $true } if ($restorePages) { $planParameters.RestorePages = $true } if ($destinationRepository -eq $sourceRepository.FullName) { $planParameters.ArchiveRepositoryName = $archiveRepositoryName } elseif (-not [string]::IsNullOrWhiteSpace($existingDestinationArchiveName)) { $planParameters.ExistingDestinationArchiveName = $existingDestinationArchiveName } $plan = Copy-GitHubRepository @planParameters Write-CgrWizardMessage Write-CgrWizardMessage -Message 'Repository copy plan' -Style Heading Write-CgrWizardMessage -Message (' Source: {0}' -f $plan.SourceRepository) -Style Value Write-CgrWizardMessage -Message (' Destination: {0}' -f $plan.DestinationRepository) -Style Value Write-CgrWizardMessage -Message (' Content mode: {0}' -f $plan.ContentMode) if ($plan.ContentMode -eq 'Snapshot') { if ($plan.IncludeReleases) { Write-CgrWizardMessage -Message ' Snapshot release preservation does not preserve original commit identities or ancestry.' -Status Warning Write-CgrWizardMessage -Message ' Selected release states become newly constructed Snapshot checkpoint commits, and selected tags are recreated against those new commits.' -Style Hint Write-CgrWizardMessage -Message (' Approved source commit: {0}' -f $plan.SourceState.CommitSha) -Style Hint Write-CgrWizardMessage -Message (' Commit message: {0}' -f $plan.CommitMessage) -Style Hint $releaseSelection = $plan.ReleaseSelection $checkpointPlan = $plan.ReleaseCheckpointPlan Write-CgrWizardMessage -Message (' Selected releases: {0} of {1}' -f $releaseSelection.SelectedReleaseCount, $releaseSelection.AvailableReleaseCount) -Style Hint Write-CgrWizardMessage -Message (' Selected release assets: {0}' -f $releaseSelection.SelectedAssetCount) -Style Hint $includePatterns = if (@($releaseSelection.IncludePatterns).Count -gt 0) { @($releaseSelection.IncludePatterns) -join ', ' } else { '(all tags)' } $excludePatterns = if (@($releaseSelection.ExcludePatterns).Count -gt 0) { @($releaseSelection.ExcludePatterns) -join ', ' } else { '(none)' } $releaseLimit = if ($null -ne $releaseSelection.ReleaseCount) { [string] $releaseSelection.ReleaseCount } else { '(none)' } Write-CgrWizardMessage -Message (' Include tag filters: {0}' -f $includePatterns) -Style Hint Write-CgrWizardMessage -Message (' Exclude tag filters: {0}' -f $excludePatterns) -Style Hint Write-CgrWizardMessage -Message (' Prereleases: {0}' -f $(if ($releaseSelection.IncludePrerelease) { 'included' } else { 'excluded' })) -Style Hint Write-CgrWizardMessage -Message (' Draft releases: {0}' -f $(if ($releaseSelection.IncludeDraftReleases) { 'included' } else { 'excluded' })) -Style Hint Write-CgrWizardMessage -Message (' Release count limit: {0}' -f $releaseLimit) -Style Hint Write-CgrWizardMessage -Message (' Snapshot release checkpoints: {0}' -f $checkpointPlan.CheckpointCount) -Style Hint Write-CgrWizardMessage -Message (' Planned Snapshot commits: {0}' -f $checkpointPlan.PlannedSnapshotCommitCount) -Style Hint Write-CgrWizardMessage -Message (' Final current-state checkpoint required: {0}' -f $checkpointPlan.FinalHeadCheckpointRequired) -Style Hint Write-CgrWizardMessage -Message ' Reviewed Snapshot checkpoint plan:' -Style Heading if (@($checkpointPlan.Checkpoints).Count -eq 0) { Write-CgrWizardMessage -Message ' - No release checkpoint commits are selected; the reviewed plan contains only the current Snapshot state.' -Style Hint } else { foreach ($checkpoint in @($checkpointPlan.Checkpoints)) { $tagNames = @($checkpoint.TagNames) -join ', ' Write-CgrWizardMessage -Message (' - {0}. source commit {1}; tree {2}; recreated tags: {3}' -f $checkpoint.Order, $checkpoint.SourceCommitSha, $checkpoint.SourceTreeSha, $tagNames) } } } else { Write-CgrWizardMessage -Message ' Snapshot publishes the approved default-branch content as one new root commit without prior Git history.' -Style Hint Write-CgrWizardMessage -Message (' Approved source commit: {0}' -f $plan.SourceState.CommitSha) -Style Hint Write-CgrWizardMessage -Message (' Commit message: {0}' -f $plan.CommitMessage) -Style Hint $historicalRecords = Get-CgrObjectProperty -InputObject $plan.SourceState -Name 'HistoricalRecords' if ($historicalRecords) { $tagCount = [int] (Get-CgrObjectProperty -InputObject $historicalRecords -Name 'TagCount') $releaseCount = [int] (Get-CgrObjectProperty -InputObject $historicalRecords -Name 'ReleaseCount') Write-CgrWizardMessage -Message (' Git tags: {0} (not copied)' -f $tagCount) -Style Hint Write-CgrWizardMessage -Message (' GitHub Releases: {0} (not copied)' -f $releaseCount) -Style Hint if ($plan.Mode -eq 'SameNameReplacement' -and ($tagCount -gt 0 -or $releaseCount -gt 0)) { Write-CgrWizardMessage -Message 'Existing tags and GitHub Releases remain with the archived original repository; they are not recreated on the clean replacement.' -Status Warning Write-CgrWizardMessage -Message 'Create the new release tag and GitHub Release only after the clean replacement has completed and been verified.' -Style Hint } } } } else { Write-CgrWizardMessage -Message ' FullHistory preserves the approved branches, tags, commits, and reachable Git LFS objects.' -Style Hint Write-CgrWizardMessage -Message (' Approved refs: {0}; reachable commits: {1}' -f @($plan.SourceState.Refs).Count, $plan.SourceState.ReachableCommitCount) -Style Hint } Write-CgrWizardMessage -Message (' Visibility: {0}' -f $plan.DestinationVisibility) if (-not [string]::IsNullOrWhiteSpace([string] $plan.ArchiveRepository)) { Write-CgrWizardMessage -Message (' Archive: {0}' -f $plan.ArchiveRepository) -Style Value } if (Get-CgrObjectProperty -InputObject $plan -Name 'RestorePages') { Write-CgrWizardMessage -Message ' GitHub Pages restoration:' -Style Heading $pages = Get-CgrObjectProperty -InputObject $plan -Name 'Pages' if ($null -eq $pages) { Write-CgrWizardMessage -Message ' - Reviewed Pages evidence is unavailable; Pages cannot be presented as restorable.' -Status Warning } else { $pagesStatus = [string] (Get-CgrObjectProperty -InputObject $pages -Name 'Status') Write-CgrWizardMessage -Message (' - Source Pages status: {0}' -f $pagesStatus) if ($pagesStatus -eq 'NotConfigured') { Write-CgrWizardMessage -Message ' - Source Pages is not configured; the approved plan will not create a destination Pages site.' -Style Hint } else { $buildType = [string] (Get-CgrObjectProperty -InputObject $pages -Name 'BuildType') if ($buildType -eq 'workflow') { Write-CgrWizardMessage -Message ' - Build mode: GitHub Actions (workflow-based Pages); no branch/path publishing source is implied.' -Style Hint } elseif (-not [string]::IsNullOrWhiteSpace($buildType)) { Write-CgrWizardMessage -Message (' - Build mode: {0} (branch/path-based Pages).' -f $buildType) -Style Hint $pagesSource = Get-CgrObjectProperty -InputObject $pages -Name 'Source' if ($null -ne $pagesSource) { Write-CgrWizardMessage -Message (' - Publishing source: {0}{1}' -f (Get-CgrObjectProperty -InputObject $pagesSource -Name 'Branch'), (Get-CgrObjectProperty -InputObject $pagesSource -Name 'Path')) -Style Hint } } $representability = Get-CgrObjectProperty -InputObject $pages -Name 'Representability' if ($null -ne $representability -and -not [bool] (Get-CgrObjectProperty -InputObject $representability -Name 'IsRepresentable')) { Write-CgrWizardMessage -Message (' - Pages is not restorable from this reviewed plan: {0}' -f (Get-CgrObjectProperty -InputObject $representability -Name 'Reason')) -Status Warning } $customDomain = [string] (Get-CgrObjectProperty -InputObject $pages -Name 'CustomDomain') $httpsIntent = Get-CgrObjectProperty -InputObject $pages -Name 'HttpsEnforced' $domainText = if ([string]::IsNullOrWhiteSpace($customDomain)) { '(none)' } else { $customDomain } Write-CgrWizardMessage -Message (' - Custom domain: {0}' -f $domainText) -Style Hint Write-CgrWizardMessage -Message (' - HTTPS enforcement intent: {0}' -f $httpsIntent) -Style Hint $externalReadiness = Get-CgrObjectProperty -InputObject $pages -Name 'ExternalReadiness' if ($null -ne $externalReadiness) { $domainVerification = Get-CgrObjectProperty -InputObject $externalReadiness -Name 'DomainVerification' $certificate = Get-CgrObjectProperty -InputObject $externalReadiness -Name 'Certificate' $certificateState = if ($null -eq $certificate) { 'NotReportedByGitHub' } elseif ($certificate -is [string]) { [string] $certificate } else { $state = [string] (Get-CgrObjectProperty -InputObject $certificate -Name 'state') if ([string]::IsNullOrWhiteSpace($state)) { [string] $certificate } else { $state } } $dnsReadiness = Get-CgrObjectProperty -InputObject $externalReadiness -Name 'Dns' Write-CgrWizardMessage -Message (' - Domain verification readiness: {0}' -f $domainVerification) -Style Hint Write-CgrWizardMessage -Message (' - Certificate readiness: {0}' -f $certificateState) -Style Hint Write-CgrWizardMessage -Message (' - DNS evidence: {0}' -f $dnsReadiness) -Style Hint } if (-not [string]::IsNullOrWhiteSpace($customDomain) -or [bool] $httpsIntent) { Write-CgrWizardMessage -Message ' - Custom-domain and HTTPS completion can depend on external DNS, GitHub domain verification, and certificate readiness; the wizard does not discover or mutate external DNS.' -Status Warning } if (-not [string]::IsNullOrWhiteSpace($customDomain) -and $plan.Mode -eq 'SameNameReplacement') { Write-CgrWizardMessage -Message (" - Same-name replacement must hand off custom-domain ownership for '$customDomain': the archived original may need to release the exact domain before the replacement can claim it. This happens only through the reviewed Pages handoff contract; external DNS is unchanged.") -Status Warning } } } } Write-CgrWizardMessage -Message ' Planned steps:' -Style Heading foreach ($plannedStep in @($plan.Steps)) { Write-CgrWizardMessage -Message (' - {0}' -f $plannedStep.Description) } $confirmation = Read-CgrWizardChoice ` -Title 'Repository copy plan' ` -Choices @('Execute', 'Cancel') ` -DefaultValue Cancel ` -HelpTopic MigrationPlan ` -AllowBack ` -AllowCancel if ($confirmation.Action -eq 'Cancel' -or $confirmation.Value -eq 'Cancel') { return & $cancelResult } if ($confirmation.Action -eq 'Back') { $step = if ($destinationRepository -eq $sourceRepository.FullName) { 5 } else { 4 } continue } if ($confirmation.Value -ne 'Execute') { continue } $restartPlanning = $false if ($plan.Mode -eq 'SameNameReplacement') { $expectedConfirmation = "SOURCE=$($plan.SourceRepository);ARCHIVE=$($plan.ArchiveRepository);REPLACEMENT=$($plan.DestinationRepository)" while ($true) { Write-CgrWizardMessage -Message 'Same-name replacement preserves the current repository as an archive before creating the replacement.' -Status Warning Write-CgrWizardMessage -Message 'Exact confirmation is required and cannot be bypassed.' -Style Hint Write-CgrWizardMessage -Message 'Required text:' -Style Hint Write-CgrWizardMessage -Message $expectedConfirmation -Style Value if (-not [string]::IsNullOrWhiteSpace($sameNameConfirmation)) { Write-CgrWizardMessage -Message 'A valid confirmation is already stored. Press Enter to reuse it.' -Style Hint } $inputText = Read-CgrWizardInput ` -Prompt 'Exact confirmation' ` -DefaultValue $sameNameConfirmation ` -AllowHelp ` -AllowBack ` -AllowCancel $navigation = Resolve-CgrWizardNavigationInput ` -InputText $inputText ` -AllowBack ` -AllowNext:(-not [string]::IsNullOrWhiteSpace($sameNameConfirmation)) ` -AllowCancel ` -AllowHelp if ($null -ne $navigation) { if ($navigation.Action -eq 'Help') { Show-CgrWizardHelp -Topic ExactConfirmation; continue } if ($navigation.Action -eq 'Cancel') { return & $cancelResult } if ($navigation.Action -eq 'Back') { $step = 5 $restartPlanning = $true break } if ($navigation.Action -eq 'Next') { break } } if ($inputText -ceq $expectedConfirmation) { $sameNameConfirmation = $inputText break } Write-CgrWizardMessage -Message 'The confirmation did not match exactly. Retry, go Back, or Cancel.' -Status Warning } } if ($restartPlanning) { continue } if ($plan.Mode -eq 'ExistingDestinationReplacement') { $expectedConfirmation = "DESTINATION=$($plan.DestinationRepository);ARCHIVE=$($plan.ArchiveRepository);REPLACEMENT=$($plan.DestinationRepository)" while ($true) { Write-CgrWizardMessage -Message 'The existing destination will be preserved as an archive before a fresh replacement is created.' -Status Warning Write-CgrWizardMessage -Message 'Exact confirmation is required and cannot be bypassed.' -Style Hint Write-CgrWizardMessage -Message 'Required text:' -Style Hint Write-CgrWizardMessage -Message $expectedConfirmation -Style Value $inputText = Read-CgrWizardInput -Prompt 'Exact confirmation' -AllowHelp -AllowCancel $navigation = Resolve-CgrWizardNavigationInput -InputText $inputText -AllowCancel -AllowHelp if ($null -ne $navigation) { if ($navigation.Action -eq 'Help') { Show-CgrWizardHelp -Topic ExactConfirmation; continue } if ($navigation.Action -eq 'Cancel') { return & $cancelResult } } if ($inputText -ceq $expectedConfirmation) { $existingDestinationConfirmation = $inputText break } Write-CgrWizardMessage -Message 'The confirmation did not match exactly. Retry or Cancel.' -Status Warning } } if (-not (& $ExecutionGuard $destinationRepository)) { return $plan } Write-CgrWizardMessage -Message 'Executing the reviewed repository copy plan...' -Status Info try { $executionResult = Invoke-CgrApprovedMigrationPlan ` -Plan $plan ` -SourceRepository $sourceRepository ` -SameNameConfirmation $sameNameConfirmation ` -ExistingDestinationConfirmation $existingDestinationConfirmation ` -HostName $HostName } catch { $errorId = ([string] $_.FullyQualifiedErrorId).Split(',', 2)[0] if ($errorId -eq 'SourceStateChangedSincePlanning') { Write-CgrWizardMessage -Message $_.Exception.Message -Status Warning Write-CgrWizardMessage -Message 'A new plan will be created for review. No GitHub mutation was performed from the stale plan.' -Style Hint $sameNameConfirmation = $null $existingDestinationConfirmation = $null $step = 6 continue } throw } Write-CgrWizardCompletionSummary -Result $executionResult return $executionResult } } } } |