import type { WebSiteManagementClient , WebSiteManagementModels } from "@azure/arm-appservice" ; import { ProgressLocation , window } from "vscode" ; import { IActionContext , IAzureNamingRules , IAzureQuickPickItem , ICreateChildImplContext } from "vscode-azureextensionui" ; import { getNewFileShareName } from "./createAppService/getNewFileShareName" ; import { ext } from "./extensionVariables" ; import { localize } from "./localize" ; import { ParsedSite } from './SiteClient' ; import { createWebSiteClient } from "./utils/azureClients" ; export async function createSlot ( site , existingSlots , context ) { const client = await createWebSiteClient ( [ context , site . subscription ] ) ; const slotName = ( await context . ui . showInputBox ( { prompt : localize ( 'enterSlotName' , 'Enter a unique name for the new deployment slot' ) , stepName : 'slotName' , validateInput : async ( value ) : Promise < string | undefined > => validateSlotName ( value , client , site ) } ) ) . trim ( ) ; const newDeploymentSlot = { name : slotName , kind : site . kind , location : site . location , serverFarmId : site . serverFarmId , siteConfig : { appSettings : [ ] } } ; const configurationSource = await chooseConfigurationSource ( context , site , existingSlots ) ; if ( configurationSource ) { const appSettings = await parseAppSettings ( context , configurationSource ) ; newDeploymentSlot . siteConfig ! . appSettings = appSettings ; } context . showCreatingTreeItem ( slotName ) ; const creatingSlot = localize ( 'creatingSlot' , 'Creating slot "{0}"...' , slotName ) ; ext . outputChannel . appendLog ( creatingSlot ) ; return await window . withProgress ( { location : ProgressLocation . Notification , title : creatingSlot } , async ( ) => { return await client . webApps . createOrUpdateSlot ( site . resourceGroup , site . siteName , newDeploymentSlot , slotName ) ; } ) ; } const slotNamingRules = { minLength : 2 , maxLength : 59 , invalidCharsRegExp : /[^a-zA-Z0-9\-]/ } ; async function validateSlotName ( value , client , site ) { value = value . trim ( ) ; if ( value === 'production' ) { return localize ( 'slotNotAvailable' , 'The slot name "{0}" is not available.' , value ) ; } else if ( value . length < slotNamingRules . minLength ) { return localize ( 'nameTooShort' , 'The slot name must be at least {0} characters.' , slotNamingRules . minLength ) ; } else if ( value . length + site . siteName . length > slotNamingRules . maxLength ) { return localize ( 'nameTooLong' , 'The combined site name and slot name must be fewer than {0} characters.' , slotNamingRules . maxLength ) ; } else if ( slotNamingRules . invalidCharsRegExp . test ( value ) ) { return localize ( 'invalidChars' , "The name can only contain letters, numbers, or hyphens." ) ; } else { const nameAvailability = await client . checkNameAvailability ( `${ site . siteName }-${ value }` , 'Slot' ) ; if ( ! nameAvailability . nameAvailable ) { return nameAvailability . message ; } else { return undefined ; } } } async function chooseConfigurationSource ( context , site , existingSlots ) { if ( site . isFunctionApp ) { return site ; } else { const configurationSources = [ { label : localize ( 'dontClone' , "Don't clone configuration from an existing slot" ) , data : undefined } ] ; configurationSources . push ( { label : site . fullName , data : site } ) ; for ( const slot of existingSlots ) { configurationSources . push ( { label : slot . fullName , data : slot } ) ; } const placeHolder = localize ( 'chooseSource' , 'Choose a configuration source.' ) ; return ( await context . ui . showQuickPick ( configurationSources , { placeHolder , stepName : 'slotConfigSource' } ) ) . data ; } } async function parseAppSettings ( context , site ) { const client = await site . createClient ( context ) ; const appSettings = await client . listApplicationSettings ( ) ; const appSettingPairs = [ ] ; if ( appSettings . properties ) { for ( const key of Object . keys ( appSettings . properties ) ) { let value = appSettings . properties [ key ] ; if ( site . isFunctionApp && key === 'WEBSITE_CONTENTSHARE' ) { value = getNewFileShareName ( site . fullName ) ; } appSettingPairs . push ( { name : key , value } ) ; } } return appSettingPairs ; }