Private/Get-PullRequestUrl.ps1

function Get-PullRequestUrl {
    <#
    .SYNOPSIS
        Builds a provider-specific pull/merge request creation URL from a git remote URL and branch.
    .DESCRIPTION
        Supports GitHub, Azure DevOps (dev.azure.com and *.visualstudio.com), Bitbucket Cloud, and GitLab.
        Both HTTPS and SSH remote formats are accepted.
        Returns the base remote URL for unrecognised providers so the user can navigate manually.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string] $RemoteUrl,

        [Parameter(Mandatory)]
        [string] $Branch,

        # Optional target/base branch (used by Azure DevOps)
        [string] $BaseBranch
    )

    # Normalize Azure DevOps SSH: git@ssh.dev.azure.com:v3/org/project/repo
    if ($RemoteUrl -match '^git@ssh\.dev\.azure\.com:v3/([^/]+)/([^/]+)/(.+?)(?:\.git)?/?$') {
        $RemoteUrl = "https://dev.azure.com/$($Matches[1])/$($Matches[2])/_git/$($Matches[3])"
    }
    # Normalize generic SSH: git@host:owner/repo.git
    elseif ($RemoteUrl -match '^git@([^:]+):(.+?)(?:\.git)?/?$') {
        $RemoteUrl = "https://$($Matches[1])/$($Matches[2])"
    }

    # Strip trailing .git from HTTPS URLs
    $RemoteUrl = $RemoteUrl -replace '\.git/?$', ''

    # GitHub — branch is a path segment, slashes are preserved
    if ($RemoteUrl -match '//github\.com/') {
        return "$RemoteUrl/compare/$Branch`?expand=1"
    }

    # For query-string providers the branch must be fully URL-encoded (including /)
    $encodedBranch = [Uri]::EscapeDataString($Branch)

    # Azure DevOps (modern and legacy visualstudio.com hostname)
    if ($RemoteUrl -match '//dev\.azure\.com/|//[^/]+\.visualstudio\.com/') {
        $targetParam = if ($BaseBranch) { "&targetRef=$([Uri]::EscapeDataString($BaseBranch))" } else { '' }
        return "$RemoteUrl/pullrequestcreate?sourceRef=$encodedBranch$targetParam"
    }

    # Bitbucket Cloud
    if ($RemoteUrl -match '//bitbucket\.org/') {
        return "$RemoteUrl/pull-requests/new?source=$encodedBranch"
    }

    # GitLab
    if ($RemoteUrl -match '//gitlab\.com/|/gitlab\.') {
        return "$RemoteUrl/-/merge_requests/new?merge_request%5Bsource_branch%5D=$encodedBranch"
    }

    # Unknown provider — return the repo root so the user can navigate manually
    return $RemoteUrl
}