Public/Complete-PSUGithubPullRequest.ps1
|
function Complete-PSUGithubPullRequest { <# .SYNOPSIS Completes (merges) a pull request in GitHub using REST API. .DESCRIPTION This function merges an open pull request in GitHub by its number and optionally deletes the source branch afterwards. It supports the merge, squash, and rebase strategies offered by the GitHub pull request merge API. .PARAMETER Owner (Optional) The GitHub repository owner (username or organization). Default value is auto-detected from git remote origin URL. .PARAMETER Repository (Optional) The GitHub repository name. Default value is auto-detected from git remote origin URL. .PARAMETER PullRequestNumber (Mandatory) The number/ID of the pull request to complete. .PARAMETER MergeMethod (Optional) The merge strategy to use: - 'merge': Create a merge commit - 'squash': Squash the commits into a single commit - 'rebase': Rebase the commits onto the base branch Default value is 'merge'. .PARAMETER CommitTitle (Optional) The title of the merge commit. GitHub generates one when omitted. .PARAMETER CommitMessage (Optional) The body of the merge commit. GitHub generates one when omitted. .PARAMETER DeleteBranch (Optional) Switch parameter to delete the source branch after a successful merge. .PARAMETER Token (Optional) GitHub Personal Access Token for authentication. Default value is $env:GITHUB_TOKEN. Set using: Set-PSUUserEnvironmentVariable -Name "GITHUB_TOKEN" -Value "value_of_token" .EXAMPLE Complete-PSUGithubPullRequest -PullRequestNumber 42 Merges pull request #42 using auto-detected repository and a merge commit. .EXAMPLE Complete-PSUGithubPullRequest -PullRequestNumber 42 -MergeMethod "squash" -DeleteBranch Squash merges pull request #42 and deletes the source branch. .EXAMPLE Complete-PSUGithubPullRequest -Owner "myuser" -Repository "myrepo" -PullRequestNumber 42 -CommitTitle "Feature complete" Merges pull request #42 in an explicit repository with a custom merge commit title. .OUTPUTS [PSCustomObject] .NOTES Author: Lakshmanachari Panuganti Date: 6th August 2026 Requires: GitHub Personal Access Token with repo permissions .LINK https://github.com/lakshmanachari-panuganti/OMG.PSUtilities/tree/main/OMG.PSUtilities.Core https://www.linkedin.com/in/lakshmanachari-panuganti/ https://www.powershellgallery.com/packages/OMG.PSUtilities.Core https://docs.github.com/en/rest/pulls/pulls#merge-a-pull-request #> [CmdletBinding(SupportsShouldProcess)] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSAvoidUsingWriteHost', '', Justification = 'This is intended for this function to display formatted output to the user on the console' )] param ( [Parameter()] [string]$Owner, [Parameter()] [string]$Repository, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [int]$PullRequestNumber, [Parameter()] [ValidateSet('merge', 'squash', 'rebase')] [string]$MergeMethod = 'merge', [Parameter()] [string]$CommitTitle, [Parameter()] [string]$CommitMessage, [Parameter()] [switch]$DeleteBranch, [Parameter()] [ValidateNotNullOrEmpty()] [string]$Token = $env:GITHUB_TOKEN ) process { try { if (-not $Owner -or -not $Repository) { $remoteUrl = git remote get-url origin 2>$null if (-not $remoteUrl) { throw "No git remote origin found and Owner/Repository not specified." } if ($remoteUrl -match 'github\.com[/:]([^/]+)/([^/]+?)(?:\.git)?/?$') { if (-not $Owner) { $Owner = $matches[1] } if (-not $Repository) { $Repository = $matches[2] } } else { throw "Could not parse GitHub repository from remote URL: $remoteUrl. Please specify Owner and Repository parameters." } } if (-not $Token) { throw "GitHub token not found. Set it using: Set-PSUUserEnvironmentVariable -Name 'GITHUB_TOKEN' -Value 'your-token'" } $headers = @{ 'Authorization' = "Bearer $Token" 'Accept' = 'application/vnd.github.v3+json' 'X-GitHub-Api-Version' = '2022-11-28' } $prUri = "https://api.github.com/repos/$Owner/$Repository/pulls/$PullRequestNumber" Write-Verbose "Getting pull request details from: $prUri" $prDetails = Invoke-RestMethod -Method Get -Uri $prUri -Headers $headers -ErrorAction Stop if ($prDetails.state -ne 'open') { throw "Pull request #$PullRequestNumber is '$($prDetails.state)' and cannot be completed." } $body = @{ merge_method = $MergeMethod } if ($CommitTitle) { $body.commit_title = $CommitTitle } if ($CommitMessage) { $body.commit_message = $CommitMessage } $bodyJson = $body | ConvertTo-Json -Depth 10 $mergeUri = "$prUri/merge" Write-Verbose "Completing pull request #$PullRequestNumber in repository: $Owner/$Repository" Write-Verbose "Merge method: $MergeMethod" Write-Verbose "API URI: $mergeUri" if (-not $PSCmdlet.ShouldProcess("$Owner/$Repository pull request #$PullRequestNumber", "Complete with $MergeMethod")) { return } $response = Invoke-RestMethod -Method Put -Uri $mergeUri -Headers $headers -Body $bodyJson -ContentType "application/json" -ErrorAction Stop Write-Host "Successfully completed pull request #$PullRequestNumber" -ForegroundColor Green Write-Host "PR URL: $($prDetails.html_url)" -ForegroundColor Cyan $sourceBranch = $prDetails.head.ref $branchDeleted = $false if ($DeleteBranch -and $response.merged) { $branchUri = "https://api.github.com/repos/$Owner/$Repository/git/refs/heads/$sourceBranch" Write-Verbose "Deleting source branch: $sourceBranch" try { Invoke-RestMethod -Method Delete -Uri $branchUri -Headers $headers -ErrorAction Stop | Out-Null $branchDeleted = $true Write-Host "Deleted source branch: $sourceBranch" -ForegroundColor Green } catch { Write-Warning "Merged pull request #$PullRequestNumber but could not delete branch '$sourceBranch': $($_.Exception.Message)" } } [PSCustomObject]@{ PullRequestNumber = $PullRequestNumber Merged = $response.merged MergeMethod = $MergeMethod MergeCommitSha = $response.sha Message = $response.message SourceBranch = $sourceBranch TargetBranch = $prDetails.base.ref BranchDeleted = $branchDeleted Owner = $Owner Repository = $Repository PullRequestUrl = $prDetails.html_url PSTypeName = 'PSU.GitHub.PullRequestCompletion' } } catch { $PSCmdlet.ThrowTerminatingError($_) } } } |