Private/Migration/Invoke-CgrApprovedFullHistoryVerification.ps1

function Invoke-CgrApprovedFullHistoryVerification {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [psobject] $SourceRepository,

        [Parameter(Mandatory)]
        [psobject] $DestinationRepository,

        [Parameter(Mandatory)]
        [psobject] $ApprovedSourceState
    )

    $workspacePath = Join-Path ([System.IO.Path]::GetTempPath()) "copy-github-repo-fullhistory-approved-verify-$([guid]::NewGuid().ToString('N'))"
    $destinationPath = Join-Path $workspacePath 'destination.git'
    try {
        New-Item -Path $workspacePath -ItemType Directory -Force | Out-Null
        $cloneResult = Invoke-CgrGitCommand -HostName $DestinationRepository.HostName -ArgumentList @('clone', '--bare', $DestinationRepository.CloneUrl, $destinationPath)
        if ($cloneResult.ExitCode -ne 0) {
            $message = "Git failed to clone destination '$($DestinationRepository.FullName)' for FullHistory verification. $($cloneResult.ErrorText)"
            $exception = [System.InvalidOperationException]::new($message.Trim())
            $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, 'FullHistoryVerificationDestinationCloneFailed', [System.Management.Automation.ErrorCategory]::InvalidOperation, $DestinationRepository.FullName)
            $PSCmdlet.ThrowTerminatingError($errorRecord)
        }

        $lfsResult = Invoke-CgrGitCommand -HostName $DestinationRepository.HostName -ArgumentList @('-C', $destinationPath, 'lfs', 'fetch', '--all', 'origin')
        if ($lfsResult.ExitCode -ne 0) {
            $message = "Git LFS failed to verify reachable objects in '$($DestinationRepository.FullName)'. $($lfsResult.ErrorText)"
            $exception = [System.InvalidOperationException]::new($message.Trim())
            $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, 'FullHistoryVerificationDestinationGitLfsFetchFailed', [System.Management.Automation.ErrorCategory]::InvalidOperation, $DestinationRepository.FullName)
            $PSCmdlet.ThrowTerminatingError($errorRecord)
        }

        $refsResult = Invoke-CgrNativeCommand -FilePath 'git' -ArgumentList @('-C', $destinationPath, 'for-each-ref', '--format=%(refname) %(objectname)', 'refs/heads', 'refs/tags')
        $commitCountResult = Invoke-CgrNativeCommand -FilePath 'git' -ArgumentList @('-C', $destinationPath, 'rev-list', '--all', '--count')
        $branchesResult = Invoke-CgrNativeCommand -FilePath 'git' -ArgumentList @('-C', $destinationPath, 'for-each-ref', '--format=%(refname)', 'refs/heads')
        foreach ($command in @($refsResult, $commitCountResult, $branchesResult)) {
            if ($command.ExitCode -ne 0) {
                $message = "Git failed while verifying FullHistory destination '$($DestinationRepository.FullName)'. $($command.ErrorText)"
                $exception = [System.InvalidOperationException]::new($message.Trim())
                $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, 'FullHistoryVerificationDestinationReadFailed', [System.Management.Automation.ErrorCategory]::InvalidOperation, $DestinationRepository.FullName)
                $PSCmdlet.ThrowTerminatingError($errorRecord)
            }
        }

        $branches = @($branchesResult.Output | ForEach-Object { $_.ToString() } | Sort-Object)
        $destinationBranchTrees = [System.Collections.Generic.List[string]]::new()
        foreach ($branch in $branches) {
            $treeResult = Invoke-CgrNativeCommand -FilePath 'git' -ArgumentList @('-C', $destinationPath, 'rev-parse', "$branch^{tree}")
            if ($treeResult.ExitCode -ne 0) {
                $message = "Git failed to read destination branch-tip tree '$branch' during FullHistory verification."
                $exception = [System.InvalidOperationException]::new($message)
                $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, 'FullHistoryVerificationBranchTreeReadFailed', [System.Management.Automation.ErrorCategory]::InvalidOperation, $branch)
                $PSCmdlet.ThrowTerminatingError($errorRecord)
            }
            $destinationBranchTrees.Add("$branch $([string] @($treeResult.Output)[0])")
        }

        $expectedRefs = @(Get-CgrObjectProperty -InputObject $ApprovedSourceState -Name 'Refs') | Sort-Object
        $actualRefs = @($refsResult.Output | ForEach-Object { $_.ToString() } | Sort-Object)
        $expectedCommitCount = [int] (Get-CgrObjectProperty -InputObject $ApprovedSourceState -Name 'ReachableCommitCount')
        $actualCommitCount = [int] ([string] @($commitCountResult.Output)[0])
        $expectedBranchTrees = @(Get-CgrObjectProperty -InputObject $ApprovedSourceState -Name 'BranchTrees') | Sort-Object
        $actualBranchTrees = @($destinationBranchTrees.ToArray() | Sort-Object)
        $expectedDefaultBranch = [string] (Get-CgrObjectProperty -InputObject $ApprovedSourceState -Name 'DefaultBranch')

        $checks = @(
            [pscustomobject] @{ Name = 'DestinationExists'; Passed = $true; Expected = $DestinationRepository.FullName; Actual = $DestinationRepository.FullName }
            [pscustomobject] @{ Name = 'DefaultBranchMatches'; Passed = $DestinationRepository.DefaultBranch -eq $expectedDefaultBranch; Expected = $expectedDefaultBranch; Actual = $DestinationRepository.DefaultBranch }
            [pscustomobject] @{ Name = 'BranchAndTagTargetsMatch'; Passed = ($actualRefs -join "`n") -eq ($expectedRefs -join "`n"); Expected = $expectedRefs; Actual = $actualRefs }
            [pscustomobject] @{ Name = 'ReachableCommitCountMatches'; Passed = $actualCommitCount -eq $expectedCommitCount; Expected = $expectedCommitCount; Actual = $actualCommitCount }
            [pscustomobject] @{ Name = 'BranchTipTreesMatch'; Passed = ($actualBranchTrees -join "`n") -eq ($expectedBranchTrees -join "`n"); Expected = $expectedBranchTrees; Actual = $actualBranchTrees }
            [pscustomobject] @{ Name = 'GitLfsObjectsAvailable'; Passed = $true; Expected = [bool] (Get-CgrObjectProperty -InputObject $ApprovedSourceState -Name 'GitLfsObjectsAvailable'); Actual = $true }
        )

        [pscustomobject] @{
            PSTypeName = 'CopyGitHubRepo.MigrationVerificationResult'
            SchemaVersion = 1
            ContentMode = 'FullHistory'
            SourceRepository = $SourceRepository.FullName
            ApprovedSourceState = $ApprovedSourceState
            DestinationRepository = $DestinationRepository.FullName
            BranchName = $expectedDefaultBranch
            SourceRefCount = $expectedRefs.Count
            DestinationRefCount = $actualRefs.Count
            SourceReachableCommitCount = $expectedCommitCount
            DestinationReachableCommitCount = $actualCommitCount
            IsSuccessful = -not ($checks | Where-Object { -not $_.Passed })
            Checks = $checks
        }
    }
    finally {
        if (Test-Path -LiteralPath $workspacePath) {
            Remove-Item -LiteralPath $workspacePath -Recurse -Force -ErrorAction SilentlyContinue
        }
    }
}