diff --git a/package.json b/package.json index aff482298..d7fe00c3f 100644 --- a/package.json +++ b/package.json @@ -226,6 +226,12 @@ "shortTitle": "%containerApps.editEnvironmentVariableValue.shortTitle%", "category": "Azure Container Apps" }, + { + "command": "containerApps.convertEnvironmentVariable", + "title": "%containerApps.convertEnvironmentVariable.title%", + "shortTitle": "%containerApps.convertEnvironmentVariable.shortTitle%", + "category": "Azure Container Apps" + }, { "command": "containerApps.editEnvironmentVariables", "title": "%containerApps.editEnvironmentVariables%", @@ -522,6 +528,11 @@ "when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /environmentVariableItem/i", "group": "1@2" }, + { + "command": "containerApps.convertEnvironmentVariable", + "when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /environmentVariableItem/i", + "group": "1@3" + }, { "command": "containerApps.deleteEnvironmentVariable", "when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /environmentVariableItem/i", diff --git a/package.nls.json b/package.nls.json index c0ecc08b7..5f4caa2ef 100644 --- a/package.nls.json +++ b/package.nls.json @@ -17,6 +17,8 @@ "containerApps.editEnvironmentVariableName.shortTitle": "Edit Name...", "containerApps.editEnvironmentVariableValue.title": "Edit Environment Variable Value...", "containerApps.editEnvironmentVariableValue.shortTitle": "Edit Value...", + "containerApps.convertEnvironmentVariable.title": "Convert Environment Variable to Secret...", + "containerApps.convertEnvironmentVariable.shortTitle": "Convert to Secret...", "containerApps.editEnvironmentVariables": "Edit Environment Variables (.env)...", "containerApps.deleteEnvironmentVariable.title": "Delete Environment Variable...", "containerApps.deleteEnvironmentVariable.shortTitle": "Delete...", diff --git a/src/commands/EXECUTE_PRIORITY.md b/src/commands/EXECUTE_PRIORITY.md index 36f189686..f7eaf23d1 100644 --- a/src/commands/EXECUTE_PRIORITY.md +++ b/src/commands/EXECUTE_PRIORITY.md @@ -93,15 +93,28 @@ When creating or updating resources, execute steps should occupy certain priorit - SecretCreateStep: 820 - SecretUpdateStep: 850 -### 8. Unallocated Space +### 8. Environment Variables -Priority Range: 900 - 1090 +Priority Range: 900 - 990 + +#### Steps + +- EnvironmentVariablesEditDraftStep: 920 (single command) + + +- EnvironmentVariableAddDraftStep: 940 (single command) +- EnvironmentVariableEditDraftStep: 960 (single command) +- EnvironmentVariableDeleteDraftStep: 980 (single command) + +### 9. Unallocated Space + +Priority Range: 1000 - 1090 #### Steps - Reserved for future commands TBD. -### 9. Scaling +### 10. Scaling Priority Range: 1100 - 1190 @@ -109,7 +122,7 @@ When creating or updating resources, execute steps should occupy certain priorit - AddScaleRuleStep: 1120 (revision draft) -### 10. Unallocated Space +### 11. Unallocated Space Priority Range: 1200 - 1390 @@ -117,7 +130,7 @@ When creating or updating resources, execute steps should occupy certain priorit - Reserved for future commands TBD. -### 11. Deploy +### 12. Deploy Priority Range: 1400 - 1490 diff --git a/src/commands/environmentVariables/addEnvironmentVariable/EnvironmentVariableAddDraftStep.ts b/src/commands/environmentVariables/addEnvironmentVariable/EnvironmentVariableAddDraftStep.ts index 57b266290..8061208b0 100644 --- a/src/commands/environmentVariables/addEnvironmentVariable/EnvironmentVariableAddDraftStep.ts +++ b/src/commands/environmentVariables/addEnvironmentVariable/EnvironmentVariableAddDraftStep.ts @@ -12,7 +12,7 @@ import { RevisionDraftUpdateBaseStep } from "../../revisionDraft/RevisionDraftUp import { type EnvironmentVariableAddContext } from "./EnvironmentVariableAddContext"; export class EnvironmentVariableAddDraftStep extends RevisionDraftUpdateBaseStep { - public priority: number = 590; + public priority: number = 940; constructor(baseItem: ContainerAppItem | RevisionsItemModel) { super(baseItem); diff --git a/src/commands/environmentVariables/convertEnvironmentVariable/EnvironmentVariableConvertContext.ts b/src/commands/environmentVariables/convertEnvironmentVariable/EnvironmentVariableConvertContext.ts new file mode 100644 index 000000000..cc5a3e454 --- /dev/null +++ b/src/commands/environmentVariables/convertEnvironmentVariable/EnvironmentVariableConvertContext.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the MIT License. See License.md in the project root for license information. +*--------------------------------------------------------------------------------------------*/ + +import { type ContainerUpdateTelemetryProps as TelemetryProps } from "../../../telemetry/commandTelemetryProps"; +import { type SetTelemetryProps } from "../../../telemetry/SetTelemetryProps"; +import { type ISecretContext } from "../../secret/ISecretContext"; +import { type EnvironmentVariableEditBaseContext } from "../editEnvironmentVariable/EnvironmentVariableEditContext"; + +export interface EnvironmentVariableConvertBaseContext extends EnvironmentVariableEditBaseContext, ISecretContext { + // Make newSecretValue required + newSecretValue: string; +} + +export type EnvironmentVariableConvertContext = EnvironmentVariableConvertBaseContext & SetTelemetryProps; diff --git a/src/commands/environmentVariables/convertEnvironmentVariable/convertEnvironmentVariable.ts b/src/commands/environmentVariables/convertEnvironmentVariable/convertEnvironmentVariable.ts new file mode 100644 index 000000000..0b389d50f --- /dev/null +++ b/src/commands/environmentVariables/convertEnvironmentVariable/convertEnvironmentVariable.ts @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the MIT License. See License.md in the project root for license information. +*--------------------------------------------------------------------------------------------*/ + +import { AzureWizard, createSubscriptionContext, nonNullValueAndProp, type IActionContext, type ISubscriptionContext } from "@microsoft/vscode-azext-utils"; +import { type EnvironmentVariableItem } from "../../../tree/containers/EnvironmentVariableItem"; +import { createActivityContext } from "../../../utils/activityUtils"; +import { getManagedEnvironmentFromContainerApp } from "../../../utils/getResourceUtils"; +import { getVerifyProvidersStep } from "../../../utils/getVerifyProvidersStep"; +import { localize } from "../../../utils/localize"; +import { pickEnvironmentVariable } from "../../../utils/pickItem/pickEnvironmentVariables"; +import { isTemplateItemEditable, TemplateItemNotEditableError } from "../../../utils/revisionDraftUtils"; +import { RevisionDraftDeployPromptStep } from "../../revisionDraft/RevisionDraftDeployPromptStep"; +import { SecretCreateStep } from "../../secret/addSecret/SecretCreateStep"; +import { SecretNameStep } from "../../secret/addSecret/SecretNameStep"; +import { EnvironmentVariableType } from "../addEnvironmentVariable/EnvironmentVariableTypeListStep"; +import { EnvironmentVariableEditDraftStep } from "../editEnvironmentVariable/EnvironmentVariableEditDraftStep"; +import { type EnvironmentVariableConvertContext } from "./EnvironmentVariableConvertContext"; + +/** + * Automatically convert a 'Manual Input' environment variable to use a container app secret instead + */ +export async function convertEnvironmentVariable(context: IActionContext, node?: EnvironmentVariableItem): Promise { + const item: EnvironmentVariableItem = node ?? await pickEnvironmentVariable(context, { autoSelectDraft: true }); + const { subscription, containerApp } = item; + + if (!isTemplateItemEditable(item)) { + throw new TemplateItemNotEditableError(item); + } + + if (item.envVariable.secretRef) { + throw new Error(localize('alreadySecret', 'The environment variable you chose to convert already uses a secret reference.')); + } + + const subscriptionContext: ISubscriptionContext = createSubscriptionContext(subscription); + const wizardContext: EnvironmentVariableConvertContext = { + ...context, + ...subscriptionContext, + ...await createActivityContext(true), + subscription, + managedEnvironment: await getManagedEnvironmentFromContainerApp({ ...context, ...subscriptionContext }, containerApp), + containerApp, + containersIdx: item.containersIdx, + environmentVariable: item.envVariable, + newSecretValue: nonNullValueAndProp(item.envVariable, 'value'), + newEnvironmentVariableType: EnvironmentVariableType.SecretRef, + isDraftCommand: true, + }; + wizardContext.telemetry.properties.revisionMode = containerApp.revisionsMode; + + const wizard: AzureWizard = new AzureWizard(wizardContext, { + title: localize('convertEnvironmentVariableTitle', 'Convert environment variable "{0}" to use a secret (draft)', wizardContext.environmentVariable.name), + promptSteps: [ + new SecretNameStep(), + new RevisionDraftDeployPromptStep(), + ], + executeSteps: [ + getVerifyProvidersStep(), + new SecretCreateStep(), + new EnvironmentVariableEditDraftStep(item), + ], + }); + + await wizard.prompt(); + wizardContext.activityTitle = localize('convertEnvironmentVariableActivityTitle', 'Convert environment variable "{0}" to use secret "{1}" (draft)', wizardContext.environmentVariable.name, wizardContext.newSecretName); + await wizard.execute(); +} diff --git a/src/commands/environmentVariables/deleteEnvironmentVariable/EnvironmentVariableDeleteDraftStep.ts b/src/commands/environmentVariables/deleteEnvironmentVariable/EnvironmentVariableDeleteDraftStep.ts index bc6d9d40f..0f8cbbaa6 100644 --- a/src/commands/environmentVariables/deleteEnvironmentVariable/EnvironmentVariableDeleteDraftStep.ts +++ b/src/commands/environmentVariables/deleteEnvironmentVariable/EnvironmentVariableDeleteDraftStep.ts @@ -12,7 +12,7 @@ import { RevisionDraftUpdateBaseStep } from "../../revisionDraft/RevisionDraftUp import { type EnvironmentVariableDeleteContext } from "./EnvironmentVariableDeleteContext"; export class EnvironmentVariableDeleteDraftStep extends RevisionDraftUpdateBaseStep { - public priority: number = 590; + public priority: number = 980; constructor(baseItem: ContainerAppItem | RevisionsItemModel) { super(baseItem); diff --git a/src/commands/environmentVariables/editEnvironmentVariable/EnvironmentVariableEditContext.ts b/src/commands/environmentVariables/editEnvironmentVariable/EnvironmentVariableEditContext.ts index 1948620ca..1f2e79cbd 100644 --- a/src/commands/environmentVariables/editEnvironmentVariable/EnvironmentVariableEditContext.ts +++ b/src/commands/environmentVariables/editEnvironmentVariable/EnvironmentVariableEditContext.ts @@ -6,9 +6,9 @@ import { type EnvironmentVar } from "@azure/arm-appcontainers"; import { type SetTelemetryProps } from "../../../telemetry/SetTelemetryProps"; import { type ContainerUpdateTelemetryProps as TelemetryProps } from "../../../telemetry/commandTelemetryProps"; -import { type EnvironmentVariableAddContext } from "../addEnvironmentVariable/EnvironmentVariableAddContext"; +import { type EnvironmentVariableAddBaseContext } from "../addEnvironmentVariable/EnvironmentVariableAddContext"; -export interface EnvironmentVariableEditBaseContext extends EnvironmentVariableAddContext { +export interface EnvironmentVariableEditBaseContext extends EnvironmentVariableAddBaseContext { // Require the environment variable upfront so we can make edits environmentVariable: EnvironmentVar; } diff --git a/src/commands/environmentVariables/editEnvironmentVariable/EnvironmentVariableEditDraftStep.ts b/src/commands/environmentVariables/editEnvironmentVariable/EnvironmentVariableEditDraftStep.ts index f85ea1248..b75c1d101 100644 --- a/src/commands/environmentVariables/editEnvironmentVariable/EnvironmentVariableEditDraftStep.ts +++ b/src/commands/environmentVariables/editEnvironmentVariable/EnvironmentVariableEditDraftStep.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { type Container, type EnvironmentVar } from "@azure/arm-appcontainers"; -import { nonNullValue } from "@microsoft/vscode-azext-utils"; +import { activityFailContext, activityFailIcon, activitySuccessContext, activitySuccessIcon, createUniversallyUniqueContextValue, GenericParentTreeItem, GenericTreeItem, nonNullValue, type ExecuteActivityOutput } from "@microsoft/vscode-azext-utils"; import { type Progress } from "vscode"; import { type ContainerAppItem } from "../../../tree/ContainerAppItem"; import { type RevisionsItemModel } from "../../../tree/revisionManagement/RevisionItem"; @@ -14,7 +14,7 @@ import { EnvironmentVariableType } from "../addEnvironmentVariable/EnvironmentVa import { type EnvironmentVariableEditContext } from "./EnvironmentVariableEditContext"; export class EnvironmentVariableEditDraftStep extends RevisionDraftUpdateBaseStep { - public priority: number = 590; + public priority: number = 960; constructor(baseItem: ContainerAppItem | RevisionsItemModel) { super(baseItem); @@ -49,4 +49,26 @@ export class EnvironmentVariableEditDraftStep extends RevisionDraftUpdateBaseStep { - public priority: number = 590; + public priority: number = 920; constructor(baseItem: ContainerAppItem | RevisionsItemModel) { super(baseItem); diff --git a/src/commands/secret/addSecret/SecretCreateStep.ts b/src/commands/secret/addSecret/SecretCreateStep.ts index ab90c74d7..d7451a334 100644 --- a/src/commands/secret/addSecret/SecretCreateStep.ts +++ b/src/commands/secret/addSecret/SecretCreateStep.ts @@ -3,16 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { AzureWizardExecuteStep, nonNullProp } from "@microsoft/vscode-azext-utils"; +import { nonNullProp } from "@microsoft/vscode-azext-utils"; import { type Progress } from "vscode"; import { ext } from "../../../extensionVariables"; import { getContainerEnvelopeWithSecrets, type ContainerAppModel } from "../../../tree/ContainerAppItem"; import { localize } from "../../../utils/localize"; +import { AzureWizardActivityOutputExecuteStep } from "../../AzureWizardActivityOutputExecuteStep"; import { updateContainerApp } from "../../updateContainerApp"; import { type ISecretContext } from "../ISecretContext"; -export class SecretCreateStep extends AzureWizardExecuteStep { +export class SecretCreateStep extends AzureWizardActivityOutputExecuteStep { public priority: number = 820; + public stepName: string = 'secretCreateStep'; + protected getSuccessString = (context: T) => localize('createSecretSuccess', 'Successfully created secret "{0}" for container app "{1}".', context.secretName, context.containerApp?.name); + protected getFailString = (context: T) => localize('createSecretFail', 'Failed to create secret "{0}" for container app "{1}".', context.newSecretName, context.containerApp?.name); + protected getTreeItemLabel = (context: T) => localize('createSecretLabel', 'Create secret "{0}" for container app "{1}"', context.secretName, context.containerApp?.name); public async execute(context: ISecretContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise { const containerApp: ContainerAppModel = nonNullProp(context, 'containerApp');