import { WebSiteManagementModels } from '@azure/arm-appservice' ; import * as vscode from 'vscode' ; import { deploy as innerDeploy , getDeployFsPath , getDeployNode , IDeployContext , IDeployPaths , showDeployConfirmation } from 'vscode-azureappservice' ; import { DialogResponses , IActionContext } from 'vscode-azureextensionui' ; import { deploySubpathSetting , ProjectLanguage , remoteBuildSetting , ScmType } from '../../constants' ; import { ext } from '../../extensionVariables' ; import { addLocalFuncTelemetry } from '../../funcCoreTools/getLocalFuncCoreToolsVersion' ; import { FuncVersion } from '../../FuncVersion' ; import { localize } from '../../localize' ; import { ProductionSlotTreeItem } from '../../tree/ProductionSlotTreeItem' ; import { SlotTreeItem } from '../../tree/SlotTreeItem' ; import { SlotTreeItemBase } from '../../tree/SlotTreeItemBase' ; import { dotnetUtils } from '../../utils/dotnetUtils' ; import { isPathEqual } from '../../utils/fs' ; import { getWorkspaceSetting } from '../../vsCodeConfig/settings' ; import { verifyInitForVSCode } from '../../vsCodeConfig/verifyInitForVSCode' ; import { tryGetFunctionProjectRoot } from '../createNewProject/verifyIsProject' ; import { notifyDeployComplete } from './notifyDeployComplete' ; import { runPreDeployTask } from './runPreDeployTask' ; import { validateRemoteBuild } from './validateRemoteBuild' ; import { verifyAppSettings } from './verifyAppSettings' ; export async function deployProductionSlot ( context , target ? , functionAppId ? ) { await deploy ( context , target , functionAppId , ProductionSlotTreeItem . contextValue ) ; } export async function deploySlot ( context , target ? , functionAppId ? ) { await deploy ( context , target , functionAppId , SlotTreeItem . contextValue ) ; } async function deploy ( actionContext , arg1 , arg2 , expectedContextValue ) { const deployPaths = await getDeployFsPath ( actionContext , arg1 ) ; addLocalFuncTelemetry ( actionContext , deployPaths . workspaceFolder . uri . fsPath ) ; const context = Object . assign ( actionContext , deployPaths , { defaultAppSetting : 'defaultFunctionAppToDeploy' } ) ; const node = await getDeployNode ( context , ext . tree , arg1 , arg2 , expectedContextValue ) ; const [ language , version ] = await verifyInitForVSCode ( context , context . effectiveDeployFsPath ) ; context . telemetry . properties . projectLanguage = language ; context . telemetry . properties . projectRuntime = version ; if ( language === ProjectLanguage . Python && ! node . site . isLinux ) { context . errorHandling . suppressReportIssue = true ; throw new Error ( localize ( 'pythonNotAvailableOnWindows' , 'Python projects are not supported on Windows Function Apps. Deploy to a Linux Function App instead.' ) ) ; } const client = await node . site . createClient ( actionContext ) ; const siteConfig = await client . getSiteConfig ( ) ; const isConsumption = await client . getIsConsumption ( actionContext ) ; let isZipDeploy = siteConfig . scmType !== ScmType . LocalGit && siteConfig . scmType !== ScmType . GitHub ; if ( ! isZipDeploy && node . site . isLinux && isConsumption ) { ext . outputChannel . appendLog ( localize ( 'linuxConsZipOnly' , 'WARNING: Using zip deploy because scm type "{0}" is not supported on Linux consumption' , siteConfig . scmType ) , { resourceName : node . site . fullName } ) ; isZipDeploy = true ; context . deployMethod = 'zip' ; } const doRemoteBuild = getWorkspaceSetting < boolean > ( remoteBuildSetting , deployPaths . effectiveDeployFsPath ) ; actionContext . telemetry . properties . scmDoBuildDuringDeployment = String ( doRemoteBuild ) ; if ( doRemoteBuild ) { await validateRemoteBuild ( context , node . site , context . workspaceFolder , language ) ; } if ( isZipDeploy && node . site . isLinux && isConsumption && ! doRemoteBuild ) { context . deployMethod = 'storage' ; } if ( getWorkspaceSetting < boolean > ( 'showDeployConfirmation' , context . workspaceFolder . uri . fsPath ) && ! context . isNewApp && isZipDeploy ) { await showDeployConfirmation ( context , node . site , 'azureFunctions.deploy' ) ; } await runPreDeployTask ( context , context . effectiveDeployFsPath , siteConfig . scmType ) ; if ( isZipDeploy ) { void validateGlobSettings ( context , context . effectiveDeployFsPath ) ; } if ( language === ProjectLanguage . CSharp && ! node . site . isLinux ) { await updateWorkerProcessTo64BitIfRequired ( context , siteConfig , node , language ) ; } if ( isZipDeploy ) { const projectPath = await tryGetFunctionProjectRoot ( context , deployPaths . workspaceFolder ) ; await verifyAppSettings ( context , node , projectPath , version , language , { doRemoteBuild , isConsumption } ) ; } await node . runWithTemporaryDescription ( context , localize ( 'deploying' , 'Deploying...' ) , async ( ) => { context . stopAppBeforeDeploy = language === ProjectLanguage . Java ; let deployFsPath = context . effectiveDeployFsPath ; if ( ! isZipDeploy && ! isPathEqual ( context . effectiveDeployFsPath , context . originalDeployFsPath ) ) { deployFsPath = context . originalDeployFsPath ; const noSubpathWarning = `WARNING: Ignoring deploySubPath "${ getWorkspaceSetting ( deploySubpathSetting , context . originalDeployFsPath ) }" for non-zip deploy.` ; ext . outputChannel . appendLog ( noSubpathWarning ) ; } await innerDeploy ( node . site , deployFsPath , context ) ; } ) ; await notifyDeployComplete ( context , node , context . workspaceFolder ) ; } async function updateWorkerProcessTo64BitIfRequired ( context , siteConfig , node , language ) { const functionProject = await tryGetFunctionProjectRoot ( context , context . workspaceFolder ) ; if ( functionProject === undefined ) { return ; } const projectFiles = await dotnetUtils . getProjFiles ( context , language , functionProject ) ; if ( projectFiles . length !== 1 ) { return ; } const platformTarget = await dotnetUtils . tryGetPlatformTarget ( projectFiles [ 0 ] ) ; if ( platformTarget === 'x64' && siteConfig . use32BitWorkerProcess === true ) { const message = localize ( 'overwriteSetting' , 'The remote app targets "{0}", but your local project targets "{1}". Update remote app to "{1}"?' , '32 bit' , '64 bit' ) ; const deployAnyway = { title : localize ( 'deployAnyway' , 'Deploy Anyway' ) } ; const dialogResult = await context . ui . showWarningMessage ( message , { modal : true , stepName : 'mismatch64bit' } , DialogResponses . yes , deployAnyway ) ; if ( dialogResult === deployAnyway ) { return ; } const config = { use32BitWorkerProcess : false } ; const client = await node . site . createClient ( context ) ; await client . updateConfiguration ( config ) ; } } async function validateGlobSettings ( context , fsPath ) { const includeKey = 'zipGlobPattern' ; const excludeKey = 'zipIgnorePattern' ; const includeSetting = getWorkspaceSetting ( includeKey , fsPath ) ; const excludeSetting = getWorkspaceSetting ( excludeKey , fsPath ) ; if ( includeSetting || excludeSetting ) { context . telemetry . properties . hasOldGlobSettings = 'true' ; const message = localize ( 'globSettingRemoved' , '"{0}" and "{1}" settings are no longer supported. Instead, place a ".funcignore" file at the root of your repo, using the same syntax as a ".gitignore" file.' , includeKey , excludeKey ) ; await context . ui . showWarningMessage ( message , { stepName : 'globSettingRemoved' } ) ; } }