From 086ec55b06d403e3414ea08c14288d2516ab0225 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Tue, 1 Jul 2025 19:14:31 +0300 Subject: [PATCH 1/2] fix: improve /openDevContainer support with local workspace folder This change allows `localWorkspaceFolder` and `localConfigFile` to be provided which allows us to use `dev-container` rather than `attached-container` to enter enabling all dev container features like file change detection and rebuilding. --- CHANGELOG.md | 3 +++ src/commands.ts | 27 +++++++++++++++++++++++++-- src/extension.ts | 10 ++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3af0db4..f07f13fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +- Update `/openDevContainer` to support all dev container features when hostPath + and configFile are provided. + ## [v1.9.2](https://github.com/coder/vscode-coder/releases/tag/v1.9.2) 2025-06-25 ### Fixed diff --git a/src/commands.ts b/src/commands.ts index c1d49f91..43e77944 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -631,6 +631,8 @@ export class Commands { const workspaceAgent = args[2] as string; const devContainerName = args[3] as string; const devContainerFolder = args[4] as string; + const localWorkspaceFolder = args[5] as string | undefined; + const localConfigFile = args[6] as string | undefined; await openDevContainer( baseUrl, @@ -639,6 +641,8 @@ export class Commands { workspaceAgent, devContainerName, devContainerFolder, + localWorkspaceFolder, + localConfigFile, ); } @@ -751,6 +755,8 @@ async function openDevContainer( workspaceAgent: string, devContainerName: string, devContainerFolder: string, + localWorkspaceFolder: string | undefined, + localConfigFile: string | undefined, ) { const remoteAuthority = toRemoteAuthority( baseUrl, @@ -759,11 +765,28 @@ async function openDevContainer( workspaceAgent, ); + if (!localWorkspaceFolder) { + localConfigFile = undefined; + } + let configFile; + if (localConfigFile) { + configFile = { + path: localConfigFile, + scheme: "vscode-fileHost", + }; + } const devContainer = Buffer.from( - JSON.stringify({ containerName: devContainerName }), + JSON.stringify({ + containerName: devContainerName, + hostPath: localWorkspaceFolder, + configFile, + localDocker: false, + }), "utf-8", ).toString("hex"); - const devContainerAuthority = `attached-container+${devContainer}@${remoteAuthority}`; + + const type = localWorkspaceFolder ? "dev-container" : "attached-container"; + const devContainerAuthority = `${type}+${devContainer}@${remoteAuthority}`; let newWindow = true; if (!vscode.workspace.workspaceFolders?.length) { diff --git a/src/extension.ts b/src/extension.ts index 10fd7783..05eb7319 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -165,6 +165,8 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { const workspaceAgent = params.get("agent"); const devContainerName = params.get("devContainerName"); const devContainerFolder = params.get("devContainerFolder"); + const localWorkspaceFolder = params.get("localWorkspaceFolder"); + const localConfigFile = params.get("localConfigFile"); if (!workspaceOwner) { throw new Error( @@ -190,6 +192,12 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { ); } + if (localConfigFile && !localWorkspaceFolder) { + throw new Error( + "local workspace folder must be specified as a query parameter if local config file is provided", + ); + } + // We are not guaranteed that the URL we currently have is for the URL // this workspace belongs to, or that we even have a URL at all (the // queries will default to localhost) so ask for it if missing. @@ -228,6 +236,8 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { workspaceAgent, devContainerName, devContainerFolder, + localWorkspaceFolder, + localConfigFile, ); } else { throw new Error(`Unknown path ${uri.path}`); From 52a37a955566129a4292ad0621dd9b2e3388faf9 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Wed, 2 Jul 2025 11:53:10 +0300 Subject: [PATCH 2/2] refactor args --- src/commands.ts | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 43e77944..d6734376 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -620,20 +620,20 @@ export class Commands { * * Throw if not logged into a deployment. */ - public async openDevContainer(...args: string[]): Promise { + public async openDevContainer( + workspaceOwner: string, + workspaceName: string, + workspaceAgent: string, + devContainerName: string, + devContainerFolder: string, + localWorkspaceFolder: string = "", + localConfigFile: string = "", + ): Promise { const baseUrl = this.restClient.getAxiosInstance().defaults.baseURL; if (!baseUrl) { throw new Error("You are not logged in"); } - const workspaceOwner = args[0] as string; - const workspaceName = args[1] as string; - const workspaceAgent = args[2] as string; - const devContainerName = args[3] as string; - const devContainerFolder = args[4] as string; - const localWorkspaceFolder = args[5] as string | undefined; - const localConfigFile = args[6] as string | undefined; - await openDevContainer( baseUrl, workspaceOwner, @@ -755,8 +755,8 @@ async function openDevContainer( workspaceAgent: string, devContainerName: string, devContainerFolder: string, - localWorkspaceFolder: string | undefined, - localConfigFile: string | undefined, + localWorkspaceFolder: string = "", + localConfigFile: string = "", ) { const remoteAuthority = toRemoteAuthority( baseUrl, @@ -765,20 +765,18 @@ async function openDevContainer( workspaceAgent, ); - if (!localWorkspaceFolder) { - localConfigFile = undefined; - } - let configFile; - if (localConfigFile) { - configFile = { - path: localConfigFile, - scheme: "vscode-fileHost", - }; - } + const hostPath = localWorkspaceFolder ? localWorkspaceFolder : undefined; + const configFile = + hostPath && localConfigFile + ? { + path: localConfigFile, + scheme: "vscode-fileHost", + } + : undefined; const devContainer = Buffer.from( JSON.stringify({ containerName: devContainerName, - hostPath: localWorkspaceFolder, + hostPath, configFile, localDocker: false, }),