public/Automerge-DockerImageVariantsPR.ps1

function Automerge-DockerImageVariantsPR {
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory,Position=0)]
        [object]$PR
    )

    try {
        $callerEA = $ErrorActionPreference
        $ErrorActionPreference = 'Stop'

        $env:GITHUB_TOKEN = if ($env:GITHUB_TOKEN) { $env:GITHUB_TOKEN } else { (Get-Content ~/.git-credentials -Encoding utf8 -Force -ErrorAction SilentlyContinue) -split "`n" | % { if ($_ -match '^https://[^:]+:([^:]+)@github.com') { $matches[1] } } | Select-Object -First 1 }
        if (!$env:GITHUB_TOKEN) {
            throw "GITHUB_TOKEN env var is empty"
        }
        $headers = @{
            'Accept' = 'application/vnd.github+json'
            'Authorization' = "Bearer $env:GITHUB_TOKEN"
            'X-GitHub-Api-Version' = '2022-11-28'
            'Content-Type' = 'application/json'
        }
        "Will automerge PR" | Write-Host
        if (!$WhatIfPreference) {
            while ($true) {
                $pr = Invoke-RestMethod -Method GET -Headers $headers -Uri "https://api.github.com/repos/$( $pr.base.repo.full_name )/pulls/$( $pr.number )"
                $commitsDiff = Invoke-RestMethod -Method GET -Headers $headers -Uri "https://api.github.com/repos/$( $pr.base.repo.full_name )/compare/$( $pr.base.ref )...$( $pr.head.sha )"
                if ($commitsDiff.behind_by -gt 0) {
                    "PR behind_by: $( $commitsDiff.behind_by ) commits. Rebasing PR" | Write-Host
                    Execute-Command { git checkout $pr.head.ref }
                    Execute-Command { git fetch origin master }
                    Execute-Command { git rebase origin/master }
                    Execute-Command { git push origin $pr.head.ref -f }
                }else {
                    "PR html_url: $( $pr.html_url )" | Write-Host
                    "PR state: $( $pr.state )" | Write-Host
                    "PR mergeable: $( $pr.mergeable )" | Write-Host
                    "PR merged: $( $pr.merged )" | Write-Host
                    $checkSuites = Invoke-RestMethod -Method GET -Headers $headers -Uri "https://api.github.com/repos/$( $pr.base.repo.full_name )/commits/$( $pr.head.sha )/check-suites" #-Body (@{
                    "PR total check suites: $( $checkSuites.total_count ) " | Write-Host
                    $checkSuiteMostRecent = $checkSuites.check_suites | Sort-Object -Property created_at -Descending | Select-Object -First 1
                    "PR latest check suite status: $( $checkSuiteMostRecent.status )" | Write-Host
                    "PR latest check suite conclusion: $( $checkSuiteMostRecent.conclusion )" | Write-Host
                    if ($pr.mergeable -eq $false) {
                        # NOTE: $pr.mergeable may occasionally be empty when the PR is just created or forced push. Only error when value is 'false'
                        throw "Skip merging PR because it is not mergeable"
                    }
                    if ($pr.mergeable -and $checkSuiteMostRecent.status -eq 'completed' -and $checkSuiteMostRecent.conclusion -eq 'success') { # Successful PR HEAD pipeline
                        "Merging PR" | Write-Host -ForegroundColor Green
                        $prMerge = Invoke-RestMethod -Method PUT -Headers $headers -Uri "https://api.github.com/repos/$( $pr.base.repo.full_name )/pulls/$( $pr.number )/merge" -Body (@{
                            sha = $pr.head.sha
                            merge_method = 'merge'
                        } | ConvertTo-Json -Depth 100)
                        "Merge sha: $( $prMerge.sha )" | Write-Host
                        "Merge merged: $( $prMerge.merged )" | Write-Host
                        "Merge message: $( $prMerge.message )" | Write-Host
                        break
                    }elseif ($pr.mergeable -and $checkSuiteMostRecent.status -eq 'completed' -and !($checkSuiteMostRecent.conclusion -eq 'success')) {
                        throw "Check suite failed. Skip merging"
                    }
                }
                "Checking again in 5 seconds" | Write-Host
                Start-Sleep -Seconds 5
            }
            $pr = Invoke-RestMethod -Method GET -Headers $headers -Uri "https://api.github.com/repos/$( $pr.base.repo.full_name )/pulls/$( $pr.number )"
            $pr
        }
    }catch {
        if ($callerEA -eq 'Stop') {
            throw
        }
        if ($callerEA -eq 'Continue') {
            $msg | Write-Error -ErrorAction Continue
        }
    }
}