functions/Update-Repo.ps1

function Update-Repo {
    param (
        [Parameter(Mandatory=$true)]
        [string] $OrgName,

        [Parameter(Mandatory=$true)]
        [string] $RepoName,

        [Parameter(Mandatory=$true)]
        [string] $BranchName,

        [Parameter(Mandatory=$true)]
        [scriptblock] $RepoChanges,

        [Parameter(Mandatory=$true)]
        [string] $CommitMessage,

        [Parameter(Mandatory=$true)]
        [string] $PrTitle,

        [Parameter()]
        [array] $RepoChangesArguments = @(),
       
        [Parameter()]
        [string] $PrBody = " ",

        [Parameter()]
        [string[]] $PrLabels,

        [Parameter()]
        [switch] $PassThruPullRequestUri,

        [Parameter()]
        [switch] $WhatIf
    )

    $RepoUrl = "https://github.com/$OrgName/$($RepoName).git"

    # Handle GitHub authentication based on whether running in GitHub Actions workflow or not
    if ( [string]::IsNullOrEmpty($env:GITHUB_TOKEN) -and (Test-Path env:\GITHUB_WORKFLOW) ) {
        Write-Error "The environment variable GITHUB_TOKEN is not set"
        exit
    }
    elseif ([string]::IsNullOrEmpty($env:GITHUB_TOKEN)) {
        Write-Information "GITHUB_TOKEN environment variable not present - triggering interactive login..."
        gh auth login

        # handle cross-platform path differences
        if ($IsWindows) {
            $configPath = Join-Path $env:APPDATA "GitHub CLI"
        }
        else {
            $configPath = "~/.config/gh"
        }
        $ghConfig = Get-Content (Join-Path $configPath "hosts.yml") -Raw | ConvertFrom-Yaml
        $env:GITHUB_TOKEN = $ghConfig."github.com".oauth_token
    }

    if ('no_release' -in $PrLabels) {
        Write-Information "Checking for 'no_release' label"
        $resp = Assert-GitHubLabel -OrgName $OrgName `
                                -RepoName $RepoName `
                                -Name 'no_release' `
                                -Description 'Suppresses auto_release functionality' `
                                -Color '27e8b4' `
                                -Verbose:$False
    }

    $tempDir = New-TemporaryDirectory
    Push-Location $tempDir.FullName
    try {
        Write-Information "Created temporary directory: $($tempDir.FullName)"

        Write-Information "Cloning: $RepoUrl"
        git clone $RepoUrl . | Write-Information
        if ($LASTEXITCODE -ne 0) { throw "git cli returned non-zero exit code cloning the repo - check previous log messages" }

        # Check whether the branch already exists on the remote
        if ( $(git ls-remote --heads $RepoUrl $BranchName) ) {
            Write-Information "Checking-out existing branch: $BranchName"
            git checkout $BranchName | Write-Information
            if ($LASTEXITCODE -ne 0) { throw "git cli returned non-zero exit code checking out existing branch - check previous log messages" }
            
            $defaultBranch = Get-GitHubRepoDefaultBranch -OrgName $OrgName -RepoName $RepoName
            Write-Information "Syncing branch with $defaultBranch"
            git merge $defaultBranch | Write-Information
            if ($LASTEXITCODE -ne 0) { throw "git cli returned non-zero exit code rebasing against master - check previous log messages" }
        }
        else {
            Write-Information "Creating new branch: $BranchName"
            git checkout -b $BranchName | Write-Information
            if ($LASTEXITCODE -ne 0) { throw "git cli returned non-zero exit code checking out new branch - check previous log messages" }
        }

        $isUpdated = $RepoChanges.Invoke($RepoChangesArguments)

        if ($isUpdated) {
            if (!$WhatIf) {
                Write-Information "Committing changes"
                git add . | Write-Information
                if ($LASTEXITCODE -ne 0) { throw "git cli returned non-zero exit code staging files ('$LASTEXITCODE') - check previous log messages" }
                
                $noChanges = $false
                $output = git commit -m $CommitMessage
                if ($LASTEXITCODE -ne 0) {
                    if ($output -match 'nothing to commit') {
                        $noChanges = $true
                        Write-Information "git detected no changes - skipping update"
                        # reset $LASTEXITCODE to avoid subsequent mis-interpretation
                        $LASTEXITCODE = 0
                    }
                    else {
                        throw "git cli returned non-zero exit code committing changes ('$LASTEXITCODE'):`n$output"
                    }
                }
                
                if ( -not $noChanges ) {
                    Write-Information "Pushing branch"
                    git push -u origin $BranchName | Write-Information
                    if ($LASTEXITCODE -ne 0) { Write-Error "git cli returned non-zero exit code when pushing branch ('$LASTEXITCODE') - check logs" }

                    # Check whether this branch already has an open PR (i.e. where pr-autoflow isn't installed or after a previous failure)
                    $existingPr = Test-GitHubPrByBranchName -OrgName $OrgName `
                                                            -RepoName $RepoName `
                                                            -BranchName $BranchName
                    if (!$existingPr) {
                        Write-Information "Opening new PR"
                        $ghPrArgs = @("pr", "create", "--title", $PrTitle, "--body", $PrBody, "--repo", "$OrgName/$RepoName")
                        if ($PrLabels) { $ghPrArgs += @("--label", $PrLabels) }
                        gh @ghPrArgs | Write-Information
                        if ($LASTEXITCODE -ne 0) { throw "github cli returned non-zero exit code - check previous log messages" }
                    }
                    else {
                        Write-Information "Existing PR will be updated"
                    }

                    # Optional feature to return the URI for the PR used above
                    if ($PassThruPullRequestUri) {
                        $pr = Get-GitHubPrByBranchName -OrgName $OrgName `
                                                       -RepoName $RepoName `
                                                       -BranchName $BranchName
                        return $pr.url
                    }
                }
            }
            else {
                Write-Information "What if: Would have committed changes and created new PR"
            }
        }
        else {
            Write-Information "Repo was unchanged"
        }
    }
    finally {
        Pop-Location
        Write-Verbose "Deleting temporary directory: $($tempDir.FullName)"
        Remove-Item $tempDir -Recurse -Force
    }
}