-
Notifications
You must be signed in to change notification settings - Fork 80
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?
Conversation
|
@Harsh9485 You will need to run |
|
I’ll do that, but if you like the idea, I’ll push the full PR. I’ll update the README and improve the script. Let me know if you want anything changed. |
…registry into Pre-install-JetBrains-plugins
|
hey @DevelopmentCats @matifali, can you review the PR? |
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.
Pull request overview
This PR adds support for automatic JetBrains plugin installation by detecting installed IDEs via JetBrains Toolbox and using each IDE's CLI to install user-specified plugins. The feature introduces a new jetbrains_plugins variable that maps IDE product codes to lists of plugin IDs, creating two coder_script resources: one to store the plugin configuration and another to execute the installation script.
Key Changes:
- New
jetbrains_pluginsvariable for specifying plugins per IDE - Bash script that polls for IDE installation and installs plugins via CLI
- Two coder_script resources for storing configuration and running installation
- Documentation with usage examples
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 13 comments.
| File | Description |
|---|---|
| registry/coder/modules/jetbrains/script/install_plugins.sh | New bash script that waits for Toolbox IDEs to install, then uses each IDE's CLI to install specified plugins |
| registry/coder/modules/jetbrains/main.tf | Adds jetbrains_plugins variable and two coder_script resources to store plugin config and run installation |
| registry/coder/modules/jetbrains/README.md | Documents the new plugin auto-installer feature with examples and instructions |
| bun.lock | Automatic lockfile update adding configVersion field |
| run_on_start = true | ||
|
|
||
| script = <<-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.
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|
|
||
| variable "jetbrains_plugins" { | ||
| type = map(list(string)) | ||
| description = "Map of IDE product codes to plugin ID lists. Example: { IU = [\"com.foo\"], GO = [\"org.bar\"] }." |
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 variable description should clarify what valid product codes are and provide a reference. Consider improving the description:
variable "jetbrains_plugins" {
type = map(list(string))
description = "Map of IDE product codes to plugin ID lists. Valid codes: CL, GO, IU, PS, PY, RD, RM, RR, WS. Example: { IU = [\"com.foo.bar\"], PY = [\"org.example.plugin\"] }. Find plugin IDs at https://plugins.jetbrains.com/"
default = {}
}| 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/." |
| } | ||
| ``` | ||
|
|
||
| ### Plugin Auto‑Installer |
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 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| ### Plugin Auto‑Installer | |
| ### Plugin Auto-Installer |
| module "jetbrains" { | ||
| count = data.coder_workspace.me.start_count | ||
| source = "registry.coder.com/coder/jetbrains/coder" | ||
| version = "1.2.1" |
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 version in the example should match the actual module version being released. The PR metadata indicates this is for version v1.1.0, but the example shows version = "1.2.1". Update to the correct version or use a placeholder that clearly indicates users should check for the latest version.
| # Loop until all plugins installed | ||
| while [ ${#pending_codes[@]} -gt 0 ]; do | ||
|
|
||
| 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 |
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| resource "coder_script" "install_jetbrains_plugins" { | ||
| agent_id = var.agent_id | ||
| display_name = "Install JetBrains Plugins" | ||
| run_on_start = true | ||
|
|
||
| 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
}| PLUGIN_MAP_FILE="$HOME/.config/jetbrains/plugins.json" | ||
|
|
||
| sudo apt-get update | ||
| sudo apt-get install -y libfreetype6 |
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 uses jq to parse JSON but doesn't install it or check if it's available before use. This will cause the script to fail silently when jq commands are executed (lines 21, 25).
Consider either:
- Installing
jqalongsidelibfreetype6:sudo apt-get install -y libfreetype6 jq - Adding a command check similar to other modules:
if ! command -v jq > /dev/null; then echo "jq is not installed"; exit 1; fi
| sudo apt-get install -y libfreetype6 | |
| sudo apt-get install -y libfreetype6 jq |
| sudo apt-get update | ||
| sudo apt-get install -y libfreetype6 |
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 |
|
|
||
| install_plugin() { | ||
| log "Installing plugin: $2" | ||
| "$1" installPlugins "$2" |
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 |
| continue | ||
| fi | ||
|
|
||
| cli_launcher="$(find_cli_launcher "$code" "$product_dir")" || continue |
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
}|
@codex review |
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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| map_folder_to_code() { | ||
| case "$1" in | ||
| *pycharm*) echo "PY" ;; | ||
| *idea*) echo "IU" ;; | ||
| *webstorm*) echo "WS" ;; |
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 👍 / 👎.
| local exe | ||
| exe="$(launcher_for_code "$1")" || return 1 | ||
|
|
||
| if [ -f "$2/bin/$exe" ]; then | ||
| echo "$2/bin/$exe" |
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 👍 / 👎.
| # Load list of IDE codes user actually needs | ||
| mapfile -t pending_codes < <(get_enabled_codes) | ||
|
|
||
| if [ ${#pending_codes[@]} -eq 0 ]; then | ||
| log "No plugin entries found. Exiting." |
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 👍 / 👎.
|
I’ve implemented all the useful suggestions, @DevelopmentCats @matifali. |
Description
This PR detects the IDE folder and uses the IDE’s CLI tool to install the plugins provided by the user. It’s a prototype, and for now I just want to show the idea. I’ll improve the script later
pycharm64.exe installPlugins <plugin-id ...>Type of Change
Module Information
Path:
registry/coder/modules/jetbrainsNew version:
v1.1.0Breaking change: [ ] Yes [x] No
Testing & Validation
bun test)bun fmt)image's
/claim #208