From 90e2d5e86016c95232b6594b5d8b46f7ec11461e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:33:31 +0000 Subject: [PATCH 1/6] Initial plan From b0525771eaadace9b7418c8fb044caeec3d0b23e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:40:32 +0000 Subject: [PATCH 2/6] Add defensive checks for undefined fsPath in VS Code extension commands This fixes the issue where provision and other commands would fail with "The 'path' argument must be of type string. Received undefined" when used with virtual file systems or certain VS Code contexts. Changes: - Added validation for selectedFile.fsPath before calling getWorkingFolder - Provides clear error messages that include URI scheme and selectedItem type - Suppresses automatic issue reporting since this is a user error - Applied fix to all affected commands: provision, deploy, up, down, restore, monitor, packageCli, and pipelineConfig - Added unit tests for the new validation logic Co-authored-by: vhvb1989 <24213737+vhvb1989@users.noreply.github.com> --- ext/vscode/src/commands/deploy.ts | 16 +++ ext/vscode/src/commands/down.ts | 16 +++ ext/vscode/src/commands/monitor.ts | 16 +++ ext/vscode/src/commands/packageCli.ts | 16 +++ ext/vscode/src/commands/pipeline.ts | 16 +++ ext/vscode/src/commands/provision.ts | 16 +++ ext/vscode/src/commands/restore.ts | 16 +++ ext/vscode/src/commands/up.ts | 16 +++ .../src/test/suite/unit/provision.test.ts | 112 ++++++++++++++++++ 9 files changed, 240 insertions(+) create mode 100644 ext/vscode/src/test/suite/unit/provision.test.ts diff --git a/ext/vscode/src/commands/deploy.ts b/ext/vscode/src/commands/deploy.ts index d0362d2ff87..870fda91d3a 100644 --- a/ext/vscode/src/commands/deploy.ts +++ b/ext/vscode/src/commands/deploy.ts @@ -25,6 +25,22 @@ export async function deploy(context: IActionContext, selectedItem?: vscode.Uri } else { selectedFile = selectedItem as vscode.Uri; } + + // Validate that selectedFile is valid for file system operations + // Virtual file systems or certain VS Code contexts may not provide a valid fsPath + if (selectedFile && !selectedFile.fsPath) { + context.errorHandling.suppressReportIssue = true; + const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : + isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : + selectedItem ? 'vscode.Uri' : 'undefined'; + throw new Error(vscode.l10n.t( + "Unable to determine working folder for deploy command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + + "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", + selectedFile.scheme, + itemType + )); + } + const workingFolder = await getWorkingFolder(context, selectedFile); const azureCli = await createAzureDevCli(context); diff --git a/ext/vscode/src/commands/down.ts b/ext/vscode/src/commands/down.ts index a937c04564d..c0764e65740 100644 --- a/ext/vscode/src/commands/down.ts +++ b/ext/vscode/src/commands/down.ts @@ -27,6 +27,22 @@ export async function down(context: IActionContext, selectedItem?: vscode.Uri | } else { selectedFile = selectedItem as vscode.Uri; } + + // Validate that selectedFile is valid for file system operations + // Virtual file systems or certain VS Code contexts may not provide a valid fsPath + if (selectedFile && !selectedFile.fsPath) { + context.errorHandling.suppressReportIssue = true; + const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : + isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : + selectedItem ? 'vscode.Uri' : 'undefined'; + throw new Error(vscode.l10n.t( + "Unable to determine working folder for down command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + + "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", + selectedFile.scheme, + itemType + )); + } + const workingFolder = await getWorkingFolder(context, selectedFile); const confirmPrompt = vscode.l10n.t("Are you sure you want to delete all this application's Azure resources? You can soft-delete certain resources like Azure KeyVaults to preserve their data, or permanently delete and purge them."); diff --git a/ext/vscode/src/commands/monitor.ts b/ext/vscode/src/commands/monitor.ts index b204e4c9090..57daad78500 100644 --- a/ext/vscode/src/commands/monitor.ts +++ b/ext/vscode/src/commands/monitor.ts @@ -35,6 +35,22 @@ export async function monitor(context: IActionContext, selectedItem?: vscode.Uri } else { selectedFile = selectedItem as vscode.Uri; } + + // Validate that selectedFile is valid for file system operations + // Virtual file systems or certain VS Code contexts may not provide a valid fsPath + if (selectedFile && !selectedFile.fsPath) { + context.errorHandling.suppressReportIssue = true; + const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : + isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : + selectedItem ? 'vscode.Uri' : 'undefined'; + throw new Error(vscode.l10n.t( + "Unable to determine working folder for monitor command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + + "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", + selectedFile.scheme, + itemType + )); + } + const workingFolder = await getWorkingFolder(context, selectedFile); const monitorChoices = await context.ui.showQuickPick(MonitorChoices, { diff --git a/ext/vscode/src/commands/packageCli.ts b/ext/vscode/src/commands/packageCli.ts index d485595bd44..e5c1ce96305 100644 --- a/ext/vscode/src/commands/packageCli.ts +++ b/ext/vscode/src/commands/packageCli.ts @@ -26,6 +26,22 @@ export async function packageCli(context: IActionContext, selectedItem?: vscode. } else { selectedFile = selectedItem as vscode.Uri; } + + // Validate that selectedFile is valid for file system operations + // Virtual file systems or certain VS Code contexts may not provide a valid fsPath + if (selectedFile && !selectedFile.fsPath) { + context.errorHandling.suppressReportIssue = true; + const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : + isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : + selectedItem ? 'vscode.Uri' : 'undefined'; + throw new Error(vscode.l10n.t( + "Unable to determine working folder for package command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + + "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", + selectedFile.scheme, + itemType + )); + } + const workingFolder = await getWorkingFolder(context, selectedFile); const azureCli = await createAzureDevCli(context); diff --git a/ext/vscode/src/commands/pipeline.ts b/ext/vscode/src/commands/pipeline.ts index 6cf6b92f1d6..4f232422eb3 100644 --- a/ext/vscode/src/commands/pipeline.ts +++ b/ext/vscode/src/commands/pipeline.ts @@ -27,6 +27,22 @@ export async function pipelineConfig(context: IActionContext, selectedItem?: vsc } else { selectedFile = selectedItem as vscode.Uri; } + + // Validate that selectedFile is valid for file system operations + // Virtual file systems or certain VS Code contexts may not provide a valid fsPath + if (selectedFile && !selectedFile.fsPath) { + context.errorHandling.suppressReportIssue = true; + const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : + isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : + selectedItem ? 'vscode.Uri' : 'undefined'; + throw new Error(vscode.l10n.t( + "Unable to determine working folder for pipeline config command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + + "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", + selectedFile.scheme, + itemType + )); + } + const workingFolder = await getWorkingFolder(context, selectedFile); const azureCli = await createAzureDevCli(context); diff --git a/ext/vscode/src/commands/provision.ts b/ext/vscode/src/commands/provision.ts index 6a42f1462c4..ea099830272 100644 --- a/ext/vscode/src/commands/provision.ts +++ b/ext/vscode/src/commands/provision.ts @@ -20,6 +20,22 @@ export async function provision(context: IActionContext, selectedItem?: vscode.U } else { selectedFile = selectedItem as vscode.Uri; } + + // Validate that selectedFile is valid for file system operations + // Virtual file systems or certain VS Code contexts may not provide a valid fsPath + if (selectedFile && !selectedFile.fsPath) { + context.errorHandling.suppressReportIssue = true; + const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : + isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : + selectedItem ? 'vscode.Uri' : 'undefined'; + throw new Error(vscode.l10n.t( + "Unable to determine working folder for provision command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + + "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", + selectedFile.scheme, + itemType + )); + } + const workingFolder = await getWorkingFolder(context, selectedFile); const azureCli = await createAzureDevCli(context); diff --git a/ext/vscode/src/commands/restore.ts b/ext/vscode/src/commands/restore.ts index 6b6ea733fe6..df8ead87f73 100644 --- a/ext/vscode/src/commands/restore.ts +++ b/ext/vscode/src/commands/restore.ts @@ -25,6 +25,22 @@ export async function restore(context: IActionContext, selectedItem?: vscode.Uri } else { selectedFile = selectedItem as vscode.Uri; } + + // Validate that selectedFile is valid for file system operations + // Virtual file systems or certain VS Code contexts may not provide a valid fsPath + if (selectedFile && !selectedFile.fsPath) { + context.errorHandling.suppressReportIssue = true; + const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : + isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : + selectedItem ? 'vscode.Uri' : 'undefined'; + throw new Error(vscode.l10n.t( + "Unable to determine working folder for restore command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + + "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", + selectedFile.scheme, + itemType + )); + } + const workingFolder = await getWorkingFolder(context, selectedFile); const azureCli = await createAzureDevCli(context); diff --git a/ext/vscode/src/commands/up.ts b/ext/vscode/src/commands/up.ts index dbf72bc5112..b91d3ac7f63 100644 --- a/ext/vscode/src/commands/up.ts +++ b/ext/vscode/src/commands/up.ts @@ -27,6 +27,22 @@ export async function up(context: IActionContext, selectedItem?: vscode.Uri | Tr } else { selectedFile = selectedItem as vscode.Uri; } + + // Validate that selectedFile is valid for file system operations + // Virtual file systems or certain VS Code contexts may not provide a valid fsPath + if (selectedFile && !selectedFile.fsPath) { + context.errorHandling.suppressReportIssue = true; + const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : + isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : + selectedItem ? 'vscode.Uri' : 'undefined'; + throw new Error(vscode.l10n.t( + "Unable to determine working folder for up command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + + "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", + selectedFile.scheme, + itemType + )); + } + const workingFolder = await getWorkingFolder(context, selectedFile); const azureCli = await createAzureDevCli(context); diff --git a/ext/vscode/src/test/suite/unit/provision.test.ts b/ext/vscode/src/test/suite/unit/provision.test.ts new file mode 100644 index 00000000000..61357ac6034 --- /dev/null +++ b/ext/vscode/src/test/suite/unit/provision.test.ts @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { expect } from 'chai'; +import * as vscode from 'vscode'; +import * as sinon from 'sinon'; +import { provision } from '../../../commands/provision'; +import { IActionContext } from '@microsoft/vscode-azext-utils'; +import { AzureDevCliApplication } from '../../../views/workspace/AzureDevCliApplication'; + +suite('provision command', () => { + let sandbox: sinon.SinonSandbox; + let mockContext: IActionContext; + + setup(() => { + sandbox = sinon.createSandbox(); + + mockContext = { + errorHandling: { + suppressReportIssue: false + }, + telemetry: { + properties: {} + } + } as unknown as IActionContext; + }); + + teardown(() => { + sandbox.restore(); + }); + + test('throws error when selectedFile has undefined fsPath (virtual file system)', async () => { + // Create a URI with a scheme that doesn't support fsPath + const virtualUri = vscode.Uri.parse('untitled:Untitled-1'); + + // Mock the URI to ensure fsPath is undefined + const mockUri = { + scheme: 'virtual', + fsPath: undefined as unknown as string + } as vscode.Uri; + + try { + await provision(mockContext, mockUri); + expect.fail('Should have thrown an error'); + } catch (error) { + expect(error).to.be.instanceOf(Error); + const errMessage = (error as Error).message; + expect(errMessage).to.include('Unable to determine working folder'); + expect(errMessage).to.include('virtual'); + expect(errMessage).to.include('vscode.Uri'); + expect(errMessage).to.include('virtual file systems'); + } + + expect(mockContext.errorHandling.suppressReportIssue).to.equal(true); + }); + + test('throws error when TreeViewModel has undefined fsPath', async () => { + const mockTreeViewModel = { + unwrap: () => ({ + context: { + configurationFile: { + scheme: 'virtual', + fsPath: undefined as unknown as string + } as vscode.Uri + } + }) + }; + + // Stub the isTreeViewModel function + const isTreeViewModelStub = sandbox.stub().returns(true); + const isAzureDevCliModelStub = sandbox.stub().returns(false); + + try { + await provision(mockContext, mockTreeViewModel as any); + expect.fail('Should have thrown an error'); + } catch (error) { + expect(error).to.be.instanceOf(Error); + const errMessage = (error as Error).message; + expect(errMessage).to.include('Unable to determine working folder'); + expect(errMessage).to.include('virtual'); + } + + expect(mockContext.errorHandling.suppressReportIssue).to.equal(true); + }); + + test('throws error when AzureDevCliModel has undefined fsPath', async () => { + const mockAzureDevCliModel = { + context: { + configurationFile: { + scheme: 'virtual', + fsPath: undefined as unknown as string + } as vscode.Uri + } + }; + + // Stub the type check functions + const isTreeViewModelStub = sandbox.stub().returns(false); + const isAzureDevCliModelStub = sandbox.stub().returns(true); + + try { + await provision(mockContext, mockAzureDevCliModel as any); + expect.fail('Should have thrown an error'); + } catch (error) { + expect(error).to.be.instanceOf(Error); + const errMessage = (error as Error).message; + expect(errMessage).to.include('Unable to determine working folder'); + expect(errMessage).to.include('virtual'); + } + + expect(mockContext.errorHandling.suppressReportIssue).to.equal(true); + }); +}); From 4deb1518f7a1b4f37eec7a59c027a2c4ded17ef9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:41:51 +0000 Subject: [PATCH 3/6] Simplify provision.test.ts based on code review feedback Removed unused stub functions that weren't actually being used. Simplified tests to focus on the core validation logic. Co-authored-by: vhvb1989 <24213737+vhvb1989@users.noreply.github.com> --- .../src/test/suite/unit/provision.test.ts | 64 +------------------ 1 file changed, 2 insertions(+), 62 deletions(-) diff --git a/ext/vscode/src/test/suite/unit/provision.test.ts b/ext/vscode/src/test/suite/unit/provision.test.ts index 61357ac6034..4a2dc6ab479 100644 --- a/ext/vscode/src/test/suite/unit/provision.test.ts +++ b/ext/vscode/src/test/suite/unit/provision.test.ts @@ -6,7 +6,6 @@ import * as vscode from 'vscode'; import * as sinon from 'sinon'; import { provision } from '../../../commands/provision'; import { IActionContext } from '@microsoft/vscode-azext-utils'; -import { AzureDevCliApplication } from '../../../views/workspace/AzureDevCliApplication'; suite('provision command', () => { let sandbox: sinon.SinonSandbox; @@ -30,10 +29,7 @@ suite('provision command', () => { }); test('throws error when selectedFile has undefined fsPath (virtual file system)', async () => { - // Create a URI with a scheme that doesn't support fsPath - const virtualUri = vscode.Uri.parse('untitled:Untitled-1'); - - // Mock the URI to ensure fsPath is undefined + // Mock the URI to ensure fsPath is undefined - simulates virtual file system const mockUri = { scheme: 'virtual', fsPath: undefined as unknown as string @@ -51,62 +47,6 @@ suite('provision command', () => { expect(errMessage).to.include('virtual file systems'); } - expect(mockContext.errorHandling.suppressReportIssue).to.equal(true); - }); - - test('throws error when TreeViewModel has undefined fsPath', async () => { - const mockTreeViewModel = { - unwrap: () => ({ - context: { - configurationFile: { - scheme: 'virtual', - fsPath: undefined as unknown as string - } as vscode.Uri - } - }) - }; - - // Stub the isTreeViewModel function - const isTreeViewModelStub = sandbox.stub().returns(true); - const isAzureDevCliModelStub = sandbox.stub().returns(false); - - try { - await provision(mockContext, mockTreeViewModel as any); - expect.fail('Should have thrown an error'); - } catch (error) { - expect(error).to.be.instanceOf(Error); - const errMessage = (error as Error).message; - expect(errMessage).to.include('Unable to determine working folder'); - expect(errMessage).to.include('virtual'); - } - - expect(mockContext.errorHandling.suppressReportIssue).to.equal(true); - }); - - test('throws error when AzureDevCliModel has undefined fsPath', async () => { - const mockAzureDevCliModel = { - context: { - configurationFile: { - scheme: 'virtual', - fsPath: undefined as unknown as string - } as vscode.Uri - } - }; - - // Stub the type check functions - const isTreeViewModelStub = sandbox.stub().returns(false); - const isAzureDevCliModelStub = sandbox.stub().returns(true); - - try { - await provision(mockContext, mockAzureDevCliModel as any); - expect.fail('Should have thrown an error'); - } catch (error) { - expect(error).to.be.instanceOf(Error); - const errMessage = (error as Error).message; - expect(errMessage).to.include('Unable to determine working folder'); - expect(errMessage).to.include('virtual'); - } - - expect(mockContext.errorHandling.suppressReportIssue).to.equal(true); + expect(mockContext.errorHandling.suppressReportIssue).to.equal(true, 'Should suppress automatic issue reporting for user errors'); }); }); From d86684857abf8e86a1866838c34155a9462bdf82 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:44:43 +0000 Subject: [PATCH 4/6] Refactor validation logic into shared utility function Based on code review feedback: - Extracted duplicated validation logic to validateFileSystemUri() in cmdUtil.ts - Updated all 8 command files to use the shared function - Simplified test assertions - Improved code maintainability by reducing duplication Co-authored-by: vhvb1989 <24213737+vhvb1989@users.noreply.github.com> --- ext/vscode/src/commands/cmdUtil.ts | 31 +++++++++++++++++++ ext/vscode/src/commands/deploy.ts | 16 ++-------- ext/vscode/src/commands/down.ts | 16 ++-------- ext/vscode/src/commands/monitor.ts | 16 ++-------- ext/vscode/src/commands/packageCli.ts | 16 ++-------- ext/vscode/src/commands/pipeline.ts | 16 ++-------- ext/vscode/src/commands/provision.ts | 16 ++-------- ext/vscode/src/commands/restore.ts | 16 ++-------- ext/vscode/src/commands/up.ts | 16 ++-------- .../src/test/suite/unit/provision.test.ts | 10 ++++-- 10 files changed, 55 insertions(+), 114 deletions(-) diff --git a/ext/vscode/src/commands/cmdUtil.ts b/ext/vscode/src/commands/cmdUtil.ts index dc251c28a2e..b301d313413 100644 --- a/ext/vscode/src/commands/cmdUtil.ts +++ b/ext/vscode/src/commands/cmdUtil.ts @@ -9,9 +9,40 @@ import * as vscode from 'vscode'; import { createAzureDevCli } from '../utils/azureDevCli'; import { execAsync } from '../utils/execAsync'; import { fileExists } from '../utils/fileUtils'; +import { isAzureDevCliModel, isTreeViewModel, TreeViewModel } from '../utils/isTreeViewModel'; const AzureYamlGlobPattern: vscode.GlobPattern = '**/[aA][zZ][uU][rR][eE].{[yY][aA][mM][lL],[yY][mM][lL]}'; +/** + * Validates that a URI has a valid fsPath for file system operations. + * Virtual file systems or certain VS Code contexts may not provide a valid fsPath. + * @param context The action context + * @param selectedFile The URI to validate + * @param selectedItem The original selected item (for error message context) + * @param commandName The name of the command being executed (for error message) + * @throws Error if the URI doesn't have a valid fsPath + */ +export function validateFileSystemUri( + context: IActionContext, + selectedFile: vscode.Uri | undefined, + selectedItem: vscode.Uri | TreeViewModel | undefined, + commandName: string +): void { + if (selectedFile && !selectedFile.fsPath) { + context.errorHandling.suppressReportIssue = true; + const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : + isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : + selectedItem ? 'vscode.Uri' : 'undefined'; + throw new Error(vscode.l10n.t( + "Unable to determine working folder for {0} command. The selected file has an unsupported URI scheme '{1}' (selectedItem type: {2}). " + + "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", + commandName, + selectedFile.scheme, + itemType + )); + } +} + // If the command was invoked with a specific file context, use the file context as the working directory for running Azure developer CLI commands. // Otherwise search the workspace for "azure.yaml" or "azure.yml" files. If only one is found, use it (i.e. its folder). If more than one is found, ask the user which one to use. // If at this point we still do not have a working directory, prompt the user to select one. diff --git a/ext/vscode/src/commands/deploy.ts b/ext/vscode/src/commands/deploy.ts index 870fda91d3a..355f1ba8596 100644 --- a/ext/vscode/src/commands/deploy.ts +++ b/ext/vscode/src/commands/deploy.ts @@ -10,7 +10,7 @@ import { executeAsTask } from '../utils/executeAsTask'; import { isAzureDevCliModel, isTreeViewModel, TreeViewModel } from '../utils/isTreeViewModel'; import { AzureDevCliModel } from '../views/workspace/AzureDevCliModel'; import { AzureDevCliService } from '../views/workspace/AzureDevCliService'; -import { getAzDevTerminalTitle, getWorkingFolder } from './cmdUtil'; +import { getAzDevTerminalTitle, getWorkingFolder, validateFileSystemUri } from './cmdUtil'; export async function deploy(context: IActionContext, selectedItem?: vscode.Uri | TreeViewModel): Promise { let selectedModel: AzureDevCliModel | undefined; @@ -27,19 +27,7 @@ export async function deploy(context: IActionContext, selectedItem?: vscode.Uri } // Validate that selectedFile is valid for file system operations - // Virtual file systems or certain VS Code contexts may not provide a valid fsPath - if (selectedFile && !selectedFile.fsPath) { - context.errorHandling.suppressReportIssue = true; - const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : - isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : - selectedItem ? 'vscode.Uri' : 'undefined'; - throw new Error(vscode.l10n.t( - "Unable to determine working folder for deploy command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + - "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", - selectedFile.scheme, - itemType - )); - } + validateFileSystemUri(context, selectedFile, selectedItem, 'deploy'); const workingFolder = await getWorkingFolder(context, selectedFile); diff --git a/ext/vscode/src/commands/down.ts b/ext/vscode/src/commands/down.ts index c0764e65740..822a4124b74 100644 --- a/ext/vscode/src/commands/down.ts +++ b/ext/vscode/src/commands/down.ts @@ -9,7 +9,7 @@ import { createAzureDevCli } from '../utils/azureDevCli'; import { executeAsTask } from '../utils/executeAsTask'; import { isAzureDevCliModel, isTreeViewModel, TreeViewModel } from '../utils/isTreeViewModel'; import { AzureDevCliApplication } from '../views/workspace/AzureDevCliApplication'; -import { getAzDevTerminalTitle, getWorkingFolder, } from './cmdUtil'; +import { getAzDevTerminalTitle, getWorkingFolder, validateFileSystemUri, } from './cmdUtil'; /** * A tuple representing the arguments that must be passed to the `down` command when executed via {@link vscode.commands.executeCommand} @@ -29,19 +29,7 @@ export async function down(context: IActionContext, selectedItem?: vscode.Uri | } // Validate that selectedFile is valid for file system operations - // Virtual file systems or certain VS Code contexts may not provide a valid fsPath - if (selectedFile && !selectedFile.fsPath) { - context.errorHandling.suppressReportIssue = true; - const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : - isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : - selectedItem ? 'vscode.Uri' : 'undefined'; - throw new Error(vscode.l10n.t( - "Unable to determine working folder for down command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + - "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", - selectedFile.scheme, - itemType - )); - } + validateFileSystemUri(context, selectedFile, selectedItem, 'down'); const workingFolder = await getWorkingFolder(context, selectedFile); diff --git a/ext/vscode/src/commands/monitor.ts b/ext/vscode/src/commands/monitor.ts index 57daad78500..16f53b91c54 100644 --- a/ext/vscode/src/commands/monitor.ts +++ b/ext/vscode/src/commands/monitor.ts @@ -8,7 +8,7 @@ import { createAzureDevCli } from '../utils/azureDevCli'; import { execAsync } from '../utils/execAsync'; import { isAzureDevCliModel, isTreeViewModel, TreeViewModel } from '../utils/isTreeViewModel'; import { AzureDevCliApplication } from '../views/workspace/AzureDevCliApplication'; -import { getWorkingFolder } from './cmdUtil'; +import { getWorkingFolder, validateFileSystemUri } from './cmdUtil'; const MonitorChoices: IAzureQuickPickItem[] = [ { @@ -37,19 +37,7 @@ export async function monitor(context: IActionContext, selectedItem?: vscode.Uri } // Validate that selectedFile is valid for file system operations - // Virtual file systems or certain VS Code contexts may not provide a valid fsPath - if (selectedFile && !selectedFile.fsPath) { - context.errorHandling.suppressReportIssue = true; - const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : - isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : - selectedItem ? 'vscode.Uri' : 'undefined'; - throw new Error(vscode.l10n.t( - "Unable to determine working folder for monitor command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + - "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", - selectedFile.scheme, - itemType - )); - } + validateFileSystemUri(context, selectedFile, selectedItem, 'monitor'); const workingFolder = await getWorkingFolder(context, selectedFile); diff --git a/ext/vscode/src/commands/packageCli.ts b/ext/vscode/src/commands/packageCli.ts index e5c1ce96305..5ee56639be0 100644 --- a/ext/vscode/src/commands/packageCli.ts +++ b/ext/vscode/src/commands/packageCli.ts @@ -10,7 +10,7 @@ import { executeAsTask } from '../utils/executeAsTask'; import { isAzureDevCliModel, isTreeViewModel, TreeViewModel } from '../utils/isTreeViewModel'; import { AzureDevCliModel } from '../views/workspace/AzureDevCliModel'; import { AzureDevCliService } from '../views/workspace/AzureDevCliService'; -import { getAzDevTerminalTitle, getWorkingFolder } from './cmdUtil'; +import { getAzDevTerminalTitle, getWorkingFolder, validateFileSystemUri } from './cmdUtil'; // `package` is a reserved identifier so `packageCli` had to be used instead export async function packageCli(context: IActionContext, selectedItem?: vscode.Uri | TreeViewModel): Promise { @@ -28,19 +28,7 @@ export async function packageCli(context: IActionContext, selectedItem?: vscode. } // Validate that selectedFile is valid for file system operations - // Virtual file systems or certain VS Code contexts may not provide a valid fsPath - if (selectedFile && !selectedFile.fsPath) { - context.errorHandling.suppressReportIssue = true; - const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : - isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : - selectedItem ? 'vscode.Uri' : 'undefined'; - throw new Error(vscode.l10n.t( - "Unable to determine working folder for package command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + - "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", - selectedFile.scheme, - itemType - )); - } + validateFileSystemUri(context, selectedFile, selectedItem, 'package'); const workingFolder = await getWorkingFolder(context, selectedFile); diff --git a/ext/vscode/src/commands/pipeline.ts b/ext/vscode/src/commands/pipeline.ts index 4f232422eb3..cf2de862217 100644 --- a/ext/vscode/src/commands/pipeline.ts +++ b/ext/vscode/src/commands/pipeline.ts @@ -4,7 +4,7 @@ import { IActionContext } from '@microsoft/vscode-azext-utils'; import { composeArgs, withArg } from '@microsoft/vscode-processutils'; import * as vscode from 'vscode'; -import { getAzDevTerminalTitle, getWorkingFolder } from './cmdUtil'; +import { getAzDevTerminalTitle, getWorkingFolder, validateFileSystemUri } from './cmdUtil'; import { TelemetryId } from '../telemetry/telemetryId'; import { createAzureDevCli } from '../utils/azureDevCli'; import { executeAsTask } from '../utils/executeAsTask'; @@ -29,19 +29,7 @@ export async function pipelineConfig(context: IActionContext, selectedItem?: vsc } // Validate that selectedFile is valid for file system operations - // Virtual file systems or certain VS Code contexts may not provide a valid fsPath - if (selectedFile && !selectedFile.fsPath) { - context.errorHandling.suppressReportIssue = true; - const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : - isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : - selectedItem ? 'vscode.Uri' : 'undefined'; - throw new Error(vscode.l10n.t( - "Unable to determine working folder for pipeline config command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + - "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", - selectedFile.scheme, - itemType - )); - } + validateFileSystemUri(context, selectedFile, selectedItem, 'pipeline config'); const workingFolder = await getWorkingFolder(context, selectedFile); diff --git a/ext/vscode/src/commands/provision.ts b/ext/vscode/src/commands/provision.ts index ea099830272..fe72669e3e3 100644 --- a/ext/vscode/src/commands/provision.ts +++ b/ext/vscode/src/commands/provision.ts @@ -9,7 +9,7 @@ import { createAzureDevCli } from '../utils/azureDevCli'; import { executeAsTask } from '../utils/executeAsTask'; import { isAzureDevCliModel, isTreeViewModel, TreeViewModel } from '../utils/isTreeViewModel'; import { AzureDevCliApplication } from '../views/workspace/AzureDevCliApplication'; -import { getAzDevTerminalTitle, getWorkingFolder } from './cmdUtil'; +import { getAzDevTerminalTitle, getWorkingFolder, validateFileSystemUri } from './cmdUtil'; export async function provision(context: IActionContext, selectedItem?: vscode.Uri | TreeViewModel): Promise { let selectedFile: vscode.Uri | undefined; @@ -22,19 +22,7 @@ export async function provision(context: IActionContext, selectedItem?: vscode.U } // Validate that selectedFile is valid for file system operations - // Virtual file systems or certain VS Code contexts may not provide a valid fsPath - if (selectedFile && !selectedFile.fsPath) { - context.errorHandling.suppressReportIssue = true; - const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : - isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : - selectedItem ? 'vscode.Uri' : 'undefined'; - throw new Error(vscode.l10n.t( - "Unable to determine working folder for provision command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + - "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", - selectedFile.scheme, - itemType - )); - } + validateFileSystemUri(context, selectedFile, selectedItem, 'provision'); const workingFolder = await getWorkingFolder(context, selectedFile); diff --git a/ext/vscode/src/commands/restore.ts b/ext/vscode/src/commands/restore.ts index df8ead87f73..a661a260ff6 100644 --- a/ext/vscode/src/commands/restore.ts +++ b/ext/vscode/src/commands/restore.ts @@ -10,7 +10,7 @@ import { executeAsTask } from '../utils/executeAsTask'; import { isAzureDevCliModel, isTreeViewModel, TreeViewModel } from '../utils/isTreeViewModel'; import { AzureDevCliModel } from '../views/workspace/AzureDevCliModel'; import { AzureDevCliService } from '../views/workspace/AzureDevCliService'; -import { getAzDevTerminalTitle, getWorkingFolder } from './cmdUtil'; +import { getAzDevTerminalTitle, getWorkingFolder, validateFileSystemUri } from './cmdUtil'; export async function restore(context: IActionContext, selectedItem?: vscode.Uri | TreeViewModel): Promise { let selectedModel: AzureDevCliModel | undefined; @@ -27,19 +27,7 @@ export async function restore(context: IActionContext, selectedItem?: vscode.Uri } // Validate that selectedFile is valid for file system operations - // Virtual file systems or certain VS Code contexts may not provide a valid fsPath - if (selectedFile && !selectedFile.fsPath) { - context.errorHandling.suppressReportIssue = true; - const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : - isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : - selectedItem ? 'vscode.Uri' : 'undefined'; - throw new Error(vscode.l10n.t( - "Unable to determine working folder for restore command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + - "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", - selectedFile.scheme, - itemType - )); - } + validateFileSystemUri(context, selectedFile, selectedItem, 'restore'); const workingFolder = await getWorkingFolder(context, selectedFile); diff --git a/ext/vscode/src/commands/up.ts b/ext/vscode/src/commands/up.ts index b91d3ac7f63..b5bf01d3d8c 100644 --- a/ext/vscode/src/commands/up.ts +++ b/ext/vscode/src/commands/up.ts @@ -9,7 +9,7 @@ import { createAzureDevCli } from '../utils/azureDevCli'; import { executeAsTask } from '../utils/executeAsTask'; import { isAzureDevCliModel, isTreeViewModel, TreeViewModel } from '../utils/isTreeViewModel'; import { AzureDevCliApplication } from '../views/workspace/AzureDevCliApplication'; -import { getAzDevTerminalTitle, getWorkingFolder } from './cmdUtil'; +import { getAzDevTerminalTitle, getWorkingFolder, validateFileSystemUri } from './cmdUtil'; /** * A tuple representing the arguments that must be passed to the `up` command when executed via {@link vscode.commands.executeCommand} @@ -29,19 +29,7 @@ export async function up(context: IActionContext, selectedItem?: vscode.Uri | Tr } // Validate that selectedFile is valid for file system operations - // Virtual file systems or certain VS Code contexts may not provide a valid fsPath - if (selectedFile && !selectedFile.fsPath) { - context.errorHandling.suppressReportIssue = true; - const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : - isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : - selectedItem ? 'vscode.Uri' : 'undefined'; - throw new Error(vscode.l10n.t( - "Unable to determine working folder for up command. The selected file has an unsupported URI scheme '{0}' (selectedItem type: {1}). " + - "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", - selectedFile.scheme, - itemType - )); - } + validateFileSystemUri(context, selectedFile, selectedItem, 'up'); const workingFolder = await getWorkingFolder(context, selectedFile); diff --git a/ext/vscode/src/test/suite/unit/provision.test.ts b/ext/vscode/src/test/suite/unit/provision.test.ts index 4a2dc6ab479..0aa464b03d7 100644 --- a/ext/vscode/src/test/suite/unit/provision.test.ts +++ b/ext/vscode/src/test/suite/unit/provision.test.ts @@ -32,8 +32,14 @@ suite('provision command', () => { // Mock the URI to ensure fsPath is undefined - simulates virtual file system const mockUri = { scheme: 'virtual', - fsPath: undefined as unknown as string - } as vscode.Uri; + fsPath: undefined, + authority: '', + path: '', + query: '', + fragment: '', + with: () => mockUri, + toString: () => 'virtual:/test' + } as unknown as vscode.Uri; try { await provision(mockContext, mockUri); From a53d159c1768e0bdc3193a1452597a256651ac0a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:45:53 +0000 Subject: [PATCH 5/6] Fix validation to use strict equality check for undefined Changed condition from `!selectedFile.fsPath` to `selectedFile.fsPath === undefined` to avoid incorrectly rejecting empty string paths which are valid for root directories. Co-authored-by: vhvb1989 <24213737+vhvb1989@users.noreply.github.com> --- ext/vscode/src/commands/cmdUtil.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/vscode/src/commands/cmdUtil.ts b/ext/vscode/src/commands/cmdUtil.ts index b301d313413..11e65b10e94 100644 --- a/ext/vscode/src/commands/cmdUtil.ts +++ b/ext/vscode/src/commands/cmdUtil.ts @@ -28,7 +28,7 @@ export function validateFileSystemUri( selectedItem: vscode.Uri | TreeViewModel | undefined, commandName: string ): void { - if (selectedFile && !selectedFile.fsPath) { + if (selectedFile && selectedFile.fsPath === undefined) { context.errorHandling.suppressReportIssue = true; const itemType = isTreeViewModel(selectedItem) ? 'TreeViewModel' : isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : From ca17642605caafed3ea7f495cdae14c58ec894aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:32:43 +0000 Subject: [PATCH 6/6] Fix l10n.t() to use single string literal instead of concatenation The first argument to vscode.l10n.t() should be a single string literal for proper localization tooling compatibility. Removed string concatenation and used a single multi-line string literal instead. Co-authored-by: vhvb1989 <24213737+vhvb1989@users.noreply.github.com> --- ext/vscode/src/commands/cmdUtil.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/vscode/src/commands/cmdUtil.ts b/ext/vscode/src/commands/cmdUtil.ts index 11e65b10e94..3f879e17780 100644 --- a/ext/vscode/src/commands/cmdUtil.ts +++ b/ext/vscode/src/commands/cmdUtil.ts @@ -34,8 +34,7 @@ export function validateFileSystemUri( isAzureDevCliModel(selectedItem) ? 'AzureDevCliModel' : selectedItem ? 'vscode.Uri' : 'undefined'; throw new Error(vscode.l10n.t( - "Unable to determine working folder for {0} command. The selected file has an unsupported URI scheme '{1}' (selectedItem type: {2}). " + - "Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", + "Unable to determine working folder for {0} command. The selected file has an unsupported URI scheme '{1}' (selectedItem type: {2}). Azure Developer CLI commands are not supported in virtual file systems. Please open a local folder or clone the repository locally.", commandName, selectedFile.scheme, itemType