Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
47 changes: 37 additions & 10 deletions registry/coder/modules/vscode-desktop/README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,63 @@
---
display_name: VS Code Desktop
description: Add a one-click button to launch VS Code Desktop
description: Add a one-click button to launch VS Code Desktop with pre-installed extensions and settings.
icon: ../../../../.icons/code.svg
verified: true
tags: [ide, vscode]
---

# VS Code Desktop

Add a button to open any workspace with a single click.
Add a button to open any workspace with a single click. This module can also pre-install VS Code extensions and apply custom settings for a ready-to-code environment.

Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder).
It uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder).

## Basic Usage

```tf
module "vscode" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vscode-desktop/coder"
version = "1.1.1"
source = "[registry.coder.com/coder/vscode-desktop/coder](https://registry.coder.com/coder/vscode-desktop/coder)"
version = "1.2.0" # Or latest version
agent_id = coder_agent.example.id
}
```

## Examples

### Open in a specific directory

```tf
module "vscode" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vscode-desktop/coder"
version = "1.1.1"
source = "[registry.coder.com/coder/vscode-desktop/coder](https://registry.coder.com/coder/vscode-desktop/coder)"
version = "1.2.0" # Or latest version
agent_id = coder_agent.example.id
folder = "/home/coder/project"
}
```

## Pre-install extensions and apply settings

```tf
module "vscode" {
source = "[registry.coder.com/coder/vscode-desktop/coder](https://registry.coder.com/coder/vscode-desktop/coder)"
version = "1.2.0" # Or latest version
agent_id = coder_agent.example.id
folder = "/home/coder/project"

# A list of extension IDs from the VS Code Marketplace to install on startup.
extensions = [
"ms-python.python",
"golang.go",
"hashicorp.terraform",
"esbenp.prettier-vscode"
]

# A map of settings that will be converted to JSON
# and written to the settings file. Use the jsonencode function for this.
settings = jsonencode({
"editor.fontSize": 14,
"terminal.integrated.fontSize": 12,
"workbench.colorTheme": "Default Dark+",
"editor.formatOnSave": true
})
}
```
44 changes: 43 additions & 1 deletion registry/coder/modules/vscode-desktop/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ describe("vscode-desktop", async () => {
expect(coder_app?.instances[0].attributes.order).toBeNull();
});

// Keep all existing tests...

it("adds folder", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
Expand Down Expand Up @@ -86,4 +88,44 @@ describe("vscode-desktop", async () => {
expect(coder_app?.instances.length).toBe(1);
expect(coder_app?.instances[0].attributes.order).toBe(22);
});
});

// Add this new test case for extensions and settings
it("installs extensions and applies settings", async () => {
const settings = JSON.stringify(
{
"editor.fontSize": 14,
"terminal.integrated.fontSize": 12,
},
null,
2,
);

const extensions = ["ms-python.python", "golang.go"];

await runTerraformApply(import.meta.dir, {
agent_id: "foo",
extensions: extensions,
settings: settings,
});

const checkScript = `
set -e
# The test environment may not have 'code' in the PATH immediately
# so we add the known location.
export PATH="$PATH:/tmp/coder/bin"

# Verify extensions
INSTALLED_EXTENSIONS=$(code --list-extensions)
echo "$INSTALLED_EXTENSIONS" | grep -q "ms-python.python"
echo "$INSTALLED_EXTENSIONS" | grep -q "golang.go"

# Verify settings
cat /home/coder/.vscode-server/data/Machine/settings.json
`;

const result = await executeScriptInContainer(checkScript);
expect(result.exitCode).toBe(0);
// Use JSON.parse to compare objects, ignoring formatting differences.
expect(JSON.parse(result.stdout)).toEqual(JSON.parse(settings));
});
});
61 changes: 60 additions & 1 deletion registry/coder/modules/vscode-desktop/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,68 @@ variable "group" {
default = null
}

# New variable for extensions
variable "extensions" {
type = list(string)
description = "A list of VS Code extension IDs to install."
default = []
}

# New variable for settings
variable "settings" {
type = string
description = "A JSON string of settings to apply to VS Code."
default = ""
}

data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}

# This script will install extensions and apply settings
resource "coder_script" "setup_vscode" {
# Only run if extensions or settings are provided
count = length(var.extensions) > 0 || var.settings != "" ? 1 : 0

agent_id = var.agent_id
display_name = "Setup VS Code"
icon = "/icon/code.svg"
run_on_start = true

script = <<-EOT
#!/bin/bash
set -e

# Wait for code-server to be available
# VS Code Server is installed by the Coder agent, which can take a moment.
for i in {1..30}; do
if command -v code &> /dev/null; then
break
fi
echo "Waiting for 'code' command..."
sleep 1
done
if ! command -v code &> /dev/null; then
echo "'code' command not found after 30s"
exit 1
fi

# Install extensions
%{ for ext in var.extensions ~}
code --install-extension ${ext} --force
%{ endfor ~}

# Apply settings
%{ if var.settings != "" ~}
# Path for settings for remote VS Code Desktop
SETTINGS_DIR="/home/coder/.vscode-server/data/Machine"
mkdir -p "$SETTINGS_DIR"
cat <<'EOF' > "$SETTINGS_DIR/settings.json"
${var.settings}
EOF
%{ endif ~}
EOT
}

resource "coder_app" "vscode" {
agent_id = var.agent_id
external = true
Expand All @@ -67,4 +126,4 @@ resource "coder_app" "vscode" {
output "vscode_url" {
value = coder_app.vscode.url
description = "VS Code Desktop URL."
}
}