Public/New-PSUADOPullRequest.ps1
function New-PSUADOPullRequest { <# .SYNOPSIS Creates a pull request in Azure DevOps using REST API. .DESCRIPTION This function submits a pull request (PR) from a specified source branch to a target branch in a given Azure DevOps repository. It authenticates using a Personal Access Token (PAT) and allows you to provide custom title and description content. You can specify the repository either by Repository ID or Repository Name. .PARAMETER Organization (Optional) The Azure DevOps organization name under which the project resides. Default value is $env:ORGANIZATION. Set using: Set-PSUUserEnvironmentVariable -Name "ORGANIZATION" -Value "value_of_org_name" .PARAMETER Project (Optional) The Azure DevOps project name containing the repository. Default value is auto-detected from git remote origin URL. .PARAMETER RepoId (Mandatory - ParameterSet: ByRepoId) The repository GUID in which to create the pull request. .PARAMETER Repository (Optional - ParameterSet: ByRepoName) The repository name in which to create the pull request. Default value is auto-detected from git remote origin URL. .PARAMETER SourceBranch (Optional) The full name of the source branch (e.g., 'refs/heads/feature-branch'). Default value is 'refs/heads/' + current git branch from git branch --show-current. .PARAMETER TargetBranch (Optional) The full name of the target branch (e.g., 'refs/heads/main'). Default value is 'refs/heads/' + default branch from git symbolic-ref refs/remotes/origin/HEAD. .PARAMETER Title (Mandatory) The title of the pull request. .PARAMETER Description (Mandatory) The detailed description of the pull request. .PARAMETER Draft (Optional) Switch parameter to create the pull request as a draft. .PARAMETER CompleteOnApproval (Optional) Switch parameter to enable auto-completion when the pull request is approved. The PR will automatically complete when all required approvals and policies are met. .PARAMETER PAT (Optional) Personal Access Token for Azure DevOps authentication. Default value is $env:PAT. Set using: Set-PSUUserEnvironmentVariable -Name "PAT" -Value "value_of_PAT" .EXAMPLE New-PSUADOPullRequest -Organization "myOrganization" -Project "MyProject" -RepoId "12345678-1234-1234-1234-123456789012" ` -SourceBranch "refs/heads/feature-x" -TargetBranch "refs/heads/main" ` -Title "Feature X Implementation" -Description "This PR adds feature X." Creates a pull request using repository ID. .EXAMPLE New-PSUADOPullRequest -Project "MyProject" -Repository "MyRepo" ` -Title "Bug fix for login" -Description "Fixed authentication issue" Creates a pull request using repository name with default source/target branches. .EXAMPLE New-PSUADOPullRequest -Title "Auto-detected PR" -Description "Uses auto-detection for org, project, and repo" Creates a pull request using auto-detected organization, project, and repository from git remote URL. .EXAMPLE New-PSUADOPullRequest -Project "MyProject" -Repository "MyRepo" ` -Title "Bug fix for login" -Description "Fixed authentication issue" -Draft Creates a draft pull request using repository name with default source/target branches. .EXAMPLE New-PSUADOPullRequest -Title "Auto-complete feature" -Description "This will auto-complete when approved" ` -CompleteOnApproval Creates a pull request that will automatically complete when all approvals and policies are satisfied. .EXAMPLE New-PSUADOPullRequest -Organization "myOrganization" -Project "MyProject" -Repository "MyRepo" ` -SourceBranch "refs/heads/feature-branch" -TargetBranch "refs/heads/develop" ` -Title "New Feature" -Description "Added new functionality" -PAT $env:AZDO_PAT Creates a pull request using repository name with specific branches and PAT. .OUTPUTS [PSCustomObject] .NOTES Author: Lakshmanachari Panuganti Date: 2025-07-30 Updated: 2025-08-14 - Added Repository parameter and parameter sets .LINK https://github.com/lakshmanachari-panuganti/OMG.PSUtilities/tree/main/OMG.PSUtilities.AzureDevOps https://www.linkedin.com/in/lakshmanachari-panuganti/ https://www.powershellgallery.com/packages/OMG.PSUtilities.AzureDevOps https://learn.microsoft.com/en-us/rest/api/azure/devops/git/pull-requests/create #> [CmdletBinding(DefaultParameterSetName = 'ByRepoName')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSAvoidUsingWriteHost', '', Justification = 'This is intended for this function to display formatted output to the user on the console' )] param ( [Parameter()] [ValidateNotNullOrEmpty()] [string]$Organization = $(if ($env:ORGANIZATION) { $env:ORGANIZATION } else { git remote get-url origin 2>$null | ForEach-Object { if ($_ -match 'dev\.azure\.com/([^/]+)/') { $matches[1] } } }), [Parameter()] [ValidateNotNullOrEmpty()] [string]$Project = $(git remote get-url origin 2>$null | ForEach-Object { if ($_ -match 'dev\.azure\.com/[^/]+/([^/]+)/_git/') { $matches[1] } }), [Parameter(Mandatory, ParameterSetName = 'ByRepoId')] [ValidateNotNullOrEmpty()] [string]$RepoId, [Parameter(ParameterSetName = 'ByRepoName')] [ValidateNotNullOrEmpty()] [string]$Repository = $(git remote get-url origin 2>$null | ForEach-Object { if ($_ -match '/_git/([^/]+?)(?:\.git)?/?$') { $matches[1] } }), [Parameter()] [ValidateScript({ if ($_ -match '^refs/heads/.+') { $true } else { throw "SourceBranch must be in the format 'refs/heads/branch-name'." } })] [string]$SourceBranch = $("refs/heads/$((git branch --show-current).Trim())"), [Parameter()] [ValidateScript({ if ($_ -match '^refs/heads/.+') { $true } else { throw "TargetBranch must be in the format 'refs/heads/branch-name'." } })] [string]$TargetBranch = $("refs/heads/$((git symbolic-ref refs/remotes/origin/HEAD | Split-Path -Leaf).Trim())"), [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Title, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Description, [Parameter()] [switch]$Draft, [Parameter()] [switch]$CompleteOnApproval, [Parameter()] [ValidateNotNullOrEmpty()] [string]$PAT = $env:PAT ) process { try { # Resolve repository ID if needed $repositoryIdentifier = $null if ($PSCmdlet.ParameterSetName -eq 'ByRepoId') { $repositoryIdentifier = $RepoId } else { $repos = Get-PSUADORepositories -Project $Project -Organization $Organization -PAT $PAT $matchedRepo = $repos | Where-Object { $_.Name -eq $Repository } if (-not $matchedRepo) { throw "Repository '$Repository' not found in project '$Project'." } $repositoryIdentifier = $matchedRepo.Id } # Compose authentication header $headers = Get-PSUAdoAuthHeader -PAT $PAT $body = @{ sourceRefName = $SourceBranch targetRefName = $TargetBranch title = $Title description = ($Description -join "`n") isDraft = $Draft.IsPresent } | ConvertTo-Json -Depth 10 $escapedProject = [uri]::EscapeDataString($Project) $uri = "https://dev.azure.com/$Organization/$escapedProject/_apis/git/repositories/$repositoryIdentifier/pullrequests?api-version=7.0" $draftStatus = if ($Draft.IsPresent) { "draft " } else { "" } Write-Verbose "Creating ${draftStatus}pull request in project: $Project" Write-Verbose "Repository: $repositoryIdentifier" Write-Verbose "Source branch: $SourceBranch" Write-Verbose "Target branch: $TargetBranch" Write-Verbose "API URI: $uri" $response = Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body -ContentType "application/json" -ErrorAction Stop $WebUrl = "https://dev.azure.com/$Organization/$escapedProject/_git/$repositoryIdentifier/pullrequest/$($response.pullRequestId)" $draftText = if ($response.isDraft) { "Draft " } else { "" } Write-Host "${draftText}Pull Request created successfully. PR ID: $($response.pullRequestId)" -ForegroundColor Green Write-Host "PR URL: $WebUrl" -ForegroundColor Cyan # Enable auto-completion if specified if ($CompleteOnApproval) { try { # Set auto-complete options $autoCompleteBody = @{ autoCompleteSetBy = @{ id = $response.createdBy.id } completionOptions = @{ mergeStrategy = "noFastForward" deleteSourceBranch = $false squashMerge = $false } } | ConvertTo-Json -Depth 10 $autoCompleteUri = "https://dev.azure.com/$Organization/$escapedProject/_apis/git/repositories/$repositoryIdentifier/pullrequests/$($response.pullRequestId)?api-version=7.0" Write-Verbose "Setting auto-completion for PR ID: $($response.pullRequestId)" Invoke-RestMethod -Method Patch -Uri $autoCompleteUri -Headers $headers -Body $autoCompleteBody -ContentType "application/json" -ErrorAction Stop Write-Host "Auto-completion enabled. PR will complete automatically when all policies and approvals are satisfied." -ForegroundColor Yellow } catch { Write-Warning "Failed to enable auto-completion: $($_.Exception.Message)" } } [PSCustomObject]@{ Id = $response.pullRequestId Title = $response.title Description = $response.description Status = $response.status IsDraft = $response.isDraft SourceBranch = $response.sourceRefName TargetBranch = $response.targetRefName CreatedBy = $response.createdBy.displayName CreatorEmail = $response.createdBy.uniqueName CreationDate = $response.creationDate RepositoryId = $response.repository.id RepositoryName = $response.repository.name ProjectName = $response.repository.project.name WebUrl = $WebUrl ApiUrl = $response.url CompleteOnApproval = $CompleteOnApproval.IsPresent PSTypeName = 'PSU.ADO.PullRequest' } } catch { $PSCmdlet.ThrowTerminatingError($_) } } } |