title: localize()

in apps/vs-code-designer/src/app/commands/deploy/deploy.ts [139:401]


          title: localize('aadDetails', 'Provide your AAD identity details to use with your Azure connections.'),
        });
        await wizard.prompt();
      }
      identityWizardContext.useAdvancedIdentity = true;
    }
  }

  identityWizardContext?.useAdvancedIdentity ? await updateAppSettingsWithIdentityDetails(context, node, identityWizardContext) : undefined;

  let isZipDeploy = false;

  if (!isHybridLogicApp) {
    await verifyAppSettings(context, node, version, language, originalDeployFsPath, !context.isNewApp);
    const client = await node.site.createClient(actionContext);
    const siteConfig: SiteConfigResource = await client.getSiteConfig();
    isZipDeploy = siteConfig.scmType !== ScmType.LocalGit && siteConfig.scmType !== ScmType.GitHub;

    if (getWorkspaceSetting<boolean>(showDeployConfirmationSetting, workspaceFolder.uri.fsPath) && !context.isNewApp && isZipDeploy) {
      const warning: string = localize(
        'confirmDeploy',
        'Are you sure you want to deploy to "{0}"? This will overwrite any previous deployment and cannot be undone.',
        client.fullName
      );
      context.telemetry.properties.cancelStep = 'confirmDestructiveDeployment';
      const deployButton: MessageItem = { title: localize('deploy', 'Deploy') };
      await context.ui.showWarningMessage(warning, { modal: true }, deployButton, DialogResponses.cancel);
      context.telemetry.properties.cancelStep = '';
    }

    await runPreDeployTask(context, effectiveDeployFsPath, siteConfig.scmType);

    if (isZipDeploy) {
      validateGlobSettings(context, effectiveDeployFsPath);
    }
  }

  await node.runWithTemporaryDescription(context, localize('deploying', 'Deploying...'), async () => {
    // preDeploy tasks are only required for zipdeploy so subpath may not exist
    let deployFsPath: string = effectiveDeployFsPath;

    if (!isZipDeploy && !isPathEqual(effectiveDeployFsPath, originalDeployFsPath)) {
      deployFsPath = originalDeployFsPath;
      const noSubpathWarning = `WARNING: Ignoring deploySubPath "${getWorkspaceSetting(
        deploySubpathSetting,
        originalDeployFsPath
      )}" for non-zip deploy.`;
      ext.outputChannel.appendLog(noSubpathWarning);
    }

    if (isWorkflowApp) {
      await cleanupPublishBinPath(context, effectiveDeployFsPath);
    }

    deployProjectPathForWorkflowApp = isWorkflowApp
      ? await getProjectPathToDeploy(node, workspaceFolder, settingsToExclude, deployFsPath, identityWizardContext, actionContext)
      : undefined;

    try {
      if (isHybridLogicApp) {
        await deployHybridLogicApp(context, node);
      } else {
        await innerDeploy(
          node.site,
          deployProjectPathForWorkflowApp !== undefined ? deployProjectPathForWorkflowApp : deployFsPath,
          context
        );
      }
    } finally {
      if (deployProjectPathForWorkflowApp !== undefined && !isHybridLogicApp) {
        await cleanAndRemoveDeployFolder(deployProjectPathForWorkflowApp);
      }
    }
  });

  if (!isHybridLogicApp) {
    await node.loadAllChildren(context);
  }
  await notifyDeployComplete(node, context.workspaceFolder, isHybridLogicApp, settingsToExclude);
}

/**
 * Shows tree item picker to select Logic App or create a new one.
 * @param {IActionContext} context - Command context.
 * @returns {Promise<SlotTreeItem>} Logic App slot tree item.
 */
async function getDeployLogicAppNode(context: IActionContext): Promise<SlotTreeItem> {
  const placeHolder: string = localize('selectLogicApp', 'Select Logic App (Standard) in Azure');
  const sub = await ext.rgApi.appResourceTree.showTreeItemPicker<AzExtParentTreeItem>(SubscriptionTreeItem.contextValue, context);

  let [site, isAdvance] = (await context.ui.showQuickPick(getLogicAppsPicks(context, sub.subscription), { placeHolder })).data;
  if (!site) {
    if (isAdvance) {
      return await createLogicAppAdvanced(context, sub);
    }
    return await createLogicApp(context, sub);
  }

  if (site.id.includes('Microsoft.App')) {
    // NOTE(anandgmenon): Getting latest metadata for hybrid app as the one loaded from the cache can have outdateed definition and cause deployment to fail.
    const clientContainer = await createContainerClient({ ...context, ...sub.subscription });
    site = (await clientContainer.containerApps.get(site.id.split('/')[4], site.name)) as undefined as Site;
  }
  const resourceTree = new LogicAppResourceTree(sub.subscription, site);

  return new SlotTreeItem(sub, resourceTree);
}

async function getLogicAppsPicks(
  context: IActionContext,
  subContext: ISubscriptionContext
): Promise<IAzureQuickPickItem<[Site | undefined, boolean]>[]> {
  const logicAppsResolver = new LogicAppResolver();
  const sites = await logicAppsResolver.getAppResourceSiteBySubscription(context, subContext);
  const picks: { label: string; data: [Site, boolean]; description?: string }[] = [];

  Array.from(sites.logicApps).forEach(([_id, site]) => {
    picks.push({ label: site.name, data: [site, false] });
  });

  Array.from(sites.hybridLogicApps).forEach(([_id, site]) => {
    picks.push({ label: `${site.name} (Hybrid)`, data: [site as unknown as Site, false] });
  });

  picks.sort((a, b) => a.label.localeCompare(b.label));
  picks.unshift({
    label: localize('selectLogicApp', '$(plus) Create new Logic App (Standard) in Azure...'),
    data: [undefined, true],
    description: localize('advanced', 'Advanced'),
  });
  picks.unshift({ label: localize('selectLogicApp', '$(plus) Create new Logic App (Standard) in Azure...'), data: [undefined, false] });

  return picks;
}

/**
 * Azure functions task `_GenerateFunctionsExtensionsMetadataPostPublish` moves `NetFxWorker`
 * in `bin/` of publish path, It needs to be reverted as it's a special case where we have a
 * Azure Function Extension inside a Logic App Extension.
 * @param context {@link IActionContext}
 * @param fsPath publish path for logic app extension
 */
async function cleanupPublishBinPath(_context: IActionContext, fsPath: string): Promise<void> {
  const netFxWorkerBinPath = path.join(fsPath, 'bin', 'NetFxWorker');
  const netFxWorkerAssetPath = path.join(fsPath, 'NetFxWorker');
  if (await fse.pathExists(netFxWorkerBinPath)) {
    return fse.move(netFxWorkerBinPath, netFxWorkerAssetPath, { overwrite: true });
  }
}

async function validateGlobSettings(context: IActionContext, fsPath: string): Promise<void> {
  const includeKey = 'zipGlobPattern';
  const excludeKey = 'zipIgnorePattern';
  const includeSetting: string | undefined = getWorkspaceSetting(includeKey, fsPath);
  const excludeSetting: string | string[] | undefined = getWorkspaceSetting(excludeKey, fsPath);

  if (includeSetting || excludeSetting) {
    context.telemetry.properties.hasOldGlobSettings = 'true';
    const message: string = 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);
  }
}

async function managedApiConnectionsExists(workspaceFolder: WorkspaceFolder): Promise<boolean> {
  const workspaceFolderPath = workspaceFolder.uri.fsPath;
  const connectionsJson = await getConnectionsJson(workspaceFolderPath);
  let connectionsData: ConnectionsData;

  try {
    connectionsData = JSON.parse(connectionsJson);
  } catch {
    return false;
  }

  return !!connectionsData.managedApiConnections && Object.keys(connectionsData.managedApiConnections).length > 0;
}

async function getProjectPathToDeploy(
  node: SlotTreeItem,
  workspaceFolder: WorkspaceFolder,
  settingsToExclude: string[],
  originalDeployFsPath: string,
  identityWizardContext: IIdentityWizardContext,
  actionContext: IActionContext
): Promise<string | undefined> {
  const workspaceFolderPath = workspaceFolder.uri.fsPath;
  const connectionsJson = await getConnectionsJson(workspaceFolderPath);
  const parametersJson = await getParametersJson(workspaceFolderPath);
  const targetAppSettings = await node.getApplicationSettings(identityWizardContext as IDeployContext);
  const parameterizeConnectionsSetting = getGlobalSetting(parameterizeConnectionsInProjectLoadSetting);
  let resolvedConnections: ConnectionsData;
  let connectionsData: ConnectionsData;

  function updateAuthenticationParameters(authValue: any): void {
    if (connectionsData.managedApiConnections && Object.keys(connectionsData.managedApiConnections).length) {
      for (const referenceKey of Object.keys(connectionsData.managedApiConnections)) {
        parametersJson[`${referenceKey}-Authentication`].value = authValue;
        actionContext.telemetry.properties.updateAuth = `updated "${referenceKey}-Authentication" parameter to ManagedServiceIdentity`;
      }
    }
  }

  function updateAuthenticationInConnections(authValue: any): void {
    if (connectionsData.managedApiConnections && Object.keys(connectionsData.managedApiConnections).length) {
      for (const referenceKey of Object.keys(connectionsData.managedApiConnections)) {
        connectionsData.managedApiConnections[referenceKey].authentication = authValue;
        actionContext.telemetry.properties.updateAuth = `updated "${referenceKey}" connection authentication to ManagedServiceIdentity`;
      }
    }
  }

  try {
    connectionsData = JSON.parse(connectionsJson);
    const authValue = { type: 'ManagedServiceIdentity' };
    const advancedIdentityAuthValue = {
      type: 'ActiveDirectoryOAuth',
      audience: 'https://management.core.windows.net/',
      credentialType: 'Secret',
      clientId: `@appsetting('${workflowAppAADClientId}')`,
      tenant: `@appsetting('${workflowAppAADTenantId}')`,
      secret: `@appsetting('${workflowAppAADClientSecret}')`,
    };

    if (parameterizeConnectionsSetting) {
      identityWizardContext?.useAdvancedIdentity
        ? updateAuthenticationParameters(advancedIdentityAuthValue)
        : updateAuthenticationParameters(authValue);
    } else {
      identityWizardContext?.useAdvancedIdentity
        ? updateAuthenticationInConnections(advancedIdentityAuthValue)
        : updateAuthenticationInConnections(authValue);
    }

    resolvedConnections = resolveConnectionsReferences(connectionsJson, parametersJson, targetAppSettings);
  } catch {
    actionContext.telemetry.properties.noAuthUpdate = 'No authentication update was made';
    return undefined;
  }

  if (connectionsData.managedApiConnections && Object.keys(connectionsData.managedApiConnections).length) {
    const deployProjectPath = path.join(path.dirname(workspaceFolderPath), `${path.basename(workspaceFolderPath)}-deploytemp`);
    const connectionsFilePathDeploy = path.join(deployProjectPath, connectionsFileName);
    const parametersFilePathDeploy = path.join(deployProjectPath, parametersFileName);

    if (await fse.pathExists(deployProjectPath)) {
      await cleanAndRemoveDeployFolder(deployProjectPath);
    }

    fse.mkdirSync(deployProjectPath);

    await fse.copy(originalDeployFsPath, deployProjectPath, { overwrite: true });

    for (const referenceKey of Object.keys(connectionsData.managedApiConnections)) {
      try {
        const connection = resolvedConnections.managedApiConnections[referenceKey].connection;
        await createAclInConnectionIfNeeded(identityWizardContext, connection.id, node.site);

        if (node.site.isSlot) {