Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a27a2bc
Partial
MicroFish91 Sep 1, 2023
42d6c19
Merge branch 'main' of https://github.com/microsoft/vscode-azureconta…
MicroFish91 Sep 6, 2023
c13c61e
Update validation logic
MicroFish91 Sep 6, 2023
0e25f45
Wip
MicroFish91 Sep 6, 2023
1134743
Wip tests
MicroFish91 Sep 7, 2023
426b5e4
Add tests
MicroFish91 Sep 8, 2023
64dccfc
Revert main.js
MicroFish91 Sep 8, 2023
fbffd33
Update test file names
MicroFish91 Sep 8, 2023
0fa2f4c
Import type
MicroFish91 Sep 8, 2023
91eff67
Update test case
MicroFish91 Sep 8, 2023
06a7ba9
Make pr smaller
MicroFish91 Sep 8, 2023
d21cdb2
Fix
MicroFish91 Sep 8, 2023
9e8f37f
Impl
MicroFish91 Sep 8, 2023
d8d2345
Merge with part I
MicroFish91 Sep 8, 2023
a9ab3ac
Add back name validation refactors
MicroFish91 Sep 8, 2023
dae4d98
Update var names
MicroFish91 Sep 8, 2023
830ecb5
Revert old change
MicroFish91 Sep 8, 2023
3e8ea38
nit
MicroFish91 Sep 8, 2023
57e86fe
Impl
MicroFish91 Sep 11, 2023
3405415
Combine if statements
MicroFish91 Sep 11, 2023
0ff2e01
Import type
MicroFish91 Sep 11, 2023
d689816
Update test display
MicroFish91 Sep 11, 2023
a721f97
Misc
MicroFish91 Sep 12, 2023
0f86bdc
Add additional parse notes
MicroFish91 Sep 13, 2023
4cab767
Update var name
MicroFish91 Sep 13, 2023
fe4f955
Merge branch 'mwf/deployWorkspaceProject-II' of https://github.com/mi…
MicroFish91 Sep 13, 2023
de11fc0
Updates
MicroFish91 Sep 13, 2023
3a3942c
Merge with main
MicroFish91 Sep 15, 2023
7a236f0
Update microsoft header
MicroFish91 Sep 15, 2023
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 extension.bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
// At runtime the tests live in dist/tests and will therefore pick up the main webpack bundle at dist/extension.bundle.js.
export * from '@microsoft/vscode-azext-utils';
// Export activate/deactivate for main.js
export * from './src/commands/deployWorkspaceProject/DeployWorkspaceProjectContext';
export * from './src/commands/deployWorkspaceProject/getDefaultValues/DefaultResourcesNameStep';
export * from './src/commands/ingress/IngressContext';
export * from './src/commands/ingress/editTargetPort/getDefaultPort';
export * from './src/commands/ingress/tryConfigureIngressUsingDockerfile';
export { activate, deactivate } from './src/extension';
export * from './src/extensionVariables';
export * from './src/utils/validateUtils';
Expand Down
7 changes: 7 additions & 0 deletions gulpfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ async function cleanReadme(): Promise<void> {
await fse.writeFile(readmePath, data);
}

async function preTest(): Promise<void> {
const fromPath: string = path.join(__dirname, 'test', 'ingress', 'dockerfileSamples');
const toPath: string = path.join(__dirname, 'dist', 'test', 'ingress', 'dockerfileSamples');
fse.copySync(fromPath, toPath);
}

exports['webpack-dev'] = gulp.series(prepareForWebpack, () => gulp_webpack('development'));
exports['webpack-prod'] = gulp.series(prepareForWebpack, () => gulp_webpack('production'));
exports.cleanReadme = cleanReadme;
exports.preTest = preTest;
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 32 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@
"title": "%containerApps.deployImageApi%",
"category": "Azure Container Apps"
},
{
"command": "containerApps.deployWorkspaceProject",
"title": "%containerApps.deployWorkspaceProject%",
"category": "Azure Container Apps"
},
{
"command": "containerApps.deleteContainerApp",
"title": "%containerApps.deleteContainerApp%",
Expand Down Expand Up @@ -230,7 +235,31 @@
"category": "Azure Container Apps"
}
],
"submenus": [
{
"id": "containerApps.submenus.workspaceActions",
"label": "Azure Container Apps",
"icon": "resources/azure-containerapps.svg"
}
],
"menus": {
"containerApps.submenus.workspaceActions": [
{
"command": "containerApps.deployWorkspaceProject",
"group": "1_deploy@1"
},
{
"command": "containerApps.createContainerApp",
"group": "2_create@1"
}
],
"view/title": [
{
"submenu": "containerApps.submenus.workspaceActions",
"when": "view == azureWorkspace",
"group": "navigation@4"
}
],
"view/item/context": [
{
"command": "containerApps.createManagedEnvironment",
Expand Down Expand Up @@ -475,7 +504,8 @@
"package": "vsce package --githubBranch main --no-dependencies",
"lint": "eslint --ext .ts .",
"lint-fix": "eslint --ext .ts . --fix",
"test": "node ./out/test/runTest.js",
"pretest": "gulp preTest",
"test": "node ./dist/test/runTest.js",
"webpack": "tsc && gulp webpack-dev",
"webpack-profile": "webpack --profile --json --mode production > webpack-stats.json && echo Use http://webpack.github.io/analyse to analyze the stats",
"prepare": "husky install"
Expand Down Expand Up @@ -518,7 +548,7 @@
"@azure/storage-blob": "^12.4.1",
"@microsoft/vscode-azext-azureutils": "^2.0.0",
"@microsoft/vscode-azext-github": "^1.0.0",
"@microsoft/vscode-azext-utils": "^2.0.0",
"@microsoft/vscode-azext-utils": "^2.0.5",
"@microsoft/vscode-azureresources-api": "^2.0.2",
"buffer": "^6.0.3",
"dayjs": "^1.11.3",
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"containerApps.editContainerApp": "Edit Container App (Advanced)...",
"containerApps.deployImage": "Update Container App Image...",
"containerApps.deployImageApi": "Update Container App Image (API)...",
"containerApps.deployWorkspaceProject": "Deploy Project from Workspace...",
"containerApps.deleteContainerApp": "Delete Container App...",
"containerApps.disableIngress": "Disable Ingress for Container App",
"containerApps.enableIngress": "Enable Ingress for Container App...",
Expand Down
39 changes: 23 additions & 16 deletions src/commands/createContainerApp/ContainerAppNameStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { ContainerAppsAPIClient } from "@azure/arm-appcontainers";
import { getResourceGroupFromId } from "@microsoft/vscode-azext-azureutils";
import { AzureWizardPromptStep } from "@microsoft/vscode-azext-utils";
import { AzureWizardPromptStep, ISubscriptionActionContext, nonNullProp } from "@microsoft/vscode-azext-utils";
import { createContainerAppsAPIClient } from '../../utils/azureClients';
import { localize } from "../../utils/localize";
import { ICreateContainerAppContext } from './ICreateContainerAppContext';
Expand All @@ -14,22 +14,22 @@ export class ContainerAppNameStep extends AzureWizardPromptStep<ICreateContainer
public hideStepCount: boolean = true;

public async prompt(context: ICreateContainerAppContext): Promise<void> {
const prompt: string = localize('containerAppNamePrompt', 'Enter a name for the new container app.');
const prompt: string = localize('containerAppNamePrompt', 'Enter a container app name.');
context.newContainerAppName = (await context.ui.showInputBox({
prompt,
validateInput: async (value: string | undefined): Promise<string | undefined> => await this.validateInput(context, value)
validateInput: this.validateInput,
asyncValidationTask: (name: string) => this.validateNameAvailable(context, name)
})).trim();

context.valuesToMask.push(context.newContainerAppName);
}

public shouldPrompt(context: ICreateContainerAppContext): boolean {
return !context.newContainerAppName;
return !context.containerApp && !context.newContainerAppName;
}

private async validateInput(context: ICreateContainerAppContext, name: string | undefined): Promise<string | undefined> {
private validateInput(name: string | undefined): string | undefined {
name = name ? name.trim() : '';
// to prevent showing an error when the character types the first letter

const { minLength, maxLength } = { minLength: 1, maxLength: 32 };
if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(name)) {
Expand All @@ -38,17 +38,24 @@ export class ContainerAppNameStep extends AzureWizardPromptStep<ICreateContainer
return localize('invalidLength', 'The name must be between {0} and {1} characters.', minLength, maxLength);
}

// do the API call last
try {
const client: ContainerAppsAPIClient = await createContainerAppsAPIClient(context);
const managedEnvironmentRg = getResourceGroupFromId(context.managedEnvironmentId);
await client.containerApps.get(managedEnvironmentRg, name);
return localize('containerAppExists', 'The container app "{0}" already exists in resource group "{1}". Please enter a unique name.', name, managedEnvironmentRg);
} catch (err) {
// do nothing
}

return undefined;
}

private async validateNameAvailable(context: ICreateContainerAppContext, name: string): Promise<string | undefined> {
const resourceGroupName: string = getResourceGroupFromId(nonNullProp(context, 'managedEnvironmentId'));
if (!await ContainerAppNameStep.isNameAvailable(context, resourceGroupName, name)) {
return localize('containerAppExists', 'The container app "{0}" already exists in resource group "{1}".', name, resourceGroupName);
}
return undefined;
}

public static async isNameAvailable(context: ISubscriptionActionContext, resourceGroupName: string, containerAppName: string): Promise<boolean> {
const client: ContainerAppsAPIClient = await createContainerAppsAPIClient(context);
try {
await client.containerApps.get(resourceGroupName, containerAppName);
return false;
} catch (_e) {
return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import type { ManagedEnvironment } from '@azure/arm-appcontainers';
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 '../deployImage/imageSource/ImageSourceBaseContext';
import type { IngressContext } from '../ingress/IngressContext';

export interface ICreateContainerAppContext extends IResourceGroupWizardContext, ImageSourceBaseContext, IngressContext, IContainerAppContext, ExecuteActivityContext {
managedEnvironmentId: string;
newContainerAppName?: string;

managedEnvironmentId?: string;
managedEnvironment?: ManagedEnvironment;
}
1 change: 1 addition & 0 deletions src/commands/createContainerApp/createContainerApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export async function createContainerApp(context: IActionContext & Partial<ICrea
...(await createActivityContext()),
subscription: node.subscription,
managedEnvironmentId: node.managedEnvironment.id,
alwaysPromptIngress: true
};

const title: string = localize('createContainerApp', 'Create Container App');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import { ManagedEnvironment } from "@azure/arm-appcontainers";
import { Workspace } from '@azure/arm-operationalinsights';
import { IResourceGroupWizardContext } from '@microsoft/vscode-azext-azureutils';
import { ExecuteActivityContext } from '@microsoft/vscode-azext-utils';
import { ExecuteActivityContext, ISubscriptionActionContext } from '@microsoft/vscode-azext-utils';
import { AzureSubscription } from "@microsoft/vscode-azureresources-api";

export interface IManagedEnvironmentContext extends ISubscriptionActionContext, IResourceGroupWizardContext, ExecuteActivityContext {
subscription: AzureSubscription;

export interface IManagedEnvironmentContext extends IResourceGroupWizardContext, ExecuteActivityContext {
newManagedEnvironmentName?: string;
logAnalyticsWorkspace?: Workspace;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,29 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { AzureWizardPromptStep } from "@microsoft/vscode-azext-utils";
import { ContainerAppsAPIClient } from "@azure/arm-appcontainers";
import { AzureWizardPromptStep, ISubscriptionActionContext, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { createContainerAppsAPIClient } from "../../utils/azureClients";
import { localize } from "../../utils/localize";
import { IManagedEnvironmentContext } from './IManagedEnvironmentContext';

export class ManagedEnvironmentNameStep extends AzureWizardPromptStep<IManagedEnvironmentContext> {
public async prompt(context: IManagedEnvironmentContext): Promise<void> {
const prompt: string = localize('containerAppNamePrompt', 'Enter a name for the new Container Apps environment.');
const prompt: string = localize('containerAppNamePrompt', 'Enter a container apps environment name.');
context.newManagedEnvironmentName = (await context.ui.showInputBox({
prompt,
validateInput: async (value: string | undefined): Promise<string | undefined> => await this.validateInput(value)
validateInput: this.validateInput,
asyncValidationTask: (name: string) => this.validateNameAvailable(context, name)
})).trim();

context.valuesToMask.push(context.newManagedEnvironmentName);
}

public shouldPrompt(context: IManagedEnvironmentContext): boolean {
return !context.managedEnvironment;
return !context.managedEnvironment && !context.newManagedEnvironmentName;
}

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

const { minLength, maxLength } = { minLength: 4, maxLength: 20 };
Expand All @@ -34,4 +37,28 @@ export class ManagedEnvironmentNameStep extends AzureWizardPromptStep<IManagedEn

return undefined;
}

private async validateNameAvailable(context: IManagedEnvironmentContext, name: string): Promise<string | undefined> {
if (!context.resourceGroup) {
// If a new resource group will house the managed environment, we can skip the name check
return undefined;
}

const resourceGroupName: string = nonNullValueAndProp(context.resourceGroup, 'name');
if (!await ManagedEnvironmentNameStep.isNameAvailable(context, resourceGroupName, name)) {
return localize('managedEnvironmentExists', 'The container apps environment "{0}" already exists in resource group "{1}".', name, resourceGroupName);
}

return undefined;
}

public static async isNameAvailable(context: ISubscriptionActionContext, resourceGroupName: string, environmentName: string): Promise<boolean> {
const client: ContainerAppsAPIClient = await createContainerAppsAPIClient(context);
try {
await client.managedEnvironments.get(resourceGroupName, environmentName);
return false;
} catch (_e) {
return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { LocationListStep, ResourceGroupCreateStep, VerifyProvidersStep } from "@microsoft/vscode-azext-azureutils";
import { AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, createSubscriptionContext, IActionContext, nonNullProp, subscriptionExperience } from "@microsoft/vscode-azext-utils";
import { AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext, createSubscriptionContext, nonNullProp, subscriptionExperience } from "@microsoft/vscode-azext-utils";
import { AzureSubscription } from "@microsoft/vscode-azureresources-api";
import { ext } from "../../extensionVariables";
import { createActivityContext } from "../../utils/activityUtils";
Expand All @@ -20,7 +20,8 @@ export async function createManagedEnvironment(context: IActionContext, node?: {
const wizardContext: IManagedEnvironmentContext = {
...context,
...createSubscriptionContext(subscription),
...(await createActivityContext())
...(await createActivityContext()),
subscription
};

const title: string = localize('createManagedEnv', 'Create Container Apps environment');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import type { IBuildImageInAzureContext } from "./IBuildImageInAzureContext";

export class DockerFileItemStep extends AzureWizardPromptStep<IBuildImageInAzureContext> {
public async prompt(context: IBuildImageInAzureContext): Promise<void> {
context.dockerFilePath = await selectWorkspaceFile(context, localize('dockerFilePick', 'Select a Dockerfile'), { filters: {} }, DOCKERFILE_GLOB_PATTERN);
context.dockerfilePath = await selectWorkspaceFile(context, localize('dockerFilePick', 'Select a Dockerfile'), { filters: {} }, DOCKERFILE_GLOB_PATTERN);
}

public shouldPrompt(context: IBuildImageInAzureContext): boolean {
return !context.dockerFilePath;
return !context.dockerfilePath;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { IContainerRegistryImageContext } from '../containerRegistry/IContainerR

export interface IBuildImageInAzureContext extends IContainerRegistryImageContext {
rootFolder: vscode.WorkspaceFolder;
dockerFilePath: string;
dockerfilePath: string;
imageName: string;
os: 'Windows' | 'Linux';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { IBuildImageInAzureContext } from "./IBuildImageInAzureContext";

export class ImageNameStep extends AzureWizardPromptStep<IBuildImageInAzureContext> {
public async prompt(context: IBuildImageInAzureContext): Promise<void> {
const suggestedImageName = await getSuggestedName(context, context.dockerFilePath);
const suggestedImageName = await getSuggestedName(context, context.dockerfilePath);

context.imageName = await context.ui.showInputBox({
prompt: localize('imageNamePrompt', 'Enter a name for the image'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class RunStep extends AzureWizardExecuteStep<IBuildImageInAzureContext> {
isPushEnabled: true,
sourceLocation: context.uploadedSourceLocation,
platform: { os: context.os },
dockerFilePath: path.relative(rootUri.path, context.dockerFilePath)
dockerFilePath: path.relative(rootUri.path, context.dockerfilePath)
};

const building: string = localize('buildingImage', 'Building image "{0}" in registry "{1}"...', context.imageName, context.registryName);
Expand Down
Loading