From 5b29270deb25396e35cd7f9076315b1976b89a23 Mon Sep 17 00:00:00 2001 From: Harsh panwar Date: Tue, 2 Dec 2025 15:00:56 +0530 Subject: [PATCH 1/7] add support pre-install plugins --- registry/coder/modules/jetbrains/main.tf | 35 ++++++ .../jetbrains/script/install_plugins.sh | 119 ++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 registry/coder/modules/jetbrains/script/install_plugins.sh diff --git a/registry/coder/modules/jetbrains/main.tf b/registry/coder/modules/jetbrains/main.tf index 8f0e0ac72..3b37aeb2b 100644 --- a/registry/coder/modules/jetbrains/main.tf +++ b/registry/coder/modules/jetbrains/main.tf @@ -173,6 +173,13 @@ variable "ide_config" { } } +variable "jetbrains_plugins" { + type = map(list(string)) + description = "Map of IDE product codes to plugin ID lists. Example: { IU = [\"com.foo\"], GO = [\"org.bar\"] }." + default = {} +} + + locals { # Parse HTTP responses once with error handling for air-gapped environments parsed_responses = { @@ -203,6 +210,9 @@ locals { # Convert the parameter value to a set for for_each selected_ides = length(var.default) == 0 ? toset(jsondecode(coalesce(data.coder_parameter.jetbrains_ides[0].value, "[]"))) : toset(var.default) + + + plugin_map_b64 = base64encode(jsonencode(var.jetbrains_plugins)) } data "coder_parameter" "jetbrains_ides" { @@ -230,6 +240,31 @@ data "coder_parameter" "jetbrains_ides" { data "coder_workspace" "me" {} data "coder_workspace_owner" "me" {} +resource "coder_script" "store_plugins" { + agent_id = var.agent_id + display_name = "Store JetBrains Plugins List" + run_on_start = true + script = <<-EOT + #!/bin/sh + set -eu + + mkdir -p "$HOME/.config/jetbrains" + echo -n "${local.plugin_map_b64}" | base64 -d > "$HOME/.config/jetbrains/plugins.json" + chmod 600 "$HOME/.config/jetbrains/plugins.json" + EOT +} + +resource "coder_script" "name" { + agent_id = var.agent_id + display_name = "Install JetBrains Plugins" + run_on_start = true + + script = <<-EOT + + ${file("${path.module}/script/install_plugins.sh")} + EOT +} + resource "coder_app" "jetbrains" { for_each = local.selected_ides agent_id = var.agent_id diff --git a/registry/coder/modules/jetbrains/script/install_plugins.sh b/registry/coder/modules/jetbrains/script/install_plugins.sh new file mode 100644 index 000000000..451801f89 --- /dev/null +++ b/registry/coder/modules/jetbrains/script/install_plugins.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash +set -euo pipefail + +LOGFILE="$HOME/.config/jetbrains/install_plugins.log" +TOOLBOX_BASE="$HOME/.local/share/JetBrains/Toolbox/apps" +PLUGIN_MAP_FILE="$HOME/.config/jetbrains/plugins.json" + +sudo apt-get update +sudo apt-get install -y libfreetype6 + + +mkdir -p "$(dirname "$LOGFILE")" + +exec > >(tee -a "$LOGFILE") 2>&1 + +log() { + printf '%s %s\n' "$(date --iso-8601=seconds)" "$*" | tee -a "$LOGFILE" +} + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + + +# -------- Read plugin JSON -------- +get_plugins_for_code() { + local code="$1" + jq -r --arg CODE "$code" '.[$CODE][]?' "$PLUGIN_MAP_FILE" 2>/dev/null || true +} + +# -------- Product code matching from folder name -------- +map_folder_to_code() { + local folder="$1" + case "$folder" in + *pycharm*) echo "PY" ;; + *idea*) echo "IU" ;; + *webstorm*) echo "WS" ;; + *goland*) echo "GO" ;; + *clion*) echo "CL" ;; + *phpstorm*) echo "PS" ;; + *rider*) echo "RD" ;; + *rubymine*) echo "RM" ;; + *rustrover*) echo "RR" ;; + *) echo "" ;; + esac +} + +# -------- Correct launcher per product -------- +launcher_for_code() { + case "$1" in + PY) echo "pycharm" ;; + IU) echo "idea" ;; + WS) echo "webstorm" ;; + GO) echo "goland" ;; + CL) echo "clion" ;; + PS) echo "phpstorm" ;; + RD) echo "rider" ;; + RM) echo "rubymine" ;; + RR) echo "rustrover" ;; + *) return 1 ;; + esac +} + +find_cli_launcher() { + local code="$1" + local product_root="$2" + + local exe + exe="$(launcher_for_code "$code")" || return 1 + + if [ -f "$product_root/bin/$exe" ]; then + echo "$product_root/bin/$exe" + else + return 1 + fi +} + +install_plugin() { + local launcher="$1" + local plugin="$2" + log "Installing plugin $plugin" + "$launcher" installPlugins "$plugin" +} + +# -------- Main logic -------- +log "Plugin installer started" + +if [ ! -f "$PLUGIN_MAP_FILE" ]; then + log "No plugin map file found. Exiting." + exit 0 +fi + +for product_dir in "$TOOLBOX_BASE"/*; do + [ -d "$product_dir" ] || continue + + product_name="$(basename "$product_dir")" + code="$(map_folder_to_code "$product_name")" + [ -n "$code" ] || continue + + cli_launcher="$(find_cli_launcher "$code" "$product_dir")" + if [ -z "$cli_launcher" ]; then + log "No CLI launcher found for code $code" + continue + fi + + plugins="$(get_plugins_for_code "$code")" + if [ -z "$plugins" ]; then + log "No plugins for $code" + continue + fi + + while read -r plugin; do + echo "$cli_launcher and $plugin" + install_plugin "$cli_launcher" "$plugin" + done <<< "$plugins" + +done + +log "Plugin installer finished" From b7df74c29c1dcd551e8b4bd564aa666386862743 Mon Sep 17 00:00:00 2001 From: Harsh panwar Date: Wed, 3 Dec 2025 14:22:16 +0530 Subject: [PATCH 2/7] enhance the script --- bun.lock | 1 + .../jetbrains/script/install_plugins.sh | 128 ++++++++++-------- 2 files changed, 75 insertions(+), 54 deletions(-) diff --git a/bun.lock b/bun.lock index 7fcb771f2..1b013ef29 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "registry", diff --git a/registry/coder/modules/jetbrains/script/install_plugins.sh b/registry/coder/modules/jetbrains/script/install_plugins.sh index 451801f89..6f7387714 100644 --- a/registry/coder/modules/jetbrains/script/install_plugins.sh +++ b/registry/coder/modules/jetbrains/script/install_plugins.sh @@ -8,7 +8,6 @@ PLUGIN_MAP_FILE="$HOME/.config/jetbrains/plugins.json" sudo apt-get update sudo apt-get install -y libfreetype6 - mkdir -p "$(dirname "$LOGFILE")" exec > >(tee -a "$LOGFILE") 2>&1 @@ -17,35 +16,32 @@ log() { printf '%s %s\n' "$(date --iso-8601=seconds)" "$*" | tee -a "$LOGFILE" } -command_exists() { - command -v "$1" >/dev/null 2>&1 +# -------- Read plugin JSON -------- +get_enabled_codes() { + jq -r 'keys[]' "$PLUGIN_MAP_FILE" } - -# -------- Read plugin JSON -------- get_plugins_for_code() { - local code="$1" - jq -r --arg CODE "$code" '.[$CODE][]?' "$PLUGIN_MAP_FILE" 2>/dev/null || true + jq -r --arg CODE "$1" '.[$CODE][]?' "$PLUGIN_MAP_FILE" 2> /dev/null || true } -# -------- Product code matching from folder name -------- +# -------- Product code mapping -------- map_folder_to_code() { - local folder="$1" - case "$folder" in - *pycharm*) echo "PY" ;; - *idea*) echo "IU" ;; - *webstorm*) echo "WS" ;; - *goland*) echo "GO" ;; - *clion*) echo "CL" ;; - *phpstorm*) echo "PS" ;; - *rider*) echo "RD" ;; - *rubymine*) echo "RM" ;; - *rustrover*) echo "RR" ;; - *) echo "" ;; + case "$1" in + *pycharm*) echo "PY" ;; + *idea*) echo "IU" ;; + *webstorm*) echo "WS" ;; + *goland*) echo "GO" ;; + *clion*) echo "CL" ;; + *phpstorm*) echo "PS" ;; + *rider*) echo "RD" ;; + *rubymine*) echo "RM" ;; + *rustrover*) echo "RR" ;; + *) echo "" ;; esac } -# -------- Correct launcher per product -------- +# -------- CLI launcher names -------- launcher_for_code() { case "$1" in PY) echo "pycharm" ;; @@ -57,63 +53,87 @@ launcher_for_code() { RD) echo "rider" ;; RM) echo "rubymine" ;; RR) echo "rustrover" ;; - *) return 1 ;; + *) return 1 ;; esac } find_cli_launcher() { - local code="$1" - local product_root="$2" - local exe - exe="$(launcher_for_code "$code")" || return 1 + exe="$(launcher_for_code "$1")" || return 1 - if [ -f "$product_root/bin/$exe" ]; then - echo "$product_root/bin/$exe" + if [ -f "$2/bin/$exe" ]; then + echo "$2/bin/$exe" else return 1 fi } install_plugin() { - local launcher="$1" - local plugin="$2" - log "Installing plugin $plugin" - "$launcher" installPlugins "$plugin" + log "Installing plugin: $2" + "$1" installPlugins "$2" } -# -------- Main logic -------- +# -------- Main -------- log "Plugin installer started" if [ ! -f "$PLUGIN_MAP_FILE" ]; then - log "No plugin map file found. Exiting." + log "No plugins.json found. Exiting." exit 0 fi -for product_dir in "$TOOLBOX_BASE"/*; do - [ -d "$product_dir" ] || continue +# Load list of IDE codes user actually needs +mapfile -t pending_codes < <(get_enabled_codes) - product_name="$(basename "$product_dir")" - code="$(map_folder_to_code "$product_name")" - [ -n "$code" ] || continue +if [ ${#pending_codes[@]} -eq 0 ]; then + log "No plugin entries found. Exiting." + exit 0 +fi - cli_launcher="$(find_cli_launcher "$code" "$product_dir")" - if [ -z "$cli_launcher" ]; then - log "No CLI launcher found for code $code" - continue - fi +log "Waiting for IDE installation. Pending codes: ${pending_codes[*]}" - plugins="$(get_plugins_for_code "$code")" - if [ -z "$plugins" ]; then - log "No plugins for $code" - continue - fi +# Loop until all plugins installed +while [ ${#pending_codes[@]} -gt 0 ]; do - while read -r plugin; do - echo "$cli_launcher and $plugin" - install_plugin "$cli_launcher" "$plugin" - done <<< "$plugins" + for product_dir in "$TOOLBOX_BASE"/*; do + [ -d "$product_dir" ] || continue + product_name="$(basename "$product_dir")" + code="$(map_folder_to_code "$product_name")" + + # Only process codes user requested + if [[ ! " ${pending_codes[*]} " =~ " $code " ]]; then + continue + fi + + cli_launcher="$(find_cli_launcher "$code" "$product_dir")" || continue + + log "Detected IDE $code at $product_dir" + + plugins="$(get_plugins_for_code "$code")" + if [ -z "$plugins" ]; then + log "No plugins for $code" + continue + fi + + while read -r plugin; do + install_plugin "$cli_launcher" "$plugin" + done <<< "$plugins" + + # remove code from pending list after success + tmp=() + for c in "${pending_codes[@]}"; do + [ "$c" != "$code" ] && tmp+=("$c") + done + pending_codes=("${tmp[@]}") + + log "Finished $code. Remaining: ${pending_codes[*]:-none}" + + done + + # If still pending, wait and retry + if [ ${#pending_codes[@]} -gt 0 ]; then + sleep 10 + fi done -log "Plugin installer finished" +log "All plugins installed. Exiting." From 2b616fca3dd0871f0b8dfd2727ce019d01d2c5a1 Mon Sep 17 00:00:00 2001 From: Harsh panwar Date: Wed, 3 Dec 2025 18:43:59 +0530 Subject: [PATCH 3/7] fix the style issue --- registry/coder/modules/jetbrains/main.tf | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/registry/coder/modules/jetbrains/main.tf b/registry/coder/modules/jetbrains/main.tf index ff62276c7..1b1ce14a9 100644 --- a/registry/coder/modules/jetbrains/main.tf +++ b/registry/coder/modules/jetbrains/main.tf @@ -174,9 +174,9 @@ variable "ide_config" { } variable "jetbrains_plugins" { - type = map(list(string)) + type = map(list(string)) description = "Map of IDE product codes to plugin ID lists. Example: { IU = [\"com.foo\"], GO = [\"org.bar\"] }." - default = {} + default = {} } @@ -211,7 +211,6 @@ locals { # Convert the parameter value to a set for for_each selected_ides = length(var.default) == 0 ? toset(jsondecode(coalesce(data.coder_parameter.jetbrains_ides[0].value, "[]"))) : toset(var.default) - plugin_map_b64 = base64encode(jsonencode(var.jetbrains_plugins)) } @@ -244,7 +243,7 @@ resource "coder_script" "store_plugins" { agent_id = var.agent_id display_name = "Store JetBrains Plugins List" run_on_start = true - script = <<-EOT + script = <<-EOT #!/bin/sh set -eu @@ -254,8 +253,8 @@ resource "coder_script" "store_plugins" { EOT } -resource "coder_script" "name" { - agent_id = var.agent_id +resource "coder_script" "install_jetbrains_plugins" { + agent_id = var.agent_id display_name = "Install JetBrains Plugins" run_on_start = true From 8c98af62c11a719d0520a00b693917ecd4f9bfb1 Mon Sep 17 00:00:00 2001 From: Harsh panwar Date: Wed, 3 Dec 2025 19:02:36 +0530 Subject: [PATCH 4/7] add the example in readme --- registry/coder/modules/jetbrains/README.md | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/registry/coder/modules/jetbrains/README.md b/registry/coder/modules/jetbrains/README.md index 718613599..dc4bf49ee 100644 --- a/registry/coder/modules/jetbrains/README.md +++ b/registry/coder/modules/jetbrains/README.md @@ -137,6 +137,34 @@ module "jetbrains" { } ``` +### Plugin Auto‑Installer + +This module now supports automatic JetBrains plugin installation inside your workspace. + +To get a plugin ID, open the plugin’s page on the JetBrains Marketplace. Scroll down to Additional Information and look for Plugin ID. Use that value in the configuration below. + +```tf +module "jetbrains" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/jetbrains/coder" + version = "1.2.1" + agent_id = coder_agent.main.id + folder = "/home/coder/project" + default = ["IU", "PY"] + jetbrains_plugins = { + "PY" = ["com.koxudaxi.pydantic","com.intellij.kubernetes"] + "IU" = ["",""] + "WS" = ["",""] + "GO" = ["",""] + "CL" = ["",""] + "PS" = ["",""] + "RD" = ["",""] + "RM" = ["",""] + "RR" = ["",""] + } +} +``` + ### Accessing the IDE Metadata You can now reference the output `ide_metadata` as a map. From 3b6c743915799f43999b84ee3d9816aae19556f2 Mon Sep 17 00:00:00 2001 From: Harsh panwar Date: Wed, 3 Dec 2025 19:06:47 +0530 Subject: [PATCH 5/7] fix the style issue --- registry/coder/modules/jetbrains/README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/registry/coder/modules/jetbrains/README.md b/registry/coder/modules/jetbrains/README.md index dc4bf49ee..4042103b2 100644 --- a/registry/coder/modules/jetbrains/README.md +++ b/registry/coder/modules/jetbrains/README.md @@ -151,16 +151,17 @@ module "jetbrains" { agent_id = coder_agent.main.id folder = "/home/coder/project" default = ["IU", "PY"] + jetbrains_plugins = { - "PY" = ["com.koxudaxi.pydantic","com.intellij.kubernetes"] - "IU" = ["",""] - "WS" = ["",""] - "GO" = ["",""] - "CL" = ["",""] - "PS" = ["",""] - "RD" = ["",""] - "RM" = ["",""] - "RR" = ["",""] + "PY" = ["com.koxudaxi.pydantic", "com.intellij.kubernetes"] + "IU" = ["", ""] + "WS" = ["", ""] + "GO" = ["", ""] + "CL" = ["", ""] + "PS" = ["", ""] + "RD" = ["", ""] + "RM" = ["", ""] + "RR" = ["", ""] } } ``` From c261779e52ee11a2e4ca083d6ec7f6624c866eec Mon Sep 17 00:00:00 2001 From: Harsh panwar Date: Wed, 3 Dec 2025 20:22:56 +0530 Subject: [PATCH 6/7] add ai suggestions --- registry/coder/modules/jetbrains/README.md | 6 +++ registry/coder/modules/jetbrains/main.tf | 4 +- .../jetbrains/script/install_plugins.sh | 40 ++++++++++++++++--- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/registry/coder/modules/jetbrains/README.md b/registry/coder/modules/jetbrains/README.md index 4042103b2..3a2f71f57 100644 --- a/registry/coder/modules/jetbrains/README.md +++ b/registry/coder/modules/jetbrains/README.md @@ -165,6 +165,12 @@ module "jetbrains" { } } ``` +> [!IMPORTANT]\ +> This module prerequisites and limitations +> 1. Requires JetBrains Toolbox to be installed +> 2. Requires jq to be available +> 3. Only works on Debian/Ubuntu-based systems (due to apt-get usage) +> 4. Plugins are installed when workspace starts, but may take time depending on IDE availability ### Accessing the IDE Metadata diff --git a/registry/coder/modules/jetbrains/main.tf b/registry/coder/modules/jetbrains/main.tf index 1b1ce14a9..52cc6bdd1 100644 --- a/registry/coder/modules/jetbrains/main.tf +++ b/registry/coder/modules/jetbrains/main.tf @@ -240,6 +240,7 @@ data "coder_workspace" "me" {} data "coder_workspace_owner" "me" {} resource "coder_script" "store_plugins" { + count = length(var.jetbrains_plugins) > 0 ? 1 : 0 agent_id = var.agent_id display_name = "Store JetBrains Plugins List" run_on_start = true @@ -254,12 +255,13 @@ resource "coder_script" "store_plugins" { } resource "coder_script" "install_jetbrains_plugins" { + count = length(var.jetbrains_plugins) > 0 ? 1 : 0 agent_id = var.agent_id display_name = "Install JetBrains Plugins" run_on_start = true + depends_on = [coder_script.store_plugins] script = <<-EOT - ${file("${path.module}/script/install_plugins.sh")} EOT } diff --git a/registry/coder/modules/jetbrains/script/install_plugins.sh b/registry/coder/modules/jetbrains/script/install_plugins.sh index 6f7387714..c3bb3f2be 100644 --- a/registry/coder/modules/jetbrains/script/install_plugins.sh +++ b/registry/coder/modules/jetbrains/script/install_plugins.sh @@ -5,8 +5,12 @@ LOGFILE="$HOME/.config/jetbrains/install_plugins.log" TOOLBOX_BASE="$HOME/.local/share/JetBrains/Toolbox/apps" PLUGIN_MAP_FILE="$HOME/.config/jetbrains/plugins.json" -sudo apt-get update -sudo apt-get install -y libfreetype6 +if command -v apt-get > /dev/null 2>&1; then + sudo apt-get update + sudo apt-get install -y libfreetype6 +else + echo "Warning: 'apt-get' not found. Please ensure 'libfreetype6' is installed manually for your distribution." >&2 +fi mkdir -p "$(dirname "$LOGFILE")" @@ -61,8 +65,12 @@ find_cli_launcher() { local exe exe="$(launcher_for_code "$1")" || return 1 - if [ -f "$2/bin/$exe" ]; then - echo "$2/bin/$exe" + # Look for the newest version directory + local latest_version + latest_version=$(find "$2" -maxdepth 2 -type d -name "ch-*" 2> /dev/null | sort -V | tail -1) + + if [ -n "$latest_version" ] && [ -f "$latest_version/bin/$exe" ]; then + echo "$latest_version/bin/$exe" else return 1 fi @@ -70,7 +78,12 @@ find_cli_launcher() { install_plugin() { log "Installing plugin: $2" - "$1" installPlugins "$2" + if "$1" installPlugins "$2"; then + log "Successfully installed plugin: $2" + else + log "Failed to install plugin: $2" + return 1 + fi } # -------- Main -------- @@ -91,8 +104,17 @@ fi log "Waiting for IDE installation. Pending codes: ${pending_codes[*]}" +MAX_ATTEMPTS=60 # 10 minutes +attempt=0 + # Loop until all plugins installed -while [ ${#pending_codes[@]} -gt 0 ]; do +while [ ${#pending_codes[@]} -gt 0 ] && [ $attempt -lt $MAX_ATTEMPTS ]; do + + if [ ! -d "$TOOLBOX_BASE" ]; then + log "Toolbox directory not found yet, waiting..." + sleep 10 + continue + fi for product_dir in "$TOOLBOX_BASE"/*; do [ -d "$product_dir" ] || continue @@ -133,7 +155,13 @@ while [ ${#pending_codes[@]} -gt 0 ]; do # If still pending, wait and retry if [ ${#pending_codes[@]} -gt 0 ]; then sleep 10 + ((attempt++)) fi done +if [ ${#pending_codes[@]} -gt 0 ]; then + log "Timeout: IDEs not found: ${pending_codes[*]}" + exit 1 +fi + log "All plugins installed. Exiting." From c6ae73615ab783d9ecd8b88ffb0bdb8c39ea2b02 Mon Sep 17 00:00:00 2001 From: Harsh panwar Date: Wed, 3 Dec 2025 20:26:04 +0530 Subject: [PATCH 7/7] fix style issue --- registry/coder/modules/jetbrains/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/registry/coder/modules/jetbrains/README.md b/registry/coder/modules/jetbrains/README.md index 3a2f71f57..eb0316264 100644 --- a/registry/coder/modules/jetbrains/README.md +++ b/registry/coder/modules/jetbrains/README.md @@ -165,8 +165,10 @@ module "jetbrains" { } } ``` + > [!IMPORTANT]\ > This module prerequisites and limitations +> > 1. Requires JetBrains Toolbox to be installed > 2. Requires jq to be available > 3. Only works on Debian/Ubuntu-based systems (due to apt-get usage)