Private/Migration/Get-CgrSnapshotReleasePreservationEvidence.ps1

function Get-CgrSnapshotReleasePreservationEvidence {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)] [psobject] $Plan,
        [AllowNull()] [psobject] $DestinationRepository,
        [AllowNull()] [psobject] $SnapshotCopyResult,
        [AllowNull()] [psobject] $ReleaseRestoreResult,
        [object[]] $GeneratedCommitProgress = @(),
        [ValidateNotNullOrEmpty()] [string] $HostName = 'github.com'
    )

    $includeReleases = [bool] (Get-CgrObjectProperty -InputObject $Plan -Name 'IncludeReleases')
    $checkpointPlan = Get-CgrObjectProperty -InputObject $Plan -Name 'ReleaseCheckpointPlan'
    $releaseSelection = Get-CgrObjectProperty -InputObject $Plan -Name 'ReleaseSelection'
    if (-not $includeReleases -or $null -eq $checkpointPlan) {
        return $null
    }

    $generatedCommits = [System.Collections.Generic.List[object]]::new()
    foreach ($generatedCommit in $(if ($SnapshotCopyResult) { @(Get-CgrObjectProperty -InputObject $SnapshotCopyResult -Name 'GeneratedCommits') } else { @($GeneratedCommitProgress) })) {
        $generatedCommits.Add($generatedCommit)
    }
    $recreatedTags = if ($SnapshotCopyResult) { @(Get-CgrObjectProperty -InputObject $SnapshotCopyResult -Name 'ReleaseTags') } else { @() }
    $destinationHeadCommitSha = if ($SnapshotCopyResult) { [string] (Get-CgrObjectProperty -InputObject $SnapshotCopyResult -Name 'CommitSha') } else { $null }
    $snapshotPublicationVerified = [bool] ($SnapshotCopyResult -and (Get-CgrObjectProperty -InputObject $SnapshotCopyResult -Name 'Verified'))

    if ($null -eq $SnapshotCopyResult -and $DestinationRepository) {
        $observedTags = [System.Collections.Generic.List[object]]::new()
        foreach ($releaseEvidence in @(Get-CgrObjectProperty -InputObject $checkpointPlan -Name 'ReleaseEvidence')) {
            $tagName = [string] (Get-CgrObjectProperty -InputObject $releaseEvidence -Name 'TagName')
            if ([string]::IsNullOrWhiteSpace($tagName)) { continue }

            $tagRead = Invoke-CgrGitHubApiReadRequest -ArgumentList @(
                'api', '--hostname', $HostName,
                "repos/$($DestinationRepository.FullName)/git/ref/tags/$([uri]::EscapeDataString($tagName))"
            )
            if ($tagRead.ExitCode -ne 0) { continue }

            $tagJson = ($tagRead.Output | ForEach-Object { [string] $_ }) -join "`n"
            $tag = $tagJson | ConvertFrom-Json -Depth 20
            $destinationCommitSha = [string] $tag.object.sha
            $sourceCommitSha = [string] (Get-CgrObjectProperty -InputObject $releaseEvidence -Name 'PeeledCommitSha')
            $checkpoint = @((Get-CgrObjectProperty -InputObject $checkpointPlan -Name 'Checkpoints') | Where-Object {
                    [string] (Get-CgrObjectProperty -InputObject $_ -Name 'SourceCommitSha') -eq $sourceCommitSha
                }) | Select-Object -First 1

            $observedTags.Add([pscustomobject] @{
                    TagName = $tagName
                    SourceTagObjectType = [string] (Get-CgrObjectProperty -InputObject $releaseEvidence -Name 'TagObjectType')
                    SourceTagObjectSha = [string] (Get-CgrObjectProperty -InputObject $releaseEvidence -Name 'TagObjectSha')
                    SourcePeeledCommitSha = $sourceCommitSha
                    DestinationCommitSha = $destinationCommitSha
                    DestinationTagType = [string] $tag.object.type
                    ObservedAfterFailure = $true
                    Verified = $false
                })

            $matchingGeneratedCommit = @($generatedCommits | Where-Object { [string] (Get-CgrObjectProperty -InputObject $_ -Name 'CommitSha') -eq $destinationCommitSha } | Select-Object -First 1)
            if ($matchingGeneratedCommit.Count -eq 1) {
                $matchingGeneratedCommit[0] | Add-Member -NotePropertyName Published -NotePropertyValue $true -Force
            }
            else {
                $generatedCommits.Add([pscustomobject] @{
                        Kind = 'ReleaseCheckpoint'
                        Order = if ($checkpoint) { Get-CgrObjectProperty -InputObject $checkpoint -Name 'Order' } else { $null }
                        SourceCommitSha = $sourceCommitSha
                        SourceTreeSha = if ($checkpoint) { Get-CgrObjectProperty -InputObject $checkpoint -Name 'SourceTreeSha' } else { $null }
                        TagNames = if ($checkpoint) { @(Get-CgrObjectProperty -InputObject $checkpoint -Name 'TagNames') } else { @($tagName) }
                        CommitSha = $destinationCommitSha
                        TreeSha = $null
                        Message = $null
                        Published = $true
                        ObservedAfterFailure = $true
                        Verified = $false
                    })
            }
        }
        $recreatedTags = $observedTags.ToArray()

        $branchRead = Invoke-CgrGitHubApiReadRequest -ArgumentList @(
            'api', '--hostname', $HostName,
            "repos/$($DestinationRepository.FullName)/git/ref/heads/$([uri]::EscapeDataString([string] $Plan.SourceDefaultBranch))"
        )
        if ($branchRead.ExitCode -eq 0) {
            $branchJson = ($branchRead.Output | ForEach-Object { [string] $_ }) -join "`n"
            $branch = $branchJson | ConvertFrom-Json -Depth 20
            $destinationHeadCommitSha = [string] $branch.object.sha
            $matchingHeadCommit = @($generatedCommits | Where-Object { [string] (Get-CgrObjectProperty -InputObject $_ -Name 'CommitSha') -eq $destinationHeadCommitSha } | Select-Object -First 1)
            if ($matchingHeadCommit.Count -eq 1) {
                $matchingHeadCommit[0] | Add-Member -NotePropertyName Published -NotePropertyValue $true -Force
            }
        }
    }

    $restoredReleases = if ($ReleaseRestoreResult) { @(Get-CgrObjectProperty -InputObject $ReleaseRestoreResult -Name 'Releases') } else { @() }
    $releaseRestoreStatus = if ($ReleaseRestoreResult) { [string] (Get-CgrObjectProperty -InputObject $ReleaseRestoreResult -Name 'Status') } else { $null }
    $releaseRestoreSuccessful = [bool] ($ReleaseRestoreResult -and $releaseRestoreStatus -eq 'Restored' -and (Get-CgrObjectProperty -InputObject $ReleaseRestoreResult -Name 'IsSuccessful'))
    $observedReleaseEvidence = [System.Collections.Generic.List[object]]::new()

    if (-not $releaseRestoreSuccessful -and $DestinationRepository) {
        foreach ($approvedRelease in @(Get-CgrObjectProperty -InputObject $releaseSelection -Name 'Releases')) {
            $tagName = [string] (Get-CgrObjectProperty -InputObject $approvedRelease -Name 'TagName')
            if ([string]::IsNullOrWhiteSpace($tagName)) { continue }

            $releaseRead = Invoke-CgrGitHubApiReadRequest -ArgumentList @(
                'api', '--hostname', $HostName,
                "repos/$($DestinationRepository.FullName)/releases/tags/$([uri]::EscapeDataString($tagName))"
            )
            if ($releaseRead.ExitCode -ne 0) { continue }

            $releaseJson = ($releaseRead.Output | ForEach-Object { [string] $_ }) -join "`n"
            $release = $releaseJson | ConvertFrom-Json -Depth 100
            $assets = @($release.assets | ForEach-Object {
                    [pscustomobject] @{
                        Id = $_.id
                        Name = [string] $_.name
                        Label = [string] $_.label
                        Size = [long] $_.size
                        ContentType = [string] $_.content_type
                        Digest = [string] $_.digest
                    }
                })
            $observedReleaseEvidence.Add([pscustomobject] @{
                    TagName = $tagName
                    SourceReleaseId = Get-CgrObjectProperty -InputObject $approvedRelease -Name 'ReleaseId'
                    DestinationReleaseId = $release.id
                    Name = [string] $release.name
                    Body = [string] $release.body
                    Draft = [bool] $release.draft
                    Prerelease = [bool] $release.prerelease
                    Assets = $assets
                    AssetCount = $assets.Count
                    ObservedAfterFailure = $true
                    Verified = $false
                })
        }
        $restoredReleases = $observedReleaseEvidence.ToArray()
    }

    $approvedReleaseCount = @((Get-CgrObjectProperty -InputObject $releaseSelection -Name 'Releases')).Count
    $plannedCheckpointCount = @((Get-CgrObjectProperty -InputObject $checkpointPlan -Name 'Checkpoints')).Count
    $constructedCheckpointCount = @($generatedCommits | Where-Object { (Get-CgrObjectProperty -InputObject $_ -Name 'Kind') -eq 'ReleaseCheckpoint' }).Count
    $publishedCheckpointCount = @($generatedCommits | Where-Object {
            (Get-CgrObjectProperty -InputObject $_ -Name 'Kind') -eq 'ReleaseCheckpoint' -and
            [bool] (Get-CgrObjectProperty -InputObject $_ -Name 'Published')
        }).Count

    return [pscustomobject] @{
        PSTypeName = 'CopyGitHubRepo.SnapshotReleasePreservationEvidence'
        Planned = [pscustomobject] @{
            ReleaseCheckpointPlan = $checkpointPlan
            ReleaseSelection = $releaseSelection
            CheckpointCount = $plannedCheckpointCount
            ReleaseCount = $approvedReleaseCount
        }
        Actual = [pscustomobject] @{
            DestinationHeadCommitSha = $destinationHeadCommitSha
            GeneratedCommits = @($generatedCommits)
            ConstructedCheckpointCount = $constructedCheckpointCount
            PublishedCheckpointCount = $publishedCheckpointCount
            ReleaseTags = @($recreatedTags)
            Releases = @($restoredReleases)
        }
        Verified = [pscustomobject] @{
            SnapshotPublication = $snapshotPublicationVerified
            ReleaseRestore = $releaseRestoreSuccessful
            VerifiedReleaseCount = @($restoredReleases | Where-Object { [bool] (Get-CgrObjectProperty -InputObject $_ -Name 'IsVerified') }).Count
        }
        Incomplete = [pscustomobject] @{
            CheckpointConstructionCount = [Math]::Max(0, $plannedCheckpointCount - $constructedCheckpointCount)
            CheckpointPublicationCount = [Math]::Max(0, $plannedCheckpointCount - $publishedCheckpointCount)
            TagCount = [Math]::Max(0, $approvedReleaseCount - @($recreatedTags).Count)
            ReleaseCount = [Math]::Max(0, $approvedReleaseCount - @($restoredReleases).Count)
        }
    }
}