private/specs/Get-ServiceSpecPathData.ps1
<#
.SYNOPSIS Get the latest API spec file paths & service/url-PUT paths (in file) for a given ProviderNamespace - ResourceType combination. This includes also child-resources. .DESCRIPTION Get the latest API spec file path & service/url-PUT path (in file) for a given ProviderNamespace - ResourceType combination. This includes also child-resources. .PARAMETER ProviderNamespace Mandatory. The provider namespace to query the data for .PARAMETER ResourceType Mandatory. The resource type to query the data for .PARAMETER RepositoryPath Mandatory. The path of the cloned/downloaded API Specs repository .PARAMETER IncludePreview Optional. Set to also consider 'preview' versions for the request. .EXAMPLE Get-ServiceSpecPathData -ProviderNamespace 'Microsoft.Keyvault' -ResourceType 'vaults' -RepositoryPath './temp/azure-rest-api-specs' -IncludePreview Get the latest API spec file path & service path for the resource type [Microsoft.KeyVault/vaults] - including the latest preview version (if any). Would return (without the JSON format): [ { "urlPath": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.KeyVault/vaults/{vaultName}/keys/{keyName}", "jsonFilePath": "azure-rest-api-specs/specification/keyvault/resource-manager/Microsoft.KeyVault/stable/2022-07-01/keys.json" }, { "urlPath": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.KeyVault/vaults/{vaultName}/accessPolicies/{operationKind}", "jsonFilePath": "azure-rest-api-specs/specification/keyvault/resource-manager/Microsoft.KeyVault/stable/2022-07-01/keyvault.json" }, { "urlPath": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.KeyVault/vaults/{vaultName}", "jsonFilePath": "azure-rest-api-specs/specification/keyvault/resource-manager/Microsoft.KeyVault/stable/2022-07-01/keyvault.json" }, { "urlPath": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.KeyVault/vaults/{vaultName}/privateEndpointConnections/{privateEndpointConnectionName}", "jsonFilePath": "azure-rest-api-specs/specification/keyvault/resource-manager/Microsoft.KeyVault/stable/2022-07-01/keyvault.json" }, { "urlPath": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.KeyVault/vaults/{vaultName}/secrets/{secretName}", "jsonFilePath": "azure-rest-api-specs/specification/keyvault/resource-manager/Microsoft.KeyVault/stable/2022-07-01/secrets.json" } ] #> function Get-ServiceSpecPathData { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $ProviderNamespace, [Parameter(Mandatory = $true)] [string] $ResourceType, [Parameter(Mandatory = $true)] [string] $RepositoryPath, [Parameter(Mandatory = $false)] [switch] $IncludePreview ) #find the resource provider folder $resourceProviderFolders = Get-FolderList -rootFolder (Join-Path $RepositoryPath 'specification') -ProviderNamespace $ProviderNamespace $pathData = @() foreach ($resourceProviderFolder in $resourceProviderFolders) { Write-Verbose ('Processing Resource provider folder [{0}]' -f $resourceProviderFolder) $apiVersionFolders = @() $stablePath = Join-Path $resourceProviderFolder 'stable' if (Test-Path -Path $stablePath) { $apiVersionFolders += (Get-ChildItem -Path $stablePath).FullName } if ($IncludePreview) { # adding preview API versions $previewPath = Join-Path $resourceProviderFolder 'preview' if (Test-Path -Path $previewPath) { $apiVersionFolders += (Get-ChildItem -Path $previewPath).FullName } } # sorting all API version from the newest to the oldest $apiVersionFolders = $apiVersionFolders | Sort-Object -Descending if ($apiVersionFolders.Count -eq 0) { Write-Warning ('No API folder found in folder [{0}]' -f $resourceProviderFolder) continue } # Get one unique instance of each file - with 'newer' files taking priority $specFilePaths = [System.Collections.ArrayList]@() foreach ($apiVersionFolder in $apiVersionFolders) { $filePaths = (Get-ChildItem $apiVersionFolder -Filter '*.json').FullName | Where-Object { (Split-Path $_ -Leaf) -notin @('common.json') } $alreadyIncludedFileNames = $specFilePaths | ForEach-Object { Split-Path $_ -LeafBase } foreach ($filePath in ($filePaths | Where-Object { (Split-Path $_ -LeafBase) -notin @($alreadyIncludedFileNames) })) { $specFilePaths += $filePath } } # Of those paths, get only those that contain a 'put' statement foreach ($specFilePath in $specFilePaths) { $urlPathsOfFile = (ConvertFrom-Json (Get-Content -Raw -Path $specFilePath) -AsHashtable).paths $urlPUTPathsInFile = $urlPathsOfFile.Keys | Where-Object { $urlPathsOfFile[$_].Keys -contains 'put' } foreach ($urlPUTPath in $urlPUTPathsInFile) { # Todo create regex dynamic based on count of '/' in RT # Build regex based in input $formattedProviderNamespace = $ProviderNamespace -replace '\.', '\.' if(($ResourceType -split '/').Count -gt 1) { # Provided a concatinated resource type like 'vaults/secrets' $resourceTypeElements = $ResourceType -split '/' $relevantPathRegex = ".*\/$formattedProviderNamespace\/" # Add each element and incorporate a theoretical 'name' in the path as it is part of each url (e.g. vaults/{vaultName}/keys/{keyName}) # '?' is introduced for urls where a hardcoded name (like 'default') is part of it $relevantPathRegex += $resourceTypeElements -join '\/\{?\w+}?\/' $relevantPathRegex += '.*' } else { $relevantPathRegex = ".*\/{0}\/{1}\/.*" -f $formattedProviderNamespace, $ResourceType } # Filter down to Provider Namespace & Resource Type (or children) if($urlPUTPath -notmatch $relevantPathRegex) { Write-Debug "Ignoring Path PUT URL [$urlPUTPath]" continue } # Populate result $pathData += @{ urlPath = $urlPUTPath jsonFilePath = $specFilePath } } } } # Add parent pointers for later reference foreach($urlPathBlock in $pathData) { $pathElements = $urlPathBlock.urlPath -split '/' $rawparentUrlPath = $pathElements[0..($pathElements.Count-3)] -join '/' if($pathElements[-3] -like "Microsoft.*") { # Top-most element. No parent $parentUrlPath = '' } elseif($rawparentUrlPath -notlike "*}") { # Special case: Parent has a default value in url (e.g. 'default'). In this case we need to find a match in the other urls $shortenedRef = $pathElements[0..($pathElements.Count-4)] -join '/' $formattedRef = [regex]::Escape($shortenedRef) -replace '\/', '\/' $parentUrlPath = $pathData.urlPath | Where-Object { $_ -match "^$formattedRef\/\{\w+\}$"} } else { $parentUrlPath = $rawparentUrlPath } $urlPathBlock['parentUrlPath'] = $parentUrlPath } return $pathData } |