diff --git a/package.json b/package.json index 4ec5da9ea..6ae29f193 100644 --- a/package.json +++ b/package.json @@ -96,8 +96,8 @@ "category": "Azure Container Apps" }, { - "command": "containerApps.deployWorkspaceProjectToContainerApp", - "title": "%containerApps.deployWorkspaceProjectToContainerApp%", + "command": "containerApps.deployContainerApp", + "title": "%containerApps.deployContainerApp%", "category": "Azure Container Apps" }, { @@ -377,7 +377,7 @@ "group": "1@2" }, { - "command": "containerApps.deployWorkspaceProjectToContainerApp", + "command": "containerApps.deployContainerApp", "when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /containerAppItem/i", "group": "2@1" }, @@ -587,10 +587,6 @@ "command": "containerApps.createContainerAppFromWorkspace", "when": "never" }, - { - "command": "containerApps.deployWorkspaceProjectToContainerApp", - "when": "never" - }, { "command": "containerApps.deployWorkspaceProjectApi", "when": "never" diff --git a/package.nls.json b/package.nls.json index 32a9d5b4c..a093e6bfd 100644 --- a/package.nls.json +++ b/package.nls.json @@ -21,7 +21,7 @@ "containerApps.deployImageApi": "Deploy Image to Container App (API)...", "containerApps.deployWorkspaceProject": "Deploy Project from Workspace...", "containerApps.deployWorkspaceProjectApi": "Deploy Project from Workspace (API)...", - "containerApps.deployWorkspaceProjectToContainerApp": "Deploy Workspace to Container App...", + "containerApps.deployContainerApp": "Deploy to Container App...", "containerApps.deleteContainerApp": "Delete Container App...", "containerApps.disableIngress": "Disable Ingress for Container App", "containerApps.enableIngress": "Enable Ingress for Container App...", diff --git a/src/commands/createContainerApp/createContainerApp.ts b/src/commands/createContainerApp/createContainerApp.ts index ac4be1393..d48fe606e 100644 --- a/src/commands/createContainerApp/createContainerApp.ts +++ b/src/commands/createContainerApp/createContainerApp.ts @@ -39,7 +39,7 @@ export async function createContainerApp(context: IActionContext, node?: Managed }; if (isAzdExtensionInstalled()) { - wizardContext.telemetry.properties.isAzdWorkspaceProject = 'true'; + wizardContext.telemetry.properties.isAzdExtensionInstalled = 'true'; } // Use the same resource group and location as the parent resource (managed environment) diff --git a/src/commands/deployContainerApp/ContainerAppDeployContext.ts b/src/commands/deployContainerApp/ContainerAppDeployContext.ts new file mode 100644 index 000000000..a73246a12 --- /dev/null +++ b/src/commands/deployContainerApp/ContainerAppDeployContext.ts @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { type IResourceGroupWizardContext } from '@microsoft/vscode-azext-azureutils'; +import { type ExecuteActivityContext } from '@microsoft/vscode-azext-utils'; +import { type IContainerAppContext } from '../IContainerAppContext'; +import { type ImageSourceBaseContext } from '../image/imageSource/ImageSourceContext'; +import { type IngressBaseContext } from '../ingress/IngressContext'; + +export type ContainerAppDeployContext = IResourceGroupWizardContext & ImageSourceBaseContext & IngressBaseContext & IContainerAppContext & ExecuteActivityContext; diff --git a/src/commands/deployContainerApp/deployContainerApp.ts b/src/commands/deployContainerApp/deployContainerApp.ts new file mode 100644 index 000000000..307bd3467 --- /dev/null +++ b/src/commands/deployContainerApp/deployContainerApp.ts @@ -0,0 +1,79 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { type ResourceGroup } from "@azure/arm-resources"; +import { LocationListStep, ResourceGroupListStep } from "@microsoft/vscode-azext-azureutils"; +import { AzureWizard, createSubscriptionContext, nonNullProp, nonNullValue, type IActionContext, type ISubscriptionActionContext, type ISubscriptionContext } from "@microsoft/vscode-azext-utils"; +import { ImageSource } from "../../constants"; +import { type ContainerAppItem } from "../../tree/ContainerAppItem"; +import { createActivityContext } from "../../utils/activityUtils"; +import { isAzdExtensionInstalled } from "../../utils/azdUtils"; +import { getManagedEnvironmentFromContainerApp } from "../../utils/getResourceUtils"; +import { getVerifyProvidersStep } from "../../utils/getVerifyProvidersStep"; +import { localize } from "../../utils/localize"; +import { pickContainerApp } from "../../utils/pickItem/pickContainerApp"; +import { deployWorkspaceProject } from "../deployWorkspaceProject/deployWorkspaceProject"; +import { ContainerAppUpdateStep } from "../image/imageSource/ContainerAppUpdateStep"; +import { ImageSourceListStep } from "../image/imageSource/ImageSourceListStep"; +import { type ContainerAppDeployContext } from "./ContainerAppDeployContext"; + +export async function deployContainerApp(context: IActionContext, node?: ContainerAppItem): Promise { + const item: ContainerAppItem = node ?? await pickContainerApp(context); + const subscriptionContext: ISubscriptionContext = createSubscriptionContext(item.subscription); + const subscriptionActionContext: ISubscriptionActionContext = { ...context, ...subscriptionContext }; + + // Prompt for image source before initializing the wizard in case we need to redirect the call to 'deployWorkspaceProject' instead + const imageSource: ImageSource = await promptImageSource(subscriptionActionContext); + if (imageSource === ImageSource.RemoteAcrBuild) { + await deployWorkspaceProject(context, item); + return; + } + + const wizardContext: ContainerAppDeployContext = { + ...subscriptionActionContext, + ...await createActivityContext(true), + subscription: item.subscription, + containerApp: item.containerApp, + managedEnvironment: await getManagedEnvironmentFromContainerApp(subscriptionActionContext, item.containerApp), + imageSource, + }; + + if (isAzdExtensionInstalled()) { + wizardContext.telemetry.properties.isAzdExtensionInstalled = 'true'; + } + + const resourceGroups: ResourceGroup[] = await ResourceGroupListStep.getResourceGroups(wizardContext); + wizardContext.resourceGroup = nonNullValue( + resourceGroups.find(rg => rg.name === item.containerApp.resourceGroup), + localize('containerAppResourceGroup', 'Expected to find the container app\'s resource group.'), + ); + + await LocationListStep.setLocation(wizardContext, item.containerApp.location); + + const wizard: AzureWizard = new AzureWizard(wizardContext, { + title: localize('deployContainerAppTitle', 'Deploy image to container app'), + promptSteps: [ + new ImageSourceListStep(), + ], + executeSteps: [ + getVerifyProvidersStep(), + new ContainerAppUpdateStep(), + ], + showLoadingPrompt: true + }); + + await wizard.prompt(); + wizardContext.activityTitle = localize('deployContainerAppActivityTitle', 'Deploy image to container app "{0}"', wizardContext.containerApp?.name); + await wizard.execute(); +} + +async function promptImageSource(context: ISubscriptionActionContext): Promise { + const promptContext: ISubscriptionActionContext & { imageSource?: ImageSource } = context; + + const imageSourceStep: ImageSourceListStep = new ImageSourceListStep(); + await imageSourceStep.prompt(promptContext); + + return nonNullProp(promptContext, 'imageSource'); +} diff --git a/src/commands/image/imageSource/ImageSourceListStep.ts b/src/commands/image/imageSource/ImageSourceListStep.ts index e6b8951be..70f2b2dd7 100644 --- a/src/commands/image/imageSource/ImageSourceListStep.ts +++ b/src/commands/image/imageSource/ImageSourceListStep.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { AzureWizardPromptStep, type AzureWizardExecuteStep, type IAzureQuickPickItem, type IWizardOptions } from "@microsoft/vscode-azext-utils"; +import { AzureWizardPromptStep, type AzureWizardExecuteStep, type IAzureQuickPickItem, type ISubscriptionActionContext, type IWizardOptions } from "@microsoft/vscode-azext-utils"; import { UIKind, env, workspace } from "vscode"; import { ImageSource } from "../../../constants"; import { localize } from "../../../utils/localize"; @@ -33,7 +33,7 @@ export class ImageSourceListStep extends AzureWizardPromptStep { + public async prompt(context: ISubscriptionActionContext & { imageSource?: ImageSource, showQuickStartImage?: boolean }): Promise { const imageSourceLabels: string[] = [ localize('containerRegistryLabel', 'Container Registry'), localize('quickstartImageLabel', 'Quickstart'), diff --git a/src/commands/registerCommands.ts b/src/commands/registerCommands.ts index 3239087fa..b01c94b66 100644 --- a/src/commands/registerCommands.ts +++ b/src/commands/registerCommands.ts @@ -10,6 +10,7 @@ import { createContainerApp } from './createContainerApp/createContainerApp'; import { createManagedEnvironment } from './createManagedEnvironment/createManagedEnvironment'; import { deleteContainerApp } from './deleteContainerApp/deleteContainerApp'; import { deleteManagedEnvironment } from './deleteManagedEnvironment/deleteManagedEnvironment'; +import { deployContainerApp } from './deployContainerApp/deployContainerApp'; import { deployWorkspaceProject } from './deployWorkspaceProject/deployWorkspaceProject'; import { editContainer } from './editContainer/editContainer'; import { editContainerImage } from './editContainer/editContainerImage/editContainerImage'; @@ -82,7 +83,7 @@ export function registerCommands(): void { registerCommandWithTreeNodeUnwrapping('containerApps.deployImageApi', deployImageApi); registerCommandWithTreeNodeUnwrapping('containerApps.deployRevisionDraft', deployRevisionDraft); registerCommandWithTreeNodeUnwrapping('containerApps.deployWorkspaceProject', deployWorkspaceProject); - registerCommandWithTreeNodeUnwrapping('containerApps.deployWorkspaceProjectToContainerApp', deployWorkspaceProject); + registerCommandWithTreeNodeUnwrapping('containerApps.deployContainerApp', deployContainerApp); // github registerCommandWithTreeNodeUnwrapping('containerApps.connectToGitHub', connectToGitHub);