-
Notifications
You must be signed in to change notification settings - Fork 79
add support pre-install plugins #571
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 8 commits
5b29270
429b629
b7df74c
408eaee
2b616fc
a95f904
8c98af6
3b6c743
c261779
c6ae736
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "lockfileVersion": 1, | ||
| "configVersion": 0, | ||
| "workspaces": { | ||
| "": { | ||
| "name": "registry", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -137,6 +137,35 @@ 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" = ["<Plugin-ID>", "<Plugin-ID>"] | ||
| "WS" = ["<Plugin-ID>", "<Plugin-ID>"] | ||
| "GO" = ["<Plugin-ID>", "<Plugin-ID>"] | ||
| "CL" = ["<Plugin-ID>", "<Plugin-ID>"] | ||
| "PS" = ["<Plugin-ID>", "<Plugin-ID>"] | ||
| "RD" = ["<Plugin-ID>", "<Plugin-ID>"] | ||
| "RM" = ["<Plugin-ID>", "<Plugin-ID>"] | ||
| "RR" = ["<Plugin-ID>", "<Plugin-ID>"] | ||
| } | ||
| } | ||
|
Comment on lines
+155
to
+166
|
||
| ``` | ||
|
|
||
| ### Accessing the IDE Metadata | ||
|
|
||
| You can now reference the output `ide_metadata` as a map. | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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\"] }." | ||||||
|
||||||
| description = "Map of IDE product codes to plugin ID lists. Example: { IU = [\"com.foo\"], GO = [\"org.bar\"] }." | |
| description = "Map of JetBrains IDE product codes to plugin ID lists. Valid codes: CL (CLion), GO (GoLand), IU (IntelliJ IDEA Ultimate), PS (PhpStorm), PY (PyCharm), RD (Rider), RM (RubyMine), RR (ReSharper), WS (WebStorm). Example: { IU = [\"com.foo\"], GO = [\"org.bar\"] }. Find plugin IDs at https://plugins.jetbrains.com/." |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The store_plugins script always runs, even when jetbrains_plugins is empty (default {}). This creates an empty JSON file unnecessarily. Consider adding a condition to only create these resources when plugins are actually configured:
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
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
}Apply the same pattern to coder_script.install_jetbrains_plugins.
Outdated
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an unnecessary blank line at the beginning of the heredoc. This will be included in the script output. Consider removing it:
script = <<-EOT
${file("${path.module}/script/install_plugins.sh")}
EOT
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The install_jetbrains_plugins script depends on the plugins.json file created by store_plugins, but there's no explicit dependency between these resources. While both have run_on_start = true, Terraform doesn't guarantee execution order without an explicit dependency. Add a depends_on to ensure proper ordering:
resource "coder_script" "install_jetbrains_plugins" {
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
}| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,139 @@ | ||||||||||||||||||||||
| #!/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 | ||||||||||||||||||||||
|
||||||||||||||||||||||
| sudo apt-get install -y libfreetype6 | |
| sudo apt-get install -y libfreetype6 jq |
Outdated
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running apt-get update and apt-get install with sudo assumes the script runs in a Debian/Ubuntu environment with sudo privileges. This may not work on other distributions (e.g., Alpine, Fedora) or systems without sudo access. Consider adding a check for the package manager or documenting this requirement in the module's README.
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make folder-to-code mapping case-insensitive
The folder mapping uses lowercase globs (*pycharm*, *idea*, etc.), but JetBrains Toolbox installs create uppercase product directories (e.g., IDEA-U, PyCharm-P) on Linux. Because Bash pattern matching is case-sensitive, these branches never match, leaving code empty, so the main loop never processes the detected IDEs and the installer spins forever without installing plugins. Normalizing the folder name or enabling case-insensitive matching is needed for Toolbox layouts.
Useful? React with 👍 / 👎.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Search JetBrains CLI inside channel/build directories
find_cli_launcher currently looks only for $product_dir/bin/<launcher> under ~/.local/share/JetBrains/Toolbox/apps, but Toolbox installs place binaries under channel/build folders such as <product>/ch-0/<build>/bin/idea.sh. For any normal install this check always fails, so cli_launcher stays empty, pending_codes is never reduced, and the installer loops forever without installing plugins. The search needs to descend into the channel/build subdirectories to locate the CLI.
Useful? React with 👍 / 👎.
Outdated
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The install_plugin function doesn't check if the plugin installation succeeds. If the IDE CLI command fails (e.g., invalid plugin ID, network issues, or CLI not supporting installPlugins), the script continues without error. Consider capturing the exit status and logging failures:
install_plugin() {
log "Installing plugin: $2"
if "$1" installPlugins "$2"; then
log "Successfully installed plugin: $2"
else
log "Failed to install plugin: $2"
return 1
fi
}| "$1" installPlugins "$2" | |
| if "$1" installPlugins "$2"; then | |
| log "Successfully installed plugin: $2" | |
| else | |
| log "Failed to install plugin: $2" | |
| return 1 | |
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filter plugins to selected IDEs before waiting
pending_codes is populated from every key in plugins.json, regardless of which IDEs were actually selected or installed. If a user supplies plugin lists for more products than they enable (e.g., the README example lists all codes while default = ["IU", "PY"]), the while loop never clears the extra entries and sleeps forever, so the script never finishes. pending_codes should be intersected with the selected/installed IDE set before entering the loop to avoid hanging.
Useful? React with 👍 / 👎.
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The glob pattern "$TOOLBOX_BASE"/* will match the literal string if the directory doesn't exist or is empty. This could lead to unexpected behavior. Consider checking if the directory exists first:
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
# ... rest of logic
done| if [ ! -d "$TOOLBOX_BASE" ]; then | |
| log "Toolbox directory not found yet, waiting..." | |
| sleep 10 | |
| continue | |
| fi |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The script looks for the CLI launcher in $product_dir/bin/$exe, but this path might not match the actual Toolbox installation structure. JetBrains Toolbox typically installs IDEs in versioned subdirectories like ~/.local/share/JetBrains/Toolbox/apps/PyCharm-P/ch-0/242.23726.102/bin/pycharm. The script needs to find the correct version directory. Consider:
find_cli_launcher() {
local exe
exe="$(launcher_for_code "$1")" || return 1
# 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
}
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The infinite while loop continues polling every 10 seconds even if no IDEs will ever be installed. If an IDE in jetbrains_plugins is never installed via Toolbox, this script will run indefinitely. Consider adding:
- A maximum retry count or timeout
- A way to skip codes that will never be available (e.g., if user only installs a subset of requested IDEs)
Example:
MAX_ATTEMPTS=60 # 10 minutes
attempt=0
while [ ${#pending_codes[@]} -gt 0 ] && [ $attempt -lt $MAX_ATTEMPTS ]; do
# ... existing loop logic ...
if [ ${#pending_codes[@]} -gt 0 ]; then
sleep 10
((attempt++))
fi
done
if [ ${#pending_codes[@]} -gt 0 ]; then
log "Timeout: IDEs not found: ${pending_codes[*]}"
fi
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The section title uses a non-breaking hyphen character (U+2011) instead of a standard hyphen. While this may render correctly in most contexts, it could cause issues with some text editors or search functionality. Consider using a standard hyphen:
### Plugin Auto-Installer