-
Notifications
You must be signed in to change notification settings - Fork 17
Add deployRevisionDraft support for all revision modes
#414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
829ab74
f4e8f05
05c617c
7d719eb
9011a88
b15db29
876f2e4
8d0669a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| * Licensed under the MIT License. See License.txt in the project root for license information. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
|
|
||
| import { AzureWizardPromptStep } from "@microsoft/vscode-azext-utils"; | ||
| import { localize } from "../../../utils/localize"; | ||
| import type { IDeployRevisionDraftContext } from "./IDeployRevisionDraftContext"; | ||
|
|
||
| export class DeployRevisionDraftConfirmStep extends AzureWizardPromptStep<IDeployRevisionDraftContext> { | ||
| public async prompt(context: IDeployRevisionDraftContext): Promise<void> { | ||
| await context.ui.showWarningMessage( | ||
| localize('deployRevisionWarning', 'This will deploy a new revision to container app "{0}".', context.containerApp?.name), | ||
| { modal: true }, | ||
| { title: localize('continue', 'Continue') } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would have this title be "Deploy" |
||
| ); | ||
| } | ||
|
|
||
| public shouldPrompt(context: IDeployRevisionDraftContext): boolean { | ||
| return !!context.template; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| * Licensed under the MIT License. See License.txt in the project root for license information. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
|
|
||
| import { KnownActiveRevisionsMode } from "@azure/arm-appcontainers"; | ||
| import { AzureWizardExecuteStep, nonNullProp } from "@microsoft/vscode-azext-utils"; | ||
| import type { Progress } from "vscode"; | ||
| import { ext } from "../../../extensionVariables"; | ||
| import { ContainerAppItem, ContainerAppModel, getContainerEnvelopeWithSecrets } from "../../../tree/ContainerAppItem"; | ||
| import { RevisionDraftItem } from "../../../tree/revisionManagement/RevisionDraftItem"; | ||
| import { localize } from "../../../utils/localize"; | ||
| import { updateContainerApp } from "../../../utils/updateContainerApp"; | ||
| import type { IDeployRevisionDraftContext } from "./IDeployRevisionDraftContext"; | ||
|
|
||
| export class DeployRevisionDraftStep extends AzureWizardExecuteStep<IDeployRevisionDraftContext> { | ||
| public priority: number = 260; | ||
|
|
||
| public async execute(context: IDeployRevisionDraftContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> { | ||
| const containerApp: ContainerAppModel = nonNullProp(context, 'containerApp'); | ||
| const containerAppEnvelope = await getContainerEnvelopeWithSecrets(context, context.subscription, containerApp); | ||
| containerAppEnvelope.template = nonNullProp(context, 'template'); | ||
|
|
||
| const creatingRevision: string = localize('creatingRevision', 'Creating revision...'); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still says revision here. |
||
| progress.report({ message: creatingRevision }); | ||
|
|
||
| const id: string = containerApp.revisionsMode === KnownActiveRevisionsMode.Single ? containerApp.id : `${containerApp.id}/${RevisionDraftItem.idSuffix}`; | ||
|
|
||
| await ext.state.runWithTemporaryDescription(id, creatingRevision, async () => { | ||
| await updateContainerApp(context, context.subscription, containerAppEnvelope); | ||
| const updatedContainerApp = await ContainerAppItem.Get(context, context.subscription, containerApp.resourceGroup, containerApp.name); | ||
|
|
||
| if (containerApp.revisionsMode === KnownActiveRevisionsMode.Multiple) { | ||
| // Display the name of the newly created revision when in multiple revisions mode | ||
| context.activityTitle = localize('deployRevision', 'Deploy revision "{0}" to container app "{1}"', updatedContainerApp.latestRevisionName, containerApp.name); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still says revision here. |
||
| } | ||
| }); | ||
| } | ||
|
|
||
| public shouldExecute(context: IDeployRevisionDraftContext): boolean { | ||
| return !!context.template; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 { Template } from "@azure/arm-appcontainers"; | ||
| import type { ExecuteActivityContext } from "@microsoft/vscode-azext-utils"; | ||
| import type { IContainerAppContext } from "../../IContainerAppContext"; | ||
|
|
||
| export interface IDeployRevisionDraftContext extends IContainerAppContext, ExecuteActivityContext { | ||
| template: Template | undefined; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| * Licensed under the MIT License. See License.txt in the project root for license information. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
|
|
||
| import { ContainerAppsAPIClient, KnownActiveRevisionsMode, Revision } from "@azure/arm-appcontainers"; | ||
| import { uiUtils } from "@microsoft/vscode-azext-azureutils"; | ||
| import { AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext, createSubscriptionContext, nonNullProp } from "@microsoft/vscode-azext-utils"; | ||
| import * as deepEqual from "deep-eql"; | ||
| import { ext } from "../../../extensionVariables"; | ||
| import type { ContainerAppItem, ContainerAppModel } from "../../../tree/ContainerAppItem"; | ||
| import { RevisionDraftItem } from "../../../tree/revisionManagement/RevisionDraftItem"; | ||
| import { createActivityContext } from "../../../utils/activityUtils"; | ||
| import { createContainerAppsAPIClient } from "../../../utils/azureClients"; | ||
| import { delay } from "../../../utils/delay"; | ||
| import { localize } from "../../../utils/localize"; | ||
| import { pickContainerApp } from "../../../utils/pickContainerApp"; | ||
| import { DeployRevisionDraftConfirmStep } from "./DeployRevisionDraftConfirmStep"; | ||
| import { DeployRevisionDraftStep } from "./DeployRevisionDraftStep"; | ||
| import type { IDeployRevisionDraftContext } from "./IDeployRevisionDraftContext"; | ||
|
|
||
| export async function deployRevisionDraft(context: IActionContext, node?: ContainerAppItem | RevisionDraftItem): Promise<void> { | ||
| const item = node ?? await pickContainerApp(context); | ||
|
|
||
| const { subscription, containerApp } = item; | ||
|
|
||
| const wizardContext: IDeployRevisionDraftContext = { | ||
| ...context, | ||
| ...createSubscriptionContext(subscription), | ||
| ...(await createActivityContext()), | ||
| subscription, | ||
| containerApp, | ||
| template: ext.revisionDraftFileSystem.parseRevisionDraft(item), | ||
| }; | ||
|
|
||
| if (!await hasUnsavedChanges(wizardContext, item)) { | ||
| throw new Error(localize('noUnsavedChanges', 'No unsaved changes detected to deploy to container app "{0}".', containerApp.name)); | ||
| } | ||
|
|
||
| const promptSteps: AzureWizardPromptStep<IDeployRevisionDraftContext>[] = [ | ||
| new DeployRevisionDraftConfirmStep() | ||
| ]; | ||
|
|
||
| const executeSteps: AzureWizardExecuteStep<IDeployRevisionDraftContext>[] = [ | ||
| new DeployRevisionDraftStep() | ||
| ]; | ||
|
|
||
| const wizard: AzureWizard<IDeployRevisionDraftContext> = new AzureWizard(wizardContext, { | ||
| title: localize('deploy', 'Deploy changes to container app "{0}"', containerApp.name), | ||
| promptSteps, | ||
| executeSteps, | ||
| }); | ||
|
|
||
| await wizard.prompt(); | ||
| await wizard.execute(); | ||
|
|
||
| if (item.containerApp.revisionsMode === KnownActiveRevisionsMode.Single) { | ||
| ext.revisionDraftFileSystem.discardRevisionDraft(item); | ||
| } else { | ||
| await ext.state.showDeleting( | ||
| `${item.containerApp.id}/${RevisionDraftItem.idSuffix}`, | ||
| async () => { | ||
| // Add a short delay to display the deleting message | ||
| await delay(5); | ||
| ext.revisionDraftFileSystem.discardRevisionDraft(item); | ||
| } | ||
| ); | ||
| } | ||
|
|
||
| ext.state.notifyChildrenChanged(item.containerApp.managedEnvironmentId); | ||
| } | ||
|
|
||
| async function hasUnsavedChanges(context: IDeployRevisionDraftContext, item: ContainerAppItem | RevisionDraftItem): Promise<boolean> { | ||
| const containerApp: ContainerAppModel = nonNullProp(context, 'containerApp'); | ||
|
|
||
| if (context.containerApp?.revisionsMode === KnownActiveRevisionsMode.Single) { | ||
| return !!containerApp.template && !!context.template && !deepEqual(containerApp.template, context.template); | ||
| } else { | ||
| const client: ContainerAppsAPIClient = await createContainerAppsAPIClient(context); | ||
| const revisions: Revision[] = await uiUtils.listAllIterator(client.containerAppsRevisions.listRevisions(containerApp.resourceGroup, containerApp.name)); | ||
|
|
||
| const baseRevisionName: string | undefined = ext.revisionDraftFileSystem.getRevisionDraftFile(item)?.baseRevisionName; | ||
| const baseRevision: Revision | undefined = revisions.find(revision => baseRevisionName && revision.name === baseRevisionName); | ||
|
|
||
| return !!baseRevision?.template && !!context.template && !deepEqual(baseRevision.template, context.template); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should steer away from the word "revision" since we don't really expose that anywhere else. We should probably just have something to the effect that we're "Deploying to container app" or "Updating container app" or something.