Skip to content
Merged
1 change: 1 addition & 0 deletions extension.bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export * from './src/commands/ingress/tryGetDockerfileExposePorts';
export { activate, deactivate } from './src/extension';
export * from './src/extensionVariables';
export * from './src/utils/azureClients';
export * from './src/utils/imageNameUtils';
export * from './src/utils/settingUtils';
export * from './src/utils/validateUtils';

Expand Down
19 changes: 12 additions & 7 deletions src/commands/image/deployImageApi/deployImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { AzureWizard, createSubscriptionContext, type AzureWizardExecuteStep, type AzureWizardPromptStep, type IActionContext, type ISubscriptionContext } from "@microsoft/vscode-azext-utils";
import { AzureWizard, createSubscriptionContext, type AzureWizardPromptStep, type IActionContext, type ISubscriptionContext } from "@microsoft/vscode-azext-utils";
import { type ContainerAppItem } from "../../../tree/ContainerAppItem";
import { createActivityContext } from "../../../utils/activityUtils";
import { getManagedEnvironmentFromContainerApp } from "../../../utils/getResourceUtils";
import { getVerifyProvidersStep } from "../../../utils/getVerifyProvidersStep";
import { getImageNameWithoutTag } from "../../../utils/imageNameUtils";
import { localize } from "../../../utils/localize";
import { ContainerAppOverwriteConfirmStep } from "../../ContainerAppOverwriteConfirmStep";
import { showContainerAppNotification } from "../../createContainerApp/showContainerAppNotification";
import { IngressPromptStep } from "../../ingress/IngressPromptStep";
import { ContainerAppUpdateStep } from "../imageSource/ContainerAppUpdateStep";
import { ImageSourceListStep } from "../imageSource/ImageSourceListStep";
import { type ContainerRegistryImageSourceContext } from "../imageSource/containerRegistry/ContainerRegistryImageSourceContext";
Expand All @@ -33,18 +35,21 @@ export async function deployImage(context: IActionContext & Partial<ContainerReg

const promptSteps: AzureWizardPromptStep<DeployImageApiContext>[] = [
new ImageSourceListStep(),
new ContainerAppOverwriteConfirmStep(),
];

const executeSteps: AzureWizardExecuteStep<DeployImageApiContext>[] = [
getVerifyProvidersStep<DeployImageApiContext>(),
new ContainerAppUpdateStep()
];
// If more than the image tag changed, prompt for ingress again
if (getImageNameWithoutTag(wizardContext.containerApp?.template?.containers?.[0].image ?? '') !== getImageNameWithoutTag(wizardContext.image ?? '')) {
promptSteps.push(new IngressPromptStep());
}
promptSteps.push(new ContainerAppOverwriteConfirmStep());

const wizard: AzureWizard<DeployImageApiContext> = new AzureWizard(wizardContext, {
title: localize('deploy', 'Deploy image to container app "{0}"', containerApp.name),
promptSteps,
executeSteps,
executeSteps: [
getVerifyProvidersStep<DeployImageApiContext>(),
new ContainerAppUpdateStep(),
],
showLoadingPrompt: true
});

Expand Down
4 changes: 4 additions & 0 deletions src/utils/imageNameUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ export function parseImageName(imageName?: string): ParsedImageName {
};
}

export function getImageNameWithoutTag(imageName: string): string {
return imageName.replace(/:[^:]*$/, '');
}

/**
* @param registryName When parsed from a full image name, everything before the first slash
*/
Expand Down
61 changes: 61 additions & 0 deletions test/imageNameUtils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as assert from "assert";
import { getImageNameWithoutTag } from "../extension.bundle";

suite('imageNameUtils', () => {
test('getImageNameWithoutTag', () => {
const testValues: string[] = [
'',
'myimage:latest',
'repository/name:1.0.0',
'custom-registry.com/myimage:v2',
'library/ubuntu:20.04',
'project/service-name:dev-build',
'docker.io/library/nginx:stable',
'my-repo/my-service:release-candidate',
'anotherrepo/anotherimage:test',
'image_without_tag',
'my-image:with:multiple:colons',
'some-registry.io/nested/repo/image:12345',
'edgecase-without-tag:',
'dockerhub.com/image-name:alpha-beta',
'registry.example.com:5000/repo/image:tagname',
'private-repo/myimage:',
'test-image-with-special-characters:beta@123',
'path/to/image:no-colon-in-name',
'simple-image:another:tag',
'example.com:8080/repo/image:v3'
];

const expectedValues: string[] = [
'',
'myimage',
'repository/name',
'custom-registry.com/myimage',
'library/ubuntu',
'project/service-name',
'docker.io/library/nginx',
'my-repo/my-service',
'anotherrepo/anotherimage',
'image_without_tag',
'my-image:with:multiple',
'some-registry.io/nested/repo/image',
'edgecase-without-tag',
'dockerhub.com/image-name',
'registry.example.com:5000/repo/image',
'private-repo/myimage',
'test-image-with-special-characters',
'path/to/image',
'simple-image:another',
'example.com:8080/repo/image'
];

for (let i = 0; i < testValues.length; i++) {
assert.equal(getImageNameWithoutTag(testValues[i]), expectedValues[i]);
}
});
});