import { HttpOperationResponse , ServiceClient } from '@azure/ms-rest-js' ; import { createGenericClient , IAzureQuickPickItem , parseError } from 'vscode-azureextensionui' ; import { hiddenStacksSetting } from '../../../constants' ; import { FuncVersion } from '../../../FuncVersion' ; import { localize } from '../../../localize' ; import { getWorkspaceSetting } from '../../../vsCodeConfig/settings' ; import { FullFunctionAppStack , IFunctionAppWizardContext } from '../IFunctionAppWizardContext' ; import { backupStacks } from './backupStacks' ; import { AppStackMinorVersion } from './models/AppStackModel' ; import { FunctionAppRuntimes , FunctionAppStack } from './models/FunctionAppStackModel' ; export async function getStackPicks ( context ) { const stacks = ( await getStacks ( context ) ) . filter ( s => ! context . stackFilter || context . stackFilter === s . value ) ; const picks = [ ] ; for ( const stack of stacks ) { for ( const majorVersion of stack . majorVersions ) { const minorVersions = majorVersion . minorVersions . filter ( mv => { return ( mv . stackSettings . linuxRuntimeSettings && mv . stackSettings . linuxRuntimeSettings . supportedFunctionsExtensionVersions . includes ( context . version ) ) || ( mv . stackSettings . windowsRuntimeSettings && mv . stackSettings . windowsRuntimeSettings . supportedFunctionsExtensionVersions . includes ( context . version ) ) ; } ) ; for ( const minorVersion of minorVersions ) { let description ; const previewOs = getFlagOs ( minorVersion . stackSettings , 'isPreview' ) ; switch ( previewOs ) { case 'All' : description = localize ( 'preview' , '(Preview)' ) ; break ; case 'Linux' : case 'Windows' : description = localize ( 'previewOnOS' , '(Preview on {0})' , previewOs ) ; break ; } const earlyAccessOS = getFlagOs ( minorVersion . stackSettings , 'isEarlyAccess' ) ; switch ( earlyAccessOS ) { case 'All' : description = localize ( 'earlyAccess' , '(Early Access)' ) ; break ; case 'Linux' : case 'Windows' : description = localize ( 'earlyAccessOnOS' , '(Early Access on {0})' , earlyAccessOS ) ; break ; } const deprecatedOS = getFlagOs ( minorVersion . stackSettings , 'isDeprecated' ) ; switch ( deprecatedOS ) { case 'All' : description = localize ( 'deprecated' , '(Deprecated)' ) ; break ; case 'Linux' : case 'Windows' : description = localize ( 'deprecatedOnOS' , '(Deprecated on {0})' , deprecatedOS ) ; break ; } picks . push ( { label : minorVersion . displayText , description , group : stack . displayText , data : { stack , majorVersion , minorVersion } } ) ; } } } return picks . sort ( ( p1 , p2 ) => { return p1 . data . stack . value !== p2 . data . stack . value ? 0 : getPriority ( p1 . data . minorVersion . stackSettings ) - getPriority ( p2 . data . minorVersion . stackSettings ) ; } ) ; } type FlagOS = 'All' | 'Linux' | 'Windows' | 'None' ; function getFlagOs ( ss , key ) { if ( [ ss . linuxRuntimeSettings , ss . windowsRuntimeSettings ] . every ( s => ! s || s [ key ] ) ) { return 'All' ; } else if ( ss . linuxRuntimeSettings ?. [ key ] ) { return 'Linux' ; } else if ( ss . windowsRuntimeSettings ?. [ key ] ) { return 'Windows' ; } else { return 'None' ; } } function getPriority ( ss ) { if ( getFlagOs ( ss , 'isDefault' ) !== 'None' ) { return 1 ; } else if ( getFlagOs ( ss , 'isEarlyAccess' ) === 'All' ) { return 3 ; } else if ( getFlagOs ( ss , 'isPreview' ) === 'All' ) { return 4 ; } else if ( getFlagOs ( ss , 'isHidden' ) === 'All' ) { return 5 ; } else if ( getFlagOs ( ss , 'isDeprecated' ) === 'All' ) { return 6 ; } else { return 2 ; } } type StacksArmResponse = { value : { properties : FunctionAppStack ; } [ ] ; } ; async function getStacks ( context ) { if ( ! context . _stacks ) { let stacksArmResponse ; try { const client = await createGenericClient ( context , context ) ; const result = await client . sendRequest ( { method : 'GET' , pathTemplate : '/providers/Microsoft.Web/functionappstacks' , queryParameters : { 'api-version' : '2020-10-01' , removeDeprecatedStacks : String ( ! getWorkspaceSetting < boolean > ( 'showDeprecatedStacks' ) ) } } ) ; stacksArmResponse = < StacksArmResponse > result . parsedBody ; } catch ( error ) { stacksArmResponse = < StacksArmResponse > JSON . parse ( backupStacks ) ; context . telemetry . properties . getStacksError = parseError ( error ) . message ; } context . _stacks = stacksArmResponse . value . map ( d => d . properties ) ; removeHiddenStacksAndProperties ( context . _stacks ) ; } return context . _stacks ; } function removeHiddenStacksAndProperties ( stacks ) { const showHiddenStacks = getWorkspaceSetting < boolean > ( hiddenStacksSetting ) ; for ( const stack of stacks ) { for ( const major of stack . majorVersions ) { for ( const minor of major . minorVersions ) { if ( major . value === 'dotnet5' ) { if ( minor . stackSettings . linuxRuntimeSettings ) { minor . stackSettings . linuxRuntimeSettings . isHidden = false ; } if ( minor . stackSettings . windowsRuntimeSettings ) { minor . stackSettings . windowsRuntimeSettings . isHidden = false ; } } if ( ! showHiddenStacks ) { if ( minor . stackSettings . linuxRuntimeSettings ?. isHidden ) { delete minor . stackSettings . linuxRuntimeSettings ; } if ( minor . stackSettings . windowsRuntimeSettings ?. isHidden ) { delete minor . stackSettings . windowsRuntimeSettings ; } } if ( minor . stackSettings . windowsRuntimeSettings ?. supportedFunctionsExtensionVersions . includes ( FuncVersion . v3 ) && minor . stackSettings . windowsRuntimeSettings ?. supportedFunctionsExtensionVersions . includes ( FuncVersion . v4 ) ) { delete minor . stackSettings . windowsRuntimeSettings . siteConfigPropertiesDictionary . netFrameworkVersion ; } } } } }