Modules/businessdev.ALbuild.Feeds/Public/ConvertFrom-BcRemoteUrl.ps1
|
function ConvertFrom-BcRemoteUrl { <# .SYNOPSIS Derives the Azure DevOps organization and project from a git remote URL. .DESCRIPTION The org/project a project-scoped Universal feed needs used to be parsed with a single regex that only matched the HTTPS remote format (dev.azure.com/{org}/{project}/_git/...). Azure Pipelines checks out exactly that way, so the pipeline worked; an SSH-based checkout (our agents / any SSH clone) uses the SSH v3 form (git@ssh.dev.azure.com:v3/{org}/{project}/{repo}), which the HTTPS regex does NOT match - the project came back empty, the Universal download ran org-scoped, the project-scoped feed was not found, and the failure surfaced much later as AL1024 on publish. This function recognizes every common Azure DevOps remote format so org/project resolve the same regardless of how the repo was cloned: * HTTPS https://[user@]dev.azure.com/{org}/{project}/_git/{repo} * Legacy HTTPS https://{org}.visualstudio.com/{project}/_git/{repo} * SSH v3 [user@]ssh.dev.azure.com:v3/{org}/{project}/{repo} * SSH host-alias <alias>:v3/{org}/{project}/{repo} (a ~/.ssh/config Host alias) Returns empty strings for both when nothing is recognized (e.g. a non-Azure-DevOps remote), so the caller can fall back to org-scoped behaviour without a hard failure. .PARAMETER RemoteUrl The output of `git remote get-url origin` (or any git remote URL). .OUTPUTS PSCustomObject with Organization (a full https://dev.azure.com/{org}/ URL, or '') and Project (the URL-decoded project name, or ''). The project name is URL-encoded in every remote format (e.g. 'Dynamics%20365%20...') and is decoded here. #> [CmdletBinding()] [OutputType([PSCustomObject])] param([string] $RemoteUrl) $result = [PSCustomObject]@{ Organization = ''; Project = '' } if ([string]::IsNullOrWhiteSpace($RemoteUrl)) { return $result } $u = $RemoteUrl.Trim() $org = ''; $proj = '' switch -Regex ($u) { # HTTPS: https://[user@]dev.azure.com/{org}/{project}/_git/{repo} 'dev\.azure\.com/([^/]+)/([^/]+)/_git/' { $org = $matches[1]; $proj = $matches[2]; break } # Legacy HTTPS: https://{org}.visualstudio.com/{project}/_git/{repo} '://([^./@]+)\.visualstudio\.com/([^/]+)/_git/' { $org = $matches[1]; $proj = $matches[2]; break } # SSH v3 (real host ssh.dev.azure.com OR a Host alias): [user@]<host>:v3/{org}/{project}[/repo] ':v3/([^/]+)/([^/]+)' { $org = $matches[1]; $proj = $matches[2]; break } } if ($org) { $result.Organization = if ($org -match '^https?://') { $org } else { "https://dev.azure.com/$org/" } # The project name is URL-encoded in every format (e.g. 'Dynamics%20365%20...'). $result.Project = [uri]::UnescapeDataString($proj) } return $result } |