Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,11 @@
"command": "containerApps.stopStreamingLogs",
"title": "%containerApps.stopStreamingLogs%",
"category": "Azure Container Apps"
},
{
"command": "containerApps.createAcr",
"title": "%containerApps.createAcr%",
"category": "Azure Container Apps"
}
],
"menus": {
Expand Down
3 changes: 2 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@
"containerApps.disconnectRepo": "Disconnect from Repo",
"containerApps.openGitHubRepo": "Open Repo in GitHub",
"containerApps.startStreamingLogs": "Start Streaming Logs...",
"containerApps.stopStreamingLogs": "Stop Streaming Logs..."
"containerApps.stopStreamingLogs": "Stop Streaming Logs...",
"containerApps.createAcr": "Create Azure Container Registry..."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { KnownSkuName, Registry } from "@azure/arm-containerregistry";
import { IResourceGroupWizardContext } from "@microsoft/vscode-azext-azureutils";
import { ExecuteActivityContext } from "@microsoft/vscode-azext-utils";

export interface CreateAcrContext extends IResourceGroupWizardContext, ExecuteActivityContext {
newRegistryName?: string;
newRegistrySku?: KnownSkuName;
registry?: Registry;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { ContainerRegistryManagementClient } from "@azure/arm-containerregistry";
import { LocationListStep } from "@microsoft/vscode-azext-azureutils";
import { AzureWizardExecuteStep, nonNullProp } from "@microsoft/vscode-azext-utils";
import { createContainerRegistryManagementClient } from "../../../../../../utils/azureClients";
import { CreateAcrContext } from "./CreateAcrContext";

export class RegistryCreateStep extends AzureWizardExecuteStep<CreateAcrContext> {
public priority: number = 150;

public async execute(context: CreateAcrContext): Promise<void> {
const client: ContainerRegistryManagementClient = await createContainerRegistryManagementClient(context);

context.registry = await client.registries.beginCreateAndWait(
nonNullProp(context, 'newResourceGroupName'),
nonNullProp(context, 'newRegistryName'),
{
location: (await LocationListStep.getLocation(context)).name,
sku: { name: nonNullProp(context, 'newRegistrySku') },
adminUserEnabled: true
}
);
}

public shouldExecute(context: CreateAcrContext): boolean {
return !!context.newRegistryName && !!context.newRegistrySku;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { ContainerRegistryManagementClient, RegistryNameStatus } from "@azure/arm-containerregistry";
import { AzureWizardPromptStep } from "@microsoft/vscode-azext-utils";
import { createContainerRegistryManagementClient } from "../../../../../../utils/azureClients";
import { localize } from "../../../../../../utils/localize";
import { CreateAcrContext } from "./CreateAcrContext";

export class RegistryNameStep extends AzureWizardPromptStep<CreateAcrContext> {
public async prompt(context: CreateAcrContext): Promise<void> {
context.newRegistryName = await context.ui.showInputBox({
prompt: localize('registryName', 'Enter a name for the new registry'),
validateInput: this.validateInput,
asyncValidationTask: (value: string): Promise<string | undefined> => this.validateNameAvalability(context, value)
});
}

public shouldPrompt(context: CreateAcrContext): boolean {
return !context.newRegistryName;
}

private validateInput(name: string | undefined): string | undefined {
name = name ? name.trim() : '';

const { minLength, maxLength } = { minLength: 5, maxLength: 50 };
if (name.length < minLength || name.length > maxLength) {
return localize('validationLengthError', 'The name must be between {0} and {1} characters.', minLength, maxLength);
} else if (!/^[a-z][a-zA-Z0-9]*$/.test(name)) {
return localize('validateInputError', `Connection names can only consist of alphanumeric characters.`);
}

return undefined;
}

private async validateNameAvalability(context: CreateAcrContext, name: string) {
const client: ContainerRegistryManagementClient = await createContainerRegistryManagementClient(context);
const nameResponse: RegistryNameStatus = await client.registries.checkNameAvailability({ name: name, type: "Microsoft.ContainerRegistry/registries" });
if (nameResponse.nameAvailable === false) {
return localize('validateInputError', `The registry name ${name} is already in use.`);
}

return undefined;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { KnownSkuName } from "@azure/arm-containerregistry";
import { AzureWizardPromptStep, IAzureQuickPickItem } from "@microsoft/vscode-azext-utils";
import { localize } from "../../../../../../utils/localize";
import { CreateAcrContext } from "./CreateAcrContext";

export class SkuListStep extends AzureWizardPromptStep<CreateAcrContext> {
public async prompt(context: CreateAcrContext): Promise<void> {
const placeHolder: string = localize("sku", "Select a SKU");
const picks: IAzureQuickPickItem<KnownSkuName>[] = [
{ label: KnownSkuName.Basic, data: KnownSkuName.Basic },
{ label: KnownSkuName.Standard, data: KnownSkuName.Standard },
{ label: KnownSkuName.Premium, data: KnownSkuName.Premium },
];

context.newRegistrySku = (await context.ui.showQuickPick(picks, {
placeHolder,
suppressPersistence: true
})).data;
}

public shouldPrompt(context: CreateAcrContext): boolean {
return !context.newRegistrySku;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { LocationListStep, ResourceGroupCreateStep } from "@microsoft/vscode-azext-azureutils";
import { AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext, createSubscriptionContext, nonNullValue, subscriptionExperience } from "@microsoft/vscode-azext-utils";
import { AzureSubscription } from "@microsoft/vscode-azureresources-api";
import { ext } from "../../../../../../extensionVariables";
import { createActivityContext } from "../../../../../../utils/activityUtils";
import { localize } from "../../../../../../utils/localize";
import { CreateAcrContext } from "./CreateAcrContext";
import { RegistryCreateStep } from "./RegistryCreateStep";
import { RegistryNameStep } from "./RegistryNameStep";
import { SkuListStep } from "./SkuListStep";

export async function createAcr(context: IActionContext, node?: { subscription: AzureSubscription }): Promise<void> {
const subscription = node?.subscription ?? await subscriptionExperience(context, ext.rgApiV2.resources.azureResourceTreeDataProvider);

const wizardContext: CreateAcrContext = {
...context,
...createSubscriptionContext(subscription),
...(await createActivityContext())
};

const title: string = localize('createAcr', "Create Azure Container Registry");

const promptSteps: AzureWizardPromptStep<CreateAcrContext>[] = [
new RegistryNameStep(),
new SkuListStep(),
];

const executeSteps: AzureWizardExecuteStep<CreateAcrContext>[] = [
new ResourceGroupCreateStep(),
Comment thread
MicroFish91 marked this conversation as resolved.
new RegistryCreateStep(),
];

LocationListStep.addStep(wizardContext, promptSteps);


const wizard: AzureWizard<CreateAcrContext> = new AzureWizard(wizardContext, {
title,
promptSteps,
executeSteps,
showLoadingPrompt: true
});

await wizard.prompt();

wizardContext.newResourceGroupName = nonNullValue(wizardContext.newRegistryName);
wizardContext.activityTitle = localize('createAcr', 'Create Azure Container Registry "{0}"', wizardContext.newRegistryName);

await wizard.execute();
}
4 changes: 4 additions & 0 deletions src/commands/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { deleteContainerApp } from './deleteContainerApp/deleteContainerApp';
import { deleteManagedEnvironment } from './deleteManagedEnvironment/deleteManagedEnvironment';
import { deployImage } from './deployImage/deployImage';
import { deployImageApi } from './deployImage/deployImageApi';
import { createAcr } from './deployImage/imageSource/containerRegistry/acr/createAcr/createAcr';
import { editContainerApp } from './editContainerApp';
import { connectToGitHub } from './gitHub/connectToGitHub/connectToGitHub';
import { disconnectRepo } from './gitHub/disconnectRepo/disconnectRepo';
Expand Down Expand Up @@ -91,4 +92,7 @@ export function registerCommands(): void {
// Suppress "Report an Issue" button for all errors in favor of the command
registerErrorHandler(c => c.errorHandling.suppressReportIssue = true);
registerReportIssueCommand('containerApps.reportIssue');

// registries
registerCommandWithTreeNodeUnwrapping('containerApps.createAcr', createAcr);
}