Modules/businessdev.ALbuild.Feeds/Private/ConvertTo-BcFeedDefinition.ps1
|
function ConvertTo-BcFeedDefinition { <# .SYNOPSIS Normalises an albuild.json feed entry into a feed definition (name, url, token, idScheme, kind). .DESCRIPTION Internal helper. A feed entry in albuild.json is either: - a plain URL string (everything else defaulted), or - an object: { url, name?, kind?, idScheme?, apiKey?, apiKeyVariable? }. Only 'url' is required. 'kind' and 'idScheme' are optional - the resolver auto-detects metapackage/runtime indirection from package metadata and locates packages by app id via the feed's search service, so they are needed only to override an edge case (a feed that serves both a regular and a runtime app for the same version, or a non-standard id scheme on a feed without a usable search service). A private feed's access key is given inline with 'apiKey' or, to keep it out of the file, by naming an environment variable with 'apiKeyVariable' (a '${env:NAME}' placeholder is also expanded in any field). The legacy 'token'/'tokenEnv' names are still accepted as aliases. .PARAMETER Entry The raw feed entry (string or object from ConvertFrom-Json). .OUTPUTS Hashtable with Name, Url, Token, IdScheme, Kind - or $null when the entry has no URL. #> [CmdletBinding()] [OutputType([hashtable])] param( [Parameter(Mandatory)] [AllowNull()] [object] $Entry ) # Expands '${env:NAME}' placeholders against the current environment. $expandEnv = { param([string] $value) if ([string]::IsNullOrEmpty($value)) { return '' } return [regex]::Replace($value, '\$\{env:([^}]+)\}', { param($m) "$([Environment]::GetEnvironmentVariable($m.Groups[1].Value))" }) } # Reads a field from a string/object/dictionary, case-insensitively, with a default. $field = { param([object] $source, [string] $name, [object] $default) if ($null -eq $source) { return $default } if ($source -is [System.Collections.IDictionary]) { foreach ($key in $source.Keys) { if ("$key" -ieq $name) { return $source[$key] } } return $default } $property = $source.PSObject.Properties | Where-Object { $_.Name -ieq $name } | Select-Object -First 1 if ($property -and $null -ne $property.Value) { return $property.Value } return $default } # Derives a feed name from its URL: the Azure DevOps '_packaging/<name>/' segment, else the host. $nameFromUrl = { param([string] $url) $match = [regex]::Match($url, '_packaging/([^/]+)/') if ($match.Success) { return $match.Groups[1].Value } try { return ([uri] $url).Host } catch { return 'feed' } } if ($Entry -is [string]) { $url = & $expandEnv $Entry if (-not $url) { return $null } return @{ Name = (& $nameFromUrl $url); Url = $url; Token = ''; IdScheme = '{publisher}.{name}.{id}'; Kind = 'apps' } } $url = & $expandEnv "$(& $field $Entry 'url' '')" if (-not $url) { Write-ALbuildLog -Level Warning "Ignoring a feed entry in the project config that has no 'url'." return $null } # Access key for a private feed. Provide it inline with 'apiKey' (a ${env:NAME} placeholder is # still expanded), or name the environment variable that holds it with 'apiKeyVariable'. The # legacy 'token' / 'tokenEnv' names remain accepted as aliases. Inline wins over a variable. $token = & $expandEnv "$(& $field $Entry 'apiKey' (& $field $Entry 'token' ''))" if (-not $token) { $apiKeyVariable = "$(& $field $Entry 'apiKeyVariable' (& $field $Entry 'tokenEnv' ''))" if ($apiKeyVariable) { $token = "$([Environment]::GetEnvironmentVariable($apiKeyVariable))" } } $name = "$(& $field $Entry 'name' '')" if (-not $name) { $name = & $nameFromUrl $url } $idScheme = "$(& $field $Entry 'idScheme' '{publisher}.{name}.{id}')" $kind = "$(& $field $Entry 'kind' 'apps')".ToLowerInvariant() if ($kind -notin @('symbols', 'apps', 'runtime')) { Write-ALbuildLog -Level Warning "Feed '$name' has an unknown kind '$kind'; using 'apps'." $kind = 'apps' } return @{ Name = $name; Url = $url; Token = $token; IdScheme = $idScheme; Kind = $kind } } |