Skip to content
Merged
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
aaf27f2
Wip
MicroFish91 Feb 19, 2025
149eb14
WIP: Advanced create scaffold done
MicroFish91 Feb 24, 2025
2b14722
WIP: ContainerAppListStep
MicroFish91 Feb 27, 2025
42bc11a
WIP: First pass needs test
MicroFish91 Feb 27, 2025
7e0e6b3
Misc fixes
MicroFish91 Feb 28, 2025
9ab8315
Misc
MicroFish91 Feb 28, 2025
9a50407
WIP: Basic almost done
MicroFish91 Mar 2, 2025
5bad23c
WIP: Mostly working on all fronts minus updated pick filters
MicroFish91 Mar 2, 2025
069eda8
Misc changes and todos
MicroFish91 Mar 3, 2025
40b315e
Misc
MicroFish91 Mar 3, 2025
570c755
Core logic mostly working
MicroFish91 Mar 3, 2025
f7de2a0
Add name suggestion logic
MicroFish91 Mar 3, 2025
5a81bb5
Update location logic
MicroFish91 Mar 4, 2025
c1ef5fc
Move managed environment prompt first and update locations logic
MicroFish91 Mar 5, 2025
e13e6ae
Merge with main
MicroFish91 Jul 7, 2025
66ad27a
Most of the core logic, needs testing
MicroFish91 Jul 8, 2025
b749915
Clean up auto context population
MicroFish91 Jul 8, 2025
8f3b048
Rename pick strategies
MicroFish91 Jul 8, 2025
2fc34be
Remove some todos
MicroFish91 Jul 8, 2025
63f8333
API changes
MicroFish91 Jul 8, 2025
f9ef062
Update step order
MicroFish91 Jul 9, 2025
09025a0
Merge with main
MicroFish91 Aug 23, 2025
5275048
Nit formatting
MicroFish91 Aug 23, 2025
63de6ea
Remove readme
MicroFish91 Aug 23, 2025
4182ccf
Make sure tree item deployment still works well
MicroFish91 Aug 23, 2025
b1ebac5
Move step order
MicroFish91 Aug 23, 2025
4f67144
Small fix
MicroFish91 Aug 23, 2025
c4deb93
Use enum
MicroFish91 Aug 24, 2025
efd8a27
Update changelog
MicroFish91 Aug 25, 2025
f5cc187
Update managed environment list step
MicroFish91 Aug 25, 2025
4d843b2
Rename method
MicroFish91 Aug 25, 2025
993e38d
Simplify boolean expression
MicroFish91 Aug 25, 2025
34b9cc2
Add deployment mode telemetry
MicroFish91 Aug 25, 2025
48af602
Add more telemetry
MicroFish91 Aug 25, 2025
3c36a95
Formatting
MicroFish91 Aug 25, 2025
666b13d
Clean more stuff up
MicroFish91 Aug 25, 2025
6b22fe8
Update starting resources step
MicroFish91 Aug 25, 2025
c0a9fee
Reduce duplicates in telemetry
MicroFish91 Aug 25, 2025
4f49a71
Add flag
MicroFish91 Aug 26, 2025
301512e
Simplify setting related resources
MicroFish91 Aug 27, 2025
d0e61a4
Simplify some more
MicroFish91 Aug 27, 2025
18f3788
Misc changes
MicroFish91 Aug 28, 2025
e888533
Remove support for managed environment items
MicroFish91 Aug 28, 2025
588639f
Update walkthrough
MicroFish91 Aug 29, 2025
f7fbfd7
Add more details for basic create
MicroFish91 Aug 29, 2025
771eb2e
Merge branch 'mwf/tame-scarlet' of https://github.com/microsoft/vscod…
MicroFish91 Aug 29, 2025
563a58a
Rethrow better error message
MicroFish91 Sep 1, 2025
05ed036
Update formatting
MicroFish91 Sep 1, 2025
d180817
Setup basic and advanced tests
MicroFish91 Sep 2, 2025
4ef3820
Add monorepo admin test scenario
MicroFish91 Sep 2, 2025
ed231b9
Finish adding tests
MicroFish91 Sep 2, 2025
0ef64a5
Finalize test changes
MicroFish91 Sep 2, 2025
fe24ae8
Update project files
MicroFish91 Sep 2, 2025
8a7d298
Delete duplicated project files
MicroFish91 Sep 2, 2025
a335b3f
Add duplicate projects to git ignore
MicroFish91 Sep 2, 2025
5708fec
Update comment
MicroFish91 Sep 2, 2025
3fb1bd5
Emtpy destination dir first
MicroFish91 Sep 2, 2025
cfa70b4
Remove overwrite
MicroFish91 Sep 2, 2025
abc307f
Delete dir before copying
MicroFish91 Sep 2, 2025
ab1fd9f
Rename apps for monorepo
MicroFish91 Sep 2, 2025
0dadd64
Reset launch config
MicroFish91 Sep 2, 2025
8d7a18f
Fix comment
MicroFish91 Sep 2, 2025
ab18307
Refactor
MicroFish91 Sep 2, 2025
e3dca3d
Fix tests again
MicroFish91 Sep 2, 2025
45fc9c7
All working
MicroFish91 Sep 3, 2025
1dbd11d
Merge branch 'main' of https://github.com/microsoft/vscode-azureconta…
MicroFish91 Sep 15, 2025
9baf69e
Merge with main
MicroFish91 Sep 15, 2025
c70ae3c
Remove exports from bundle
MicroFish91 Sep 15, 2025
05bf582
Merge branch 'mwf/walkthrough-082925' of https://github.com/microsoft…
MicroFish91 Sep 15, 2025
3c01583
Merge branch 'main' of https://github.com/microsoft/vscode-azureconta…
MicroFish91 Sep 16, 2025
8512f79
Add deleted dockerfile back
MicroFish91 Sep 16, 2025
ff9378e
Fix missing dockerfile
MicroFish91 Sep 16, 2025
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
3 changes: 1 addition & 2 deletions resources/walkthrough/add-workspace-project.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
| Prompt | Value |
|--------|-------|
| Pick a repository source | Select: <b>Clone from GitHub</b> |
| Enter a repository name | [https://github.com/Azure-Samples/containerapps-albumapi-javascript]() |
| Provide repository URL | [https://github.com/Azure-Samples/containerapps-albumapi-javascript]() |
| Select a folder to clone the project into | Select a repository destination. |
| Open the project | Select: <b>Open</b> |
2 changes: 1 addition & 1 deletion resources/walkthrough/clean-up-resources.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
| Prompt | Value |
|--------|-------|
| Select subscription | Select the Azure subscription used in the previous step. |
| Select resource group(s) | Select <b>my-container-env</b> and press enter. |
| Select resource group(s) | Select <b>contoso-env</b> and press enter. |
| Confirm resources to delete | Select: <b>Delete</b> |
11 changes: 6 additions & 5 deletions resources/walkthrough/create-and-deploy.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
| Prompt | Value |
|--------|-------|
| Select subscription | Select the Azure subscription you want to use. |
| Select a container apps environment | Select: <b>Create new container apps environment</b>. You will only be asked this question if you have existing container apps environments. |
| Confirm resources to create | Select: <b>Continue</b> |
| Enter a name for the new container app environment resources | Enter: <b>my-container-env</b> |
| Enter a name for the new container app | Enter: <b>my-container-app</b> |
| Select deployment mode | Select: <b>Basic</b> |
| Enter a name for container environment resources | Enter: <b>contoso-env</b> |
| Enter a name for the new container app | Enter: <b>contoso-app</b> |
| Select a location | Select an Azure region near you. |
| Select a registry connection method | Select: <b>Managed Identity</b> |
| Provide a source code directory for upload | Select: <b>./src</b> |
| Select a location | Select an Azure region close to you. |
| Confirm resources to be created | Select: <b>Continue</b> |
| Save deployment configuration | Select: <b>Save</b> |
| <i>On completion<i>: | <details><summary>View Save Configuration: </summary><p>`.vscode/settings.json`:</p><img src="./images/dwp-saved-settings.png"></details> <details><summary>View Activity Log: </summary><img src="./images/dwp-activity-log.png"></details> <details><summary>View Deployment: </summary><img src="./images/dwp-popup.png"></details> <details><summary>View Azure Resources Tree (Resource Type): </summary><img src="./images/dwp-tree-resource-type.png"></details> <details><summary>View Azure Resources Tree (Resource Group): </summary><img src="./images/dwp-tree-resource-group.png"></details> |
1 change: 1 addition & 0 deletions resources/walkthrough/explore-details.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
| <h4>I. <u>Add a workspace project</u></h4>Navigate to the Explorer view and add a project with a Dockerfile to the local VS Code workspace using <b>Open Folder</b> or <b>Clone Repository</b>. | <img src="./images/explorer-workspace-project.png"> |
| <h4>II. <u>Sign in to Azure</u></h4>Navigate to the Azure Resources view and select: <b>Sign in to Azure</b>. | <img src="./images/azure-sign-in.png"></details> |
| <h4>III. <u>Create and deploy</u></h4>Navigate to the Azure Workspace view and use the container app icon to select: <b>Deploy Project from Workspace</b>.<br /><br />Re-deploy to the same resources by running the command again with saved workspace settings (<i>.vscode/settings.json</i>). | <img src="./images/deploy-workspace-project.png"> |
| <h4>IV. <u>Open Walkthrough</u></h4>Navigate to the Azure Workspace view and use the container app icon to select: <b>Open Walkthrough</b> if you ever need to return to this walkthrough again in the future. | <img src="./images/dwp-open-walkthrough.png"> |
Binary file modified resources/walkthrough/images/dwp-activity-log.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/walkthrough/images/dwp-popup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/walkthrough/images/dwp-saved-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/walkthrough/images/dwp-tree-resource-group.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/walkthrough/images/dwp-tree-resource-type.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { RegistryNameStep } from "./createAcr/RegistryNameStep";
import { SkuListStep } from "./createAcr/SkuListStep";

export interface AcrListStepOptions {
createIfNone?: boolean;
suppressCreatePick?: boolean;
pickUpdateStrategy?: AcrPickUpdateStrategy;
}
Expand Down Expand Up @@ -48,7 +49,7 @@ export class AcrListStep<T extends ContainerRegistryImageSourceContext> extends
let result: Registry | typeof noMatchingResources | undefined;
do {
const picks: IAzureQuickPickItem<Registry | typeof noMatchingResources | undefined>[] = await this.getPicks(context);
if (picks.length === 1 && picks[0] === acrCreatePick) {
if (this.options.createIfNone && picks.length === 1 && picks[0] === acrCreatePick) {
pick = acrCreatePick;
result = pick.data as typeof acrCreatePick['data'];
break;
Expand Down
17 changes: 15 additions & 2 deletions src/commands/walkthrough/addWorkspaceProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { UserCancelledError, type IActionContext } from "@microsoft/vscode-azext-utils";
import { parseError, UserCancelledError, type IActionContext, type IParsedError } from "@microsoft/vscode-azext-utils";
import { commands, workspace, type MessageItem } from "vscode";
import { localize } from "../../utils/localize";

Expand All @@ -18,5 +18,18 @@ export async function addWorkspaceProjectWalkthrough(context: IActionContext): P
throw new UserCancelledError();
}

await commands.executeCommand('git.clone');
try {
await commands.executeCommand('git.clone');
} catch (e) {
const perr: IParsedError = parseError(e);
if (/git\.clone.*not found/i.test(perr.message)) {
throw new Error(localize('gitCloneNotFound',
'Command "git.clone" not found. This could be due to one of the following reasons:\n\n' +
'- Git is not installed on your system.\n' +
'- Git is installed but not added to your system PATH.\n' +
'- Git is installed but is broken or permission-blocked.\n\n' +
'Please ensure Git is installed and properly configured.'));
}
throw e;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,11 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { type ManagedEnvironment } from "@azure/arm-appcontainers";
import { type Registry } from "@azure/arm-containerregistry";
import { runWithTestActionContext } from "@microsoft/vscode-azext-dev";
import { nonNullProp, randomUtils } from "@microsoft/vscode-azext-utils";
import * as assert from "assert";
import { createAcr, createManagedEnvironment } from "../../../extension.bundle";
import { nonNullProp } from "@microsoft/vscode-azext-utils";
import { longRunningTestsEnabled } from '../../global.test';
import { resourceGroupsToDelete } from "../global.nightly.test";
import { buildParallelTestScenarios, type DwpParallelTestScenario } from './buildParallelScenarios';
import { generateParallelTests, type DwpParallelTestScenario } from "./parallelTests";

let setupTask: Promise<void>;
const testScenarios: DwpParallelTestScenario[] = buildParallelTestScenarios();
const testScenarios: DwpParallelTestScenario[] = generateParallelTests();

suite('deployWorkspaceProject', async function (this: Mocha.Suite) {
this.timeout(15 * 60 * 1000);
Expand All @@ -24,13 +17,8 @@ suite('deployWorkspaceProject', async function (this: Mocha.Suite) {
this.skip();
}

// Create a container registry & managed environment first so that we can guarantee one is always built before workspace deployment tests start.
// This is crucial for test consistency because some resource prompts will skip if no existing resources exist to choose from
// Creating at least one of each resource first ensures consistent reproduceability.
setupTask = setupResources();

for (const s of testScenarios) {
s.scenario = s.callback(setupTask);
s.scenario = s.callback();
}
});

Expand All @@ -40,39 +28,3 @@ suite('deployWorkspaceProject', async function (this: Mocha.Suite) {
});
}
});

async function setupResources(): Promise<void> {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defaulting behavior is a bit more predictable now, so we can remove this.

let envResourceTask: Promise<void> | undefined;
let managedEnvironment: ManagedEnvironment | undefined;
try {
envResourceTask = runWithTestActionContext('createManagedEnvironment', async context => {
const resourceName: string = 'dwp' + randomUtils.getRandomHexString(6);
await context.ui.runWithInputs([resourceName, 'East US'], async () => {
managedEnvironment = await createManagedEnvironment(context);
});
});
} catch (e) {
console.error(e);
}

let acrResourceTask: Promise<void> | undefined;
let registry: Registry | undefined;
try {
acrResourceTask = runWithTestActionContext('createContainerRegistry', async context => {
const resourceName: string = 'dwp' + randomUtils.getRandomHexString(6);
await context.ui.runWithInputs([resourceName, 'Basic', 'East US'], async () => {
registry = await createAcr(context);
});
});
} catch (e) {
console.error(e);
}

await Promise.allSettled([envResourceTask, acrResourceTask]);

assert.ok(managedEnvironment, 'Failed to create managed environment - skipping "deployWorkspaceProject" tests.');
resourceGroupsToDelete.add(nonNullProp(managedEnvironment, 'name'));

assert.ok(registry, 'Failed to create container registry - skipping "deployWorkspaceProject" tests.');
resourceGroupsToDelete.add(nonNullProp(registry, 'name'));
}
44 changes: 0 additions & 44 deletions test/nightly/deployWorkspaceProject/dwpTestScenarios.ts

This file was deleted.

12 changes: 6 additions & 6 deletions test/nightly/deployWorkspaceProject/dwpTestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as assert from "assert";
import { createContainerAppsAPIClient, type DeployWorkspaceProjectResults } from "../../../extension.bundle";
import { type StringOrRegExpProps } from "../../typeUtils";
import { subscriptionContext } from "../global.nightly.test";
import { type PostTestAssertion } from "./testCases/DeployWorkspaceProjectTestCase";
import { type PostTestAssertion } from "./scenarios/DeployWorkspaceProjectTestScenario";

export namespace dwpTestUtils {
export function generateExpectedResultsWithCredentials(sharedResourceName: string, acrResourceName: string, appResourceName: string): StringOrRegExpProps<DeployWorkspaceProjectResults> {
Expand All @@ -19,10 +19,10 @@ export namespace dwpTestUtils {
imageName: new RegExp(appResourceName, 'i'),
logAnalyticsWorkspaceId: new RegExp(`\/resourceGroups\/${sharedResourceName}\/providers\/Microsoft\.OperationalInsights\/workspaces\/${sharedResourceName}`, 'i'),
managedEnvironmentId: new RegExp(`\/resourceGroups\/${sharedResourceName}\/providers\/Microsoft\.App\/managedEnvironments\/${sharedResourceName}`, 'i'),
registryId: new RegExp(`\/resourceGroups\/${sharedResourceName}\/providers\/Microsoft\.ContainerRegistry\/registries\/${acrResourceName}.{6}`, 'i'),
registryLoginServer: new RegExp(`${acrResourceName}.{6}\.azurecr\.io`, 'i'),
registryId: new RegExp(`\/resourceGroups\/${sharedResourceName}\/providers\/Microsoft\.ContainerRegistry\/registries\/${acrResourceName}`, 'i'),
registryLoginServer: new RegExp(`${acrResourceName}(?:.{6})?\.azurecr\.io`, 'i'),
registryPassword: new RegExp('.*'),
registryUsername: new RegExp(`${acrResourceName}.{6}`, 'i'),
registryUsername: new RegExp(acrResourceName, 'i'),
resourceGroupId: new RegExp(`\/resourceGroups\/${sharedResourceName}`, 'i')
};
}
Expand All @@ -33,8 +33,8 @@ export namespace dwpTestUtils {
imageName: new RegExp(appResourceName, 'i'),
logAnalyticsWorkspaceId: new RegExp(`\/resourceGroups\/${sharedResourceName}\/providers\/Microsoft\.OperationalInsights\/workspaces\/${sharedResourceName}`, 'i'),
managedEnvironmentId: new RegExp(`\/resourceGroups\/${sharedResourceName}\/providers\/Microsoft\.App\/managedEnvironments\/${sharedResourceName}`, 'i'),
registryId: new RegExp(`\/resourceGroups\/${sharedResourceName}\/providers\/Microsoft\.ContainerRegistry\/registries\/${acrResourceName}.{6}`, 'i'),
registryLoginServer: new RegExp(`${acrResourceName}.{6}\.azurecr\.io`, 'i'),
registryId: new RegExp(`\/resourceGroups\/${sharedResourceName}\/providers\/Microsoft\.ContainerRegistry\/registries\/${acrResourceName}`, 'i'),
registryLoginServer: new RegExp(`${acrResourceName}(?:.{6})?\.azurecr\.io`, 'i'),
registryPassword: undefined,
registryUsername: undefined,
resourceGroupId: new RegExp(`\/resourceGroups\/${sharedResourceName}`, 'i')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,26 @@ import { workspace, type Uri, type WorkspaceFolder } from "vscode";
import { AzExtFsExtra, deployWorkspaceProject, dwpSettingUtilsV2, ext, parseError, settingUtils, type DeploymentConfigurationSettings, type DeployWorkspaceProjectResults, type IParsedError } from "../../../extension.bundle";
import { assertStringPropsMatch, getWorkspaceFolderUri } from "../../testUtils";
import { resourceGroupsToDelete } from "../global.nightly.test";
import { getDwpTestScenarios, type DeployWorkspaceProjectTestScenario } from "./dwpTestScenarios";
import { type DeployWorkspaceProjectTestScenario } from "./scenarios/DeployWorkspaceProjectTestScenario";
import { generateTestScenarios } from "./scenarios/testScenarios";

export interface DwpParallelTestScenario {
title: string;
callback(setupTask: Promise<void>): Promise<void>;
callback(): Promise<void>;
scenario?: Promise<void>;
}

export function buildParallelTestScenarios(): DwpParallelTestScenario[] {
return getDwpTestScenarios().map(scenario => {
export function generateParallelTests(): DwpParallelTestScenario[] {
return generateTestScenarios().map(scenario => {
return {
title: scenario.label,
callback: buildParallelScenarioCallback(scenario),
callback: runTestScenario(scenario),
};
});
}

function buildParallelScenarioCallback(scenario: DeployWorkspaceProjectTestScenario): DwpParallelTestScenario['callback'] {
return async (setupTask: Promise<void>) => {
await setupTask;

function runTestScenario(scenario: DeployWorkspaceProjectTestScenario): DwpParallelTestScenario['callback'] {
return async () => {
const workspaceFolderUri: Uri = getWorkspaceFolderUri(scenario.folderName);
const rootFolder: WorkspaceFolder | undefined = workspace.getWorkspaceFolder(workspaceFolderUri);
assert.ok(rootFolder, 'Could not retrieve root workspace folder.');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
import { type DeploymentConfigurationSettings, type DeployWorkspaceProjectResults, type IActionContext } from "../../../../extension.bundle";
import { type StringOrRegExpProps } from "../../../typeUtils";

export interface DeployWorkspaceProjectTestScenario {
label: string;
folderName: string;
testCases: DeployWorkspaceProjectTestCase[];
}

export interface DeployWorkspaceProjectTestCase {
/**
* Label to display when executing the test
Expand Down
Loading