diff --git a/registry/coder/modules/code-server/README.md b/registry/coder/modules/code-server/README.md index 0589ec3d4..07758fdc7 100644 --- a/registry/coder/modules/code-server/README.md +++ b/registry/coder/modules/code-server/README.md @@ -14,7 +14,7 @@ Automatically install [code-server](https://github.com/coder/code-server) in a w module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.4" + version = "1.5.0" agent_id = coder_agent.example.id } ``` @@ -29,7 +29,7 @@ module "code-server" { module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.4" + version = "1.5.0" agent_id = coder_agent.example.id install_version = "4.106.3" } @@ -43,7 +43,7 @@ Install the Dracula theme from [OpenVSX](https://open-vsx.org/): module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.4" + version = "1.5.0" agent_id = coder_agent.example.id extensions = [ "dracula-theme.theme-dracula" @@ -61,7 +61,7 @@ Configure VS Code's [settings.json](https://code.visualstudio.com/docs/getstarte module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.4" + version = "1.5.0" agent_id = coder_agent.example.id extensions = ["dracula-theme.theme-dracula"] settings = { @@ -78,12 +78,26 @@ Install multiple extensions from [OpenVSX](https://open-vsx.org/) by adding them module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.4" + version = "1.5.0" agent_id = coder_agent.example.id extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"] } ``` +### Open a Workspace File + +Open a [`.code-workspace`](https://coder.com/docs/code-server/FAQ#how-does-code-server-decide-what-workspace-or-folder-to-open) file instead of a folder. `folder` and `workspace` are mutually exclusive. + +```tf +module "code-server" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/code-server/coder" + version = "1.5.0" + agent_id = coder_agent.example.id + workspace = "/home/coder/project/my.code-workspace" +} +``` + ### Pass Additional Arguments You can pass additional command-line arguments to code-server using the `additional_args` variable. For example, to disable workspace trust: @@ -92,7 +106,7 @@ You can pass additional command-line arguments to code-server using the `additio module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.4" + version = "1.5.0" agent_id = coder_agent.example.id additional_args = "--disable-workspace-trust" } @@ -108,7 +122,7 @@ Run an existing copy of code-server if found, otherwise download from GitHub: module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.4" + version = "1.5.0" agent_id = coder_agent.example.id use_cached = true extensions = ["dracula-theme.theme-dracula", "ms-azuretools.vscode-docker"] @@ -121,7 +135,7 @@ Just run code-server in the background, don't fetch it from GitHub: module "code-server" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/code-server/coder" - version = "1.4.4" + version = "1.5.0" agent_id = coder_agent.example.id offline = true } diff --git a/registry/coder/modules/code-server/code-server.tftest.hcl b/registry/coder/modules/code-server/code-server.tftest.hcl index ebbb71755..209a0f39d 100644 --- a/registry/coder/modules/code-server/code-server.tftest.hcl +++ b/registry/coder/modules/code-server/code-server.tftest.hcl @@ -48,3 +48,55 @@ run "url_with_folder_query" { error_message = "coder_app URL must include encoded folder query param" } } + +run "url_with_workspace_query" { + command = plan + + variables { + agent_id = "foo" + workspace = "/home/coder/project/my.code-workspace" + port = 13337 + } + + assert { + condition = resource.coder_app.code-server.url == "http://localhost:13337/?workspace=%2Fhome%2Fcoder%2Fproject%2Fmy.code-workspace" + error_message = "coder_app URL must include encoded workspace query param" + } +} + +run "url_with_no_target" { + command = plan + + variables { + agent_id = "foo" + port = 13337 + } + + assert { + condition = resource.coder_app.code-server.url == "http://localhost:13337/" + error_message = "coder_app URL must omit query string when neither folder nor workspace is set" + } +} + +run "folder_and_workspace_conflict" { + command = plan + + variables { + agent_id = "foo" + folder = "/home/coder/project" + workspace = "/home/coder/project/my.code-workspace" + } + + expect_failures = [ + var.workspace + ] +} + +run "workspace_extension_rejected" { + command = plan + variables { + agent_id = "foo" + workspace = "/home/coder/project/settings.json" + } + expect_failures = [var.workspace] +} diff --git a/registry/coder/modules/code-server/main.tf b/registry/coder/modules/code-server/main.tf index 090b6a53a..a0cd9c0f3 100644 --- a/registry/coder/modules/code-server/main.tf +++ b/registry/coder/modules/code-server/main.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.9" required_providers { coder = { @@ -56,6 +56,19 @@ variable "folder" { default = "" } +variable "workspace" { + type = string + description = "The path to a `.code-workspace` file to open in code-server. Mutually exclusive with `folder`." + default = "" + validation { + condition = var.workspace == "" || endswith(var.workspace, ".code-workspace") + error_message = "workspace must be a path to a .code-workspace file" + } + validation { + condition = var.folder == "" || var.workspace == "" + error_message = "folder and workspace are mutually exclusive; set at most one" + } +} variable "install_prefix" { type = string description = "The prefix to install code-server to." @@ -173,6 +186,7 @@ resource "coder_script" "code-server" { USE_CACHED_EXTENSIONS : var.use_cached_extensions, EXTENSIONS_DIR : var.extensions_dir, FOLDER : var.folder, + WORKSPACE : var.workspace, AUTO_INSTALL_EXTENSIONS : var.auto_install_extensions, ADDITIONAL_ARGS : var.additional_args, }) @@ -195,7 +209,7 @@ resource "coder_app" "code-server" { agent_id = var.agent_id slug = var.slug display_name = var.display_name - url = "http://localhost:${var.port}/${var.folder != "" ? "?folder=${urlencode(var.folder)}" : ""}" + url = "http://localhost:${var.port}/${var.folder != "" ? "?folder=${urlencode(var.folder)}" : var.workspace != "" ? "?workspace=${urlencode(var.workspace)}" : ""}" icon = "/icon/code.svg" subdomain = var.subdomain share = var.share diff --git a/registry/coder/modules/code-server/run.sh b/registry/coder/modules/code-server/run.sh index 33a6972a6..5af5a0046 100644 --- a/registry/coder/modules/code-server/run.sh +++ b/registry/coder/modules/code-server/run.sh @@ -122,15 +122,29 @@ if [ "${AUTO_INSTALL_EXTENSIONS}" = true ]; then exit 0 fi - WORKSPACE_DIR="$HOME" - if [ -n "${FOLDER}" ]; then - WORKSPACE_DIR="${FOLDER}" + RECOMMENDATIONS_FILE="" + RECOMMENDATIONS_QUERY=".recommendations[]" + if [ -n "${WORKSPACE}" ]; then + if [ -f "${WORKSPACE}" ]; then + RECOMMENDATIONS_FILE="${WORKSPACE}" + RECOMMENDATIONS_QUERY=".extensions.recommendations[]?" + else + echo "⚠️ Workspace file ${WORKSPACE} not found, skipping extension recommendations." + fi + else + WORKSPACE_DIR="$HOME" + if [ -n "${FOLDER}" ]; then + WORKSPACE_DIR="${FOLDER}" + fi + if [ -f "$WORKSPACE_DIR/.vscode/extensions.json" ]; then + RECOMMENDATIONS_FILE="$WORKSPACE_DIR/.vscode/extensions.json" + fi fi - if [ -f "$WORKSPACE_DIR/.vscode/extensions.json" ]; then - printf "🧩 Installing extensions from %s/.vscode/extensions.json...\n" "$WORKSPACE_DIR" + if [ -n "$RECOMMENDATIONS_FILE" ]; then + printf "🧩 Installing extensions from %s...\n" "$RECOMMENDATIONS_FILE" # Use sed to remove single-line comments before parsing with jq - extensions=$(sed 's|//.*||g' "$WORKSPACE_DIR"/.vscode/extensions.json | jq -r '.recommendations[]') + extensions=$(sed 's|//.*||g' "$RECOMMENDATIONS_FILE" | jq -r "$RECOMMENDATIONS_QUERY") for extension in $extensions; do if extension_installed "$extension"; then continue