From 5a2437cc71ed03790e51ec9572559ff35af8361e Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 18 Aug 2026 18:15:04 +0000 Subject: [PATCH] fix(registry/coder/modules/vscode-web): install extensions when reusing a cached copy Reusing a cached or pre-installed VS Code Web (use_cached=true) exited before extension installation, so both the extensions list and auto_install_extensions were skipped. Skip only the download now; extensions are installed and the server started in both the fresh and cached paths. Offline behavior is unchanged. Bump vscode-web to 1.6.2. --- registry/coder/modules/vscode-web/README.md | 12 +-- .../coder/modules/vscode-web/main.test.ts | 84 +++++++++++++++++ registry/coder/modules/vscode-web/run.sh | 90 ++++++++++--------- 3 files changed, 136 insertions(+), 50 deletions(-) diff --git a/registry/coder/modules/vscode-web/README.md b/registry/coder/modules/vscode-web/README.md index e3a1681ea..08b952b5a 100644 --- a/registry/coder/modules/vscode-web/README.md +++ b/registry/coder/modules/vscode-web/README.md @@ -14,7 +14,7 @@ Automatically install [Visual Studio Code Server](https://code.visualstudio.com/ module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.6.1" + version = "1.6.2" agent_id = coder_agent.example.id accept_license = true } @@ -30,7 +30,7 @@ module "vscode-web" { module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.6.1" + version = "1.6.2" agent_id = coder_agent.example.id install_prefix = "/home/coder/.vscode-web" folder = "/home/coder" @@ -44,7 +44,7 @@ module "vscode-web" { module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.6.1" + version = "1.6.2" agent_id = coder_agent.example.id extensions = ["github.copilot", "ms-python.python", "ms-toolsai.jupyter"] accept_license = true @@ -59,7 +59,7 @@ Configure VS Code's [Machine settings.json](https://code.visualstudio.com/docs/g module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.6.1" + version = "1.6.2" agent_id = coder_agent.example.id extensions = ["dracula-theme.theme-dracula"] settings = { @@ -80,7 +80,7 @@ By default, this module installs the latest. To pin a specific version, retrieve module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.6.1" + version = "1.6.2" agent_id = coder_agent.example.id commit_id = "e54c774e0add60467559eb0d1e229c6452cf8447" accept_license = true @@ -96,7 +96,7 @@ Note: Either `workspace` or `folder` can be used, but not both simultaneously. T module "vscode-web" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-web/coder" - version = "1.6.1" + version = "1.6.2" agent_id = coder_agent.example.id workspace = "/home/coder/coder.code-workspace" } diff --git a/registry/coder/modules/vscode-web/main.test.ts b/registry/coder/modules/vscode-web/main.test.ts index bcc64d038..2b00da257 100644 --- a/registry/coder/modules/vscode-web/main.test.ts +++ b/registry/coder/modules/vscode-web/main.test.ts @@ -492,4 +492,88 @@ JSONCEOF`, expect(result.stdout).toContain("INSTALLED:ms-python.python"); expect(result.stdout).toContain("INSTALLED:dbaeumer.vscode-eslint"); }); + + it("installs the extensions list when reusing a cached copy", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + accept_license: true, + use_cached: true, + extensions: '["ms-python.python", "golang.go"]', + }); + + const containerId = await runContainer("ubuntu:22.04"); + cleanupContainers.push(containerId); + + // Pre-bake the cached server. With use_cached set, the script skips the + // download but must still install the configured extensions. + await execContainer(containerId, [ + "bash", + "-c", + `mkdir -p /tmp/vscode-web/bin && cat > /tmp/vscode-web/bin/code-server << 'MOCKEOF' +${MOCK_VSCODE_WEB} +MOCKEOF +chmod +x /tmp/vscode-web/bin/code-server`, + ]); + + const script = findResourceInstance(state, "coder_script"); + const result = await execContainer(containerId, [ + "bash", + "-c", + script.script, + ]); + + expect(result.exitCode).toBe(0); + expect(result.stdout).toContain("Found a copy of VS Code Web"); + // The explicit extensions loop captures the CLI output, so assert on the + // per-extension log line the script prints before each install. + expect(result.stdout).toContain("Installing extension ms-python.python"); + expect(result.stdout).toContain("Installing extension golang.go"); + }); + + it("auto-installs recommended extensions when reusing a cached copy", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + accept_license: true, + use_cached: true, + auto_install_extensions: true, + }); + + const containerId = await runContainer("ubuntu:22.04"); + cleanupContainers.push(containerId); + + await execContainer(containerId, ["apt-get", "update", "-qq"]); + await execContainer(containerId, ["apt-get", "install", "-y", "-qq", "jq"]); + + // Pre-bake the cached server; the download is skipped, so no curl/tar stub + // is needed. The recommendations path must still run. + await execContainer(containerId, [ + "bash", + "-c", + `mkdir -p /tmp/vscode-web/bin && cat > /tmp/vscode-web/bin/code-server << 'MOCKEOF' +${MOCK_VSCODE_WEB} +MOCKEOF +chmod +x /tmp/vscode-web/bin/code-server`, + ]); + + await execContainer(containerId, [ + "bash", + "-c", + `mkdir -p /root/.vscode && cat > /root/.vscode/extensions.json << 'JSONCEOF' +${JSONC_EXTENSIONS_JSON} +JSONCEOF`, + ]); + + const script = findResourceInstance(state, "coder_script"); + const result = await execContainer(containerId, [ + "bash", + "-c", + script.script, + ]); + + expect(result.exitCode).toBe(0); + expect(result.stdout).toContain("Found a copy of VS Code Web"); + expect(result.stdout).toContain("INSTALLED:ms-python.python"); + expect(result.stdout).toContain("INSTALLED:dbaeumer.vscode-eslint"); + expect(result.stdout).toContain("INSTALLED:esbenp.prettier-vscode"); + }); }); diff --git a/registry/coder/modules/vscode-web/run.sh b/registry/coder/modules/vscode-web/run.sh index 0256812a2..fc1c76765 100644 --- a/registry/coder/modules/vscode-web/run.sh +++ b/registry/coder/modules/vscode-web/run.sh @@ -79,62 +79,64 @@ if [ -n "$SETTINGS_B64" ]; then fi fi -# Check if vscode-server is already installed for offline or cached mode +SKIP_INSTALL=false if [ -f "$VSCODE_WEB" ]; then - if [ "${OFFLINE}" = true ] || [ "${USE_CACHED}" = true ]; then - echo "🥳 Found a copy of VS Code Web" + echo "🥳 Found a copy of VS Code Web" + if [ "${OFFLINE}" = true ]; then run_vscode_web exit 0 + elif [ "${USE_CACHED}" = true ]; then + SKIP_INSTALL=true fi -fi -# Offline mode always expects a copy of vscode-server to be present -if [ "${OFFLINE}" = true ]; then +elif [ "${OFFLINE}" = true ]; then echo "Failed to find a copy of VS Code Web" exit 1 fi -# Create install prefix -mkdir -p ${INSTALL_PREFIX} - -printf "$${BOLD}Installing Microsoft Visual Studio Code Server!\n" - -# Download and extract vscode-server -ARCH=$(uname -m) -case "$ARCH" in - x86_64) ARCH="x64" ;; - aarch64) ARCH="arm64" ;; - *) - echo "Unsupported architecture" - exit 1 - ;; -esac - -# Detect the platform -if [ -n "${PLATFORM}" ]; then - DETECTED_PLATFORM="${PLATFORM}" -elif [ -f /etc/alpine-release ] || grep -qi 'ID=alpine' /etc/os-release 2> /dev/null || command -v apk > /dev/null 2>&1; then - DETECTED_PLATFORM="alpine" -elif [ "$(uname -s)" = "Darwin" ]; then - DETECTED_PLATFORM="darwin" -else - DETECTED_PLATFORM="linux" -fi +if [ "$SKIP_INSTALL" != true ]; then + # Create install prefix + mkdir -p ${INSTALL_PREFIX} + + printf "$${BOLD}Installing Microsoft Visual Studio Code Server!\n" + + # Download and extract vscode-server + ARCH=$(uname -m) + case "$ARCH" in + x86_64) ARCH="x64" ;; + aarch64) ARCH="arm64" ;; + *) + echo "Unsupported architecture" + exit 1 + ;; + esac + + # Detect the platform + if [ -n "${PLATFORM}" ]; then + DETECTED_PLATFORM="${PLATFORM}" + elif [ -f /etc/alpine-release ] || grep -qi 'ID=alpine' /etc/os-release 2> /dev/null || command -v apk > /dev/null 2>&1; then + DETECTED_PLATFORM="alpine" + elif [ "$(uname -s)" = "Darwin" ]; then + DETECTED_PLATFORM="darwin" + else + DETECTED_PLATFORM="linux" + fi -# Check if a specific VS Code Web commit ID was provided -if [ -n "${COMMIT_ID}" ]; then - HASH="${COMMIT_ID}" -else - HASH=$(curl -fsSL https://update.code.visualstudio.com/api/commits/stable/server-$DETECTED_PLATFORM-$ARCH-web | cut -d '"' -f 2) -fi -printf "$${BOLD}VS Code Web commit id version $HASH.\n" + # Check if a specific VS Code Web commit ID was provided + if [ -n "${COMMIT_ID}" ]; then + HASH="${COMMIT_ID}" + else + HASH=$(curl -fsSL https://update.code.visualstudio.com/api/commits/stable/server-$DETECTED_PLATFORM-$ARCH-web | cut -d '"' -f 2) + fi + printf "$${BOLD}VS Code Web commit id version $HASH.\n" -output=$(curl -fsSL "https://vscode.download.prss.microsoft.com/dbazure/download/stable/$HASH/vscode-server-$DETECTED_PLATFORM-$ARCH-web.tar.gz" | tar -xz -C "${INSTALL_PREFIX}" --strip-components 1) + output=$(curl -fsSL "https://vscode.download.prss.microsoft.com/dbazure/download/stable/$HASH/vscode-server-$DETECTED_PLATFORM-$ARCH-web.tar.gz" | tar -xz -C "${INSTALL_PREFIX}" --strip-components 1) -if [ $? -ne 0 ]; then - echo "Failed to install Microsoft Visual Studio Code Server: $output" - exit 1 + if [ $? -ne 0 ]; then + echo "Failed to install Microsoft Visual Studio Code Server: $output" + exit 1 + fi + printf "$${BOLD}VS Code Web has been installed.\n" fi -printf "$${BOLD}VS Code Web has been installed.\n" # Install each extension... IFS=',' read -r -a EXTENSIONLIST <<< "$${EXTENSIONS}"