Compare commits

...

7 Commits

Author SHA1 Message Date
Jiachen Jiang 60fec19d7d Update README.md (#440)
Added recommendation to the Gateway README, pointing to the Toolbox
module.

---------

Co-authored-by: DevCats <christofer@coder.com>
2025-09-30 09:14:16 -07:00
Atif Ali 44354b202d Fix claude-code module not passing workdir to agentapi (#439)
## Summary

Fixes #436 - The claude-code 3.0.0 module was not passing the custom
`workdir` variable to the agentapi module, causing it to default to
`/home/coder` instead of using the specified working directory.

## Changes

- Added missing `folder = local.workdir` parameter to the agentapi
module call in `main.tf:247`
- This ensures that custom working directories are properly propagated
to the agentapi module

## Test Plan

- [x] Terraform validation passes
- [x] Code formatting applied with `bun run fmt`
- [x] Basic terraform test passes (one pre-existing test failure
unrelated to this change)

## Verification

The fix adds the missing parameter that was identified in the issue:
```terraform
module "agentapi" {
  # ... other parameters
  folder = local.workdir  # <- Added this line
  # ... rest of configuration
}
```

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: DevCats <christofer@coder.com>
2025-09-30 08:02:35 -05:00
dependabot[bot] 80acbd7e3a chore(deps): bump crate-ci/typos from 1.36.2 to 1.36.3 in the github-actions group (#438)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-30 12:53:03 +00:00
DevCats 80f429faf1 chore: remove it wrappers from required variables tests (#442)
## Description

<!-- Briefly describe what this PR does and why -->
Remove it wrappers from required variables tf test in jfrog-oauth and
jfrog-token modules. This solves the failing tf tests that we were
encountering in all PR's across the board.

## Type of Change

- [ ] New module
- [X] Bug fix
- [ ] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Testing & Validation

- [X] Tests pass (`bun test`)
- [X] Code formatted (`bun run fmt`)
- [X] Changes tested locally

## Related Issues

<!-- Link related issues or write "None" if not applicable -->
2025-09-30 07:44:41 -05:00
Benraouane Soufiane e516446d03 Add Rustdesk module (#266)
Closes #79

## Description
This PR add new module, install minimal desktop environment (xfce),
virtual display, ,rustdesk package from deb file, init new screen,
export DISPLAY environment variable with last created virtual screen,
start new xfce session & execute the rustdesk cli, generate new
password, change the default password, then log the ID & password to be
used within rustdesk client to connect to the host

## Type of Change

- [x] New module
- [ ] Bug fix
- [ ] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Module Information
Overview/test video: live demo that launch rustdesk with GUI in a docker
container https://youtu.be/_rR-l7nARN4
Screenshots: 
<img width="1920" height="1080" alt="image"
src="https://github.com/user-attachments/assets/ba67a864-4295-471e-8b6a-976c23cb8f55"
/>
<img width="1920" height="1080" alt="image"
src="https://github.com/user-attachments/assets/24686339-aba7-47fe-92b4-5700ef5b154a"
/>
<img width="1920" height="1080" alt="image"
src="https://github.com/user-attachments/assets/21884c31-9eed-45ef-b3de-c12c99f2aa96"
/>
<img width="1920" height="1080" alt="image"
src="https://github.com/user-attachments/assets/ec0c65fe-61be-404c-ba36-8cc2882e85a2"
/>







**Path:** `registry/BenraouaneSoufiane/modules/rustdesk`  
**New version:** `v1.0.0`  
**Breaking change:** [ ] Yes [x] No

## Testing & Validation

- [x] Tests pass (`bun test`)
- [x] Code formatted (`bun run fmt`)
- [x] Changes tested locally

## Related Issues

/claim #79 (remain asset 150$)

---------

Co-authored-by: root <root@DESKTOP-6QN3GRE.localdomain>
Co-authored-by: DevCats <christofer@coder.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-22 20:04:24 -05:00
Rafael Rodriguez f0045397d4 feat: add tooltip support to jetbrains module (#421)
## Description

In this pull request we're updating the JetBrains module to support the
tooltip field added as requested in
https://github.com/coder/coder/pull/19781#pullrequestreview-3214217375

## Type of Change

- [ ] New module
- [ ] Bug fix
- [x] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Module Information

<!-- Delete this section if not applicable -->

**Path:** `registry/coder/modules/jetbrains`  
**New version:** `v1.1.0`  
**Breaking change:** [ ] Yes [x] No

## Testing & Validation

- [x] Tests pass (`bun test`)
- [x] Code formatted (`bun run fmt`)
- [x] Changes tested locally

## Related Issues

https://github.com/coder/coder/issues/18431

---------

Co-authored-by: Benjamin Peinhardt <61021968+bcpeinhardt@users.noreply.github.com>
2025-09-22 13:29:12 -05:00
DevCats 6af8508bc0 chore: update tasks template for claude-code update (#423)
## Description

Refactor template for claude-code module update for tasks

## Type of Change

- [ ] New module
- [ ] Bug fix
- [ ] Feature/enhancement
- [ ] Documentation
- [X] Other

## Testing & Validation

- [X] Tests pass (`bun test`)
- [X] Code formatted (`bun run fmt`)
- [X] Changes tested locally

## Related Issues

https://github.com/coder/registry/pull/402

---------

Co-authored-by: Atif Ali <atif@coder.com>
2025-09-19 14:51:37 -05:00
17 changed files with 422 additions and 70 deletions
+1 -1
View File
@@ -48,7 +48,7 @@ jobs:
- name: Validate formatting
run: bun fmt:ci
- name: Check for typos
uses: crate-ci/typos@v1.36.2
uses: crate-ci/typos@v1.36.3
with:
config: .github/typos.toml
validate-readme-files:
+5
View File
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="32" viewBox="0 0 375 375" width="32" xmlns="http://www.w3.org/2000/svg">
<rect fill="#0071ff" height="375.001088" rx="58.59392" stroke-width=".91553" width="375.001088" x=".0009759" y="-.0066962"/>
<path d="m150.428 322.264c-29.063-6.202-53.897-22.439-73.115-47.804-19.507-25.746-27.838-55.355-25.723-91.414 6.655-62.013 47.667-106.753 99.687-120.411 4.509-.989 8.353-3.462 12.55-1.322 3.22 1.64 6.028 4.467 7.206 7.251 1.25 2.955 1.877 21.54.99 29.331-1.076 9.46-3.877 12.418-14.566 15.388-29.723 10.195-48.105 34.07-53.697 61.017-4.8 29.668 2.951 59.729 21.528 78.727 8.966 8.993 17.92 14.24 30.869 18.086 8.646 2.57 13.393 5.758 15.036 10.102 1.085 2.867 1.63 22.984.779 28.772-1.33 9.046-1.702 9.796-5.792 11.667-5.029 2.3-7.404 2.392-15.752.61zm50.708.29c-3.092-1.402-5.673-4.83-6.73-8.94-.134-9.408-2.366-25.754 1.02-33.373 1.88-4.128 4.65-5.999 12.433-8.396 21.267-6.551 37.593-19.88 46.806-38.213 11.11-22.108 11.877-55.183 1.808-77.975-9.154-20.723-25.7-35.217-48.555-42.534-8.872-2.84-12.004-5.065-12.968-9.21-1.002-4.31-1.435-19.87-.785-28.218.682-8.766 1.249-9.99 6.162-13.318 3.701-2.505 5.482-2.446 17.223.575 36.718 10.077 65.97 33.597 83.026 66.68 18.495 37.034 19.191 86.11 1.742 122.655-17.233 36.09-50.591 62.511-88.622 70.194-8.172 1.65-9.07 1.656-12.56.073z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

+14
View File
@@ -0,0 +1,14 @@
---
display_name: "Benraouane Soufiane"
bio: "Full stack developer creating awesome things."
avatar: "./.images/avatar.png"
github: "benraouanesoufiane"
linkedin: "https://www.linkedin.com/in/benraouane-soufiane" # Optional
website: "https://benraouanesoufiane.com" # Optional
support_email: "hello@benraouanesoufiane.com" # Optional
status: "community"
---
# Benraouane Soufiane
Full stack developer creating awesome things.
@@ -0,0 +1,82 @@
---
display_name: RustDesk
description: Run RustDesk in your workspace with virtual display
icon: ../../../../.icons/rustdesk.svg
verified: false
tags: [rustdesk, rdp, vm]
---
# RustDesk
Launches RustDesk within your workspace with a virtual display to provide remote desktop access. The module outputs the RustDesk ID and password needed to connect from external RustDesk clients.
```tf
module "rustdesk" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/BenraouaneSoufiane/rustdesk/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
}
```
## Features
- Automatically sets up virtual display (Xvfb)
- Downloads and configures RustDesk
- Outputs RustDesk ID and password for easy connection
- Provides external app link to RustDesk web client for browser-based access
- Starts virtual display (Xvfb) with customizable resolution
- Customizable screen resolution and RustDesk version
## Requirements
- Coder v2.5 or higher
- Linux workspace with `apt`, `dnf`, or `yum` package manager
## Examples
### Custom configuration with specific version
```tf
module "rustdesk" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/BenraouaneSoufiane/rustdesk/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
rustdesk_password = "mycustompass"
xvfb_resolution = "1920x1080x24"
rustdesk_version = "1.4.1"
}
```
### Docker container configuration
It requires coder' server to be run as root, when using with Docker, add the following to your `docker_container` resource:
```tf
resource "docker_container" "workspace" {
# ... other configuration ...
user = "root"
privileged = true
network_mode = "host"
ports {
internal = 21115
external = 21115
}
ports {
internal = 21116
external = 21116
}
ports {
internal = 21118
external = 21118
}
ports {
internal = 21119
external = 21119
}
}
```
@@ -0,0 +1,75 @@
terraform {
required_version = ">= 1.0"
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.5"
}
}
}
variable "log_path" {
type = string
description = "The path to log rustdesk to."
default = "/tmp/rustdesk.log"
}
variable "agent_id" {
description = "Attach RustDesk setup to this agent"
type = string
}
variable "order" {
description = "Run order among scripts/apps"
type = number
default = 1
}
# Optional knobs passed as env (you can expose these as variables too)
variable "rustdesk_password" {
description = "If empty, the script will generate one"
type = string
default = ""
sensitive = true
}
variable "xvfb_resolution" {
description = "Xvfb screen size/depth"
type = string
default = "1024x768x16"
}
variable "rustdesk_version" {
description = "RustDesk version to install (use 'latest' for most recent release)"
type = string
default = "latest"
}
resource "coder_script" "rustdesk" {
agent_id = var.agent_id
display_name = "RustDesk"
run_on_start = true
# Prepend env as bash exports, then append the script file literally.
script = <<-EOT
# --- module-provided env knobs ---
export RUSTDESK_PASSWORD="${var.rustdesk_password}"
export XVFB_RESOLUTION="${var.xvfb_resolution}"
export RUSTDESK_VERSION="${var.rustdesk_version}"
# ---------------------------------
${file("${path.module}/run.sh")}
EOT
}
resource "coder_app" "rustdesk" {
agent_id = var.agent_id
slug = "rustdesk"
display_name = "Rustdesk"
url = "https://rustdesk.com/web"
icon = "/icon/rustdesk.svg"
order = var.order
external = true
}
@@ -0,0 +1,117 @@
#!/usr/bin/env bash
BOLD='\033[0;1m'
RESET='\033[0m'
printf "${BOLD}🖥️ Installing RustDesk Remote Desktop\n${RESET}"
# ---- configurable knobs (env overrides) ----
RUSTDESK_VERSION="${RUSTDESK_VERSION:-latest}"
LOG_PATH="${LOG_PATH:-/tmp/rustdesk.log}"
# ---- fetch latest version if needed ----
if [ "$RUSTDESK_VERSION" = "latest" ]; then
printf "🔍 Fetching latest RustDesk version...\n"
RUSTDESK_VERSION=$(curl -s https://api.github.com/repos/rustdesk/rustdesk/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' || echo "1.4.1")
printf "📌 Fetched RustDesk version: ${RUSTDESK_VERSION}\n"
else
printf "📌 Using specified RustDesk version: ${RUSTDESK_VERSION}\n"
fi
XVFB_RESOLUTION="${XVFB_RESOLUTION:-1024x768x16}"
RUSTDESK_PASSWORD="${RUSTDESK_PASSWORD:-}"
# ---- detect package manager & arch ----
ARCH="$(uname -m)"
case "$ARCH" in
x86_64 | amd64) PKG_ARCH="x86_64" ;;
aarch64 | arm64) PKG_ARCH="aarch64" ;;
*)
echo "❌ Unsupported arch: $ARCH"
exit 1
;;
esac
if command -v apt-get > /dev/null 2>&1; then
PKG_SYS="deb"
PKG_NAME="rustdesk-${RUSTDESK_VERSION}-${PKG_ARCH}.deb"
INSTALL_DEPS='apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y wget libva2 libva-drm2 libva-x11-2 libgstreamer-plugins-base1.0-0 gstreamer1.0-pipewire xfce4 xfce4-goodies xvfb x11-xserver-utils dbus-x11 libegl1 libgl1 libglx0 libglu1-mesa mesa-utils libxrandr2 libxss1 libgtk-3-0t64 libgbm1 libdrm2 libxcomposite1 libxdamage1 libxfixes3'
INSTALL_CMD="apt-get install -y ./${PKG_NAME}"
CLEAN_CMD="rm -f \"${PKG_NAME}\""
elif command -v dnf > /dev/null 2>&1; then
PKG_SYS="rpm"
PKG_NAME="rustdesk-${RUSTDESK_VERSION}-${PKG_ARCH}.rpm"
INSTALL_DEPS='dnf install -y wget libva libva-intel-driver gstreamer1-plugins-base pipewire xfce4-session xfce4-panel xorg-x11-server-Xvfb xorg-x11-xauth dbus-x11 mesa-libEGL mesa-libGL mesa-libGLU mesa-dri-drivers libXrandr libXScrnSaver gtk3 mesa-libgbm libdrm libXcomposite libXdamage libXfixes'
INSTALL_CMD="dnf install -y ./${PKG_NAME}"
CLEAN_CMD="rm -f \"${PKG_NAME}\""
elif command -v yum > /dev/null 2>&1; then
PKG_SYS="rpm"
PKG_NAME="rustdesk-${RUSTDESK_VERSION}-${PKG_ARCH}.rpm"
INSTALL_DEPS='yum install -y wget libva libva-intel-driver gstreamer1-plugins-base pipewire xfce4-session xfce4-panel xorg-x11-server-Xvfb xorg-x11-xauth dbus-x11 mesa-libEGL mesa-libGL mesa-libGLU mesa-dri-drivers libXrandr libXScrnSaver gtk3 mesa-libgbm libdrm libXcomposite libXdamage libXfixes'
INSTALL_CMD="yum install -y ./${PKG_NAME}"
CLEAN_CMD="rm -f \"${PKG_NAME}\""
else
echo "❌ Unsupported distro: need apt, dnf, or yum."
exit 1
fi
# ---- install rustdesk if missing ----
if ! command -v rustdesk > /dev/null 2>&1; then
printf "📦 Installing dependencies...\n"
sudo bash -c "$INSTALL_DEPS" 2>&1 | tee -a "${LOG_PATH}"
printf "⬇️ Downloading RustDesk ${RUSTDESK_VERSION} (${PKG_SYS}, ${PKG_ARCH})...\n"
URL="https://github.com/rustdesk/rustdesk/releases/download/${RUSTDESK_VERSION}/${PKG_NAME}"
wget -q "$URL" 2>&1 | tee -a "${LOG_PATH}"
printf "🔧 Installing RustDesk...\n"
sudo bash -c "$INSTALL_CMD" 2>&1 | tee -a "${LOG_PATH}"
printf "🧹 Cleaning up...\n"
bash -c "$CLEAN_CMD" 2>&1 | tee -a "${LOG_PATH}"
else
printf "✅ RustDesk already installed\n"
fi
# ---- start virtual display ----
echo "Starting Xvfb with resolution ${XVFB_RESOLUTION}"
Xvfb :99 -screen 0 "${XVFB_RESOLUTION}" >> "${LOG_PATH}" 2>&1 &
export DISPLAY=:99
# Wait for X to be ready
for i in {1..10}; do
if xdpyinfo -display :99 > /dev/null 2>&1; then
echo "X display is ready"
break
fi
sleep 1
done
# ---- create (or accept) password and start rustdesk ----
if [[ -z "${RUSTDESK_PASSWORD}" ]]; then
RUSTDESK_PASSWORD="$(tr -dc 'a-zA-Z0-9@' < /dev/urandom | head -c 10)@97"
fi
echo "Starting XFCE desktop environment..."
xfce4-session >> "${LOG_PATH}" 2>&1 &
echo "Waiting for xfce4-session to initialize..."
sleep 5
printf "🔐 Setting RustDesk password and starting service...\n"
rustdesk >> "${LOG_PATH}" 2>&1 &
sleep 2
rustdesk --password "${RUSTDESK_PASSWORD}" >> "${LOG_PATH}" 2>&1 &
sleep 3
RID="$(rustdesk --get-id 2> /dev/null || echo 'ID_PENDING')"
printf "🥳 RustDesk setup complete!\n\n"
printf "${BOLD}📋 Connection Details:${RESET}\n"
printf " RustDesk ID: ${RID}\n"
printf " RustDesk Password: ${RUSTDESK_PASSWORD}\n"
printf " Display: ${DISPLAY} (${XVFB_RESOLUTION})\n"
printf "\n📝 Logs available at: ${LOG_PATH}\n\n"
echo "Setup script completed successfully. All services running in background."
exit 0
@@ -22,31 +22,16 @@ provider "docker" {}
module "claude-code" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/claude-code/coder"
version = "2.0.0"
version = "3.0.0"
agent_id = coder_agent.main.id
folder = "/home/coder/projects"
install_claude_code = true
claude_code_version = "latest"
workdir = "/home/coder/projects"
order = 999
experiment_post_install_script = data.coder_parameter.setup_script.value
# This enables Coder Tasks
experiment_report_tasks = true
}
# You can also use a model provider, like AWS Bedrock or Vertex by replacing
# this with the special env vars from the Claude Code docs.
# see: https://docs.anthropic.com/en/docs/claude-code/third-party-integrations
variable "anthropic_api_key" {
type = string
description = "Generate one at: https://console.anthropic.com/settings/keys"
sensitive = true
}
resource "coder_env" "anthropic_api_key" {
agent_id = coder_agent.main.id
name = "CODER_MCP_CLAUDE_API_KEY"
value = var.anthropic_api_key
claude_api_key = ""
ai_prompt = data.coder_parameter.ai_prompt.value
system_prompt = data.coder_parameter.system_prompt.value
model = "sonnet"
permission_mode = "plan"
post_install_script = data.coder_parameter.setup_script.value
}
# We are using presets to set the prompts, image, and set up instructions
@@ -172,23 +157,6 @@ data "coder_parameter" "preview_port" {
mutable = false
}
# Other variables for Claude Code
resource "coder_env" "claude_task_prompt" {
agent_id = coder_agent.main.id
name = "CODER_MCP_CLAUDE_TASK_PROMPT"
value = data.coder_parameter.ai_prompt.value
}
resource "coder_env" "app_status_slug" {
agent_id = coder_agent.main.id
name = "CODER_MCP_APP_STATUS_SLUG"
value = "ccw"
}
resource "coder_env" "claude_system_prompt" {
agent_id = coder_agent.main.id
name = "CODER_MCP_CLAUDE_SYSTEM_PROMPT"
value = data.coder_parameter.system_prompt.value
}
data "coder_provisioner" "me" {}
data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}
+4 -4
View File
@@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "3.0.0"
version = "3.0.1"
agent_id = coder_agent.example.id
workdir = "/home/coder/project"
claude_api_key = "xxxx-xxxxx-xxxx"
@@ -49,7 +49,7 @@ data "coder_parameter" "ai_prompt" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "3.0.0"
version = "3.0.1"
agent_id = coder_agent.example.id
workdir = "/home/coder/project"
@@ -85,7 +85,7 @@ Run and configure Claude Code as a standalone CLI in your workspace.
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "3.0.0"
version = "3.0.1"
agent_id = coder_agent.example.id
workdir = "/home/coder"
install_claude_code = true
@@ -108,7 +108,7 @@ variable "claude_code_oauth_token" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "3.0.0"
version = "3.0.1"
agent_id = coder_agent.example.id
workdir = "/home/coder/project"
claude_code_oauth_token = var.claude_code_oauth_token
@@ -244,6 +244,7 @@ module "agentapi" {
web_app_group = var.group
web_app_icon = var.icon
web_app_display_name = var.web_app_display_name
folder = local.workdir
cli_app = var.cli_app
cli_app_slug = var.cli_app ? "${local.app_slug}-cli" : null
cli_app_display_name = var.cli_app ? var.cli_app_display_name : null
@@ -10,6 +10,8 @@ tags: [ide, jetbrains, parameter, gateway]
This module adds a JetBrains Gateway Button to open any workspace with a single click.
> We recommend using the [Coder Toolbox module](https://registry.coder.com/modules/coder/jetbrains), which offers significant stability and connectivity benefits over Gateway. Reference our [documentation](https://coder.com/docs/user-guides/workspace-access/jetbrains/toolbox) for more information.
JetBrains recommends a minimum of 4 CPU cores and 8GB of RAM.
Consult the [JetBrains documentation](https://www.jetbrains.com/help/idea/prerequisites.html#min_requirements) to confirm other system requirements.
@@ -17,7 +19,7 @@ Consult the [JetBrains documentation](https://www.jetbrains.com/help/idea/prereq
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains-gateway/coder"
version = "1.2.2"
version = "1.2.3"
agent_id = coder_agent.example.id
folder = "/home/coder/example"
jetbrains_ides = ["CL", "GO", "IU", "PY", "WS"]
@@ -35,7 +37,7 @@ module "jetbrains_gateway" {
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains-gateway/coder"
version = "1.2.2"
version = "1.2.3"
agent_id = coder_agent.example.id
folder = "/home/coder/example"
jetbrains_ides = ["GO", "WS"]
@@ -49,7 +51,7 @@ module "jetbrains_gateway" {
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains-gateway/coder"
version = "1.2.2"
version = "1.2.3"
agent_id = coder_agent.example.id
folder = "/home/coder/example"
jetbrains_ides = ["IU", "PY"]
@@ -64,7 +66,7 @@ module "jetbrains_gateway" {
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains-gateway/coder"
version = "1.2.2"
version = "1.2.3"
agent_id = coder_agent.example.id
folder = "/home/coder/example"
jetbrains_ides = ["IU", "PY"]
@@ -89,7 +91,7 @@ module "jetbrains_gateway" {
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains-gateway/coder"
version = "1.2.2"
version = "1.2.3"
agent_id = coder_agent.example.id
folder = "/home/coder/example"
jetbrains_ides = ["GO", "WS"]
@@ -107,7 +109,7 @@ Due to the highest priority of the `ide_download_link` parameter in the `(jetbra
module "jetbrains_gateway" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains-gateway/coder"
version = "1.2.2"
version = "1.2.3"
agent_id = coder_agent.example.id
folder = "/home/coder/example"
jetbrains_ides = ["GO", "WS"]
+30 -6
View File
@@ -14,9 +14,10 @@ This module adds JetBrains IDE buttons to launch IDEs directly from the dashboar
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.0.3"
version = "1.1.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
# tooltip = "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button." # Optional
}
```
@@ -39,7 +40,7 @@ When `default` contains IDE codes, those IDEs are created directly without user
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.0.3"
version = "1.1.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
default = ["PY", "IU"] # Pre-configure GoLand and IntelliJ IDEA
@@ -52,7 +53,7 @@ module "jetbrains" {
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.0.3"
version = "1.1.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
# Show parameter with limited options
@@ -66,7 +67,7 @@ module "jetbrains" {
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.0.3"
version = "1.1.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
default = ["IU", "PY"]
@@ -81,7 +82,7 @@ module "jetbrains" {
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.0.3"
version = "1.1.0"
agent_id = coder_agent.example.id
folder = "/workspace/project"
@@ -107,7 +108,7 @@ module "jetbrains" {
module "jetbrains_pycharm" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.0.3"
version = "1.1.0"
agent_id = coder_agent.example.id
folder = "/workspace/project"
@@ -119,6 +120,22 @@ module "jetbrains_pycharm" {
}
```
### Custom Tooltip
Add helpful tooltip text that appears when users hover over the IDE app buttons:
```tf
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.1.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
default = ["IU", "PY"]
tooltip = "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button."
}
```
## Behavior
### Parameter vs Direct Apps
@@ -132,6 +149,13 @@ module "jetbrains_pycharm" {
- If the API is unreachable (air-gapped environments), the module automatically falls back to build numbers from `ide_config`
- `major_version` and `channel` control which API endpoint is queried (when API access is available)
### Tooltip
- **`tooltip`**: Optional markdown text displayed when hovering over IDE app buttons
- If not specified, no tooltip is shown
- Supports markdown formatting for rich text (bold, italic, links, etc.)
- All IDE apps created by this module will show the same tooltip text
## Supported IDEs
All JetBrains IDEs with remote development capabilities:
@@ -129,3 +129,34 @@ run "app_order_when_default_not_empty" {
error_message = "Expected coder_app order to be set to 10"
}
}
run "tooltip_when_provided" {
command = plan
variables {
agent_id = "foo"
folder = "/home/coder"
default = ["GO"]
tooltip = "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button."
}
assert {
condition = anytrue([for app in values(resource.coder_app.jetbrains) : app.tooltip == "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button."])
error_message = "Expected coder_app tooltip to be set when provided"
}
}
run "tooltip_null_when_not_provided" {
command = plan
variables {
agent_id = "foo"
folder = "/home/coder"
default = ["GO"]
}
assert {
condition = anytrue([for app in values(resource.coder_app.jetbrains) : app.tooltip == null])
error_message = "Expected coder_app tooltip to be null when not provided"
}
}
@@ -276,6 +276,36 @@ describe("jetbrains", async () => {
);
expect(parameter?.instances[0].attributes.order).toBe(5);
});
it("should set tooltip when specified", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
folder: "/home/coder",
default: '["GO"]',
tooltip:
"You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button.",
});
const coder_app = state.resources.find(
(res) => res.type === "coder_app" && res.name === "jetbrains",
);
expect(coder_app?.instances[0].attributes.tooltip).toBe(
"You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button.",
);
});
it("should have null tooltip when not specified", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
folder: "/home/coder",
default: '["GO"]',
});
const coder_app = state.resources.find(
(res) => res.type === "coder_app" && res.name === "jetbrains",
);
expect(coder_app?.instances[0].attributes.tooltip).toBeNull();
});
});
// URL Generation Tests
+7
View File
@@ -59,6 +59,12 @@ variable "coder_parameter_order" {
default = null
}
variable "tooltip" {
type = string
description = "Markdown text that is displayed when hovering over workspace apps."
default = null
}
variable "major_version" {
type = string
description = "The major version of the IDE. i.e. 2025.1"
@@ -232,6 +238,7 @@ resource "coder_app" "jetbrains" {
external = true
order = var.coder_app_order
group = var.group
tooltip = var.tooltip
url = join("", [
"jetbrains://gateway/coder?&workspace=", # requires 2.6.3+ version of Toolbox
data.coder_workspace.me.name,
@@ -24,12 +24,10 @@ describe("jfrog-oauth", async () => {
const fakeFrogUrl = "http://localhost:8081";
const user = "default";
it("can run apply with required variables", async () => {
testRequiredVariables<TestVariables>(import.meta.dir, {
agent_id: "some-agent-id",
jfrog_url: fakeFrogUrl,
package_managers: "{}",
});
testRequiredVariables<TestVariables>(import.meta.dir, {
agent_id: "some-agent-id",
jfrog_url: fakeFrogUrl,
package_managers: "{}",
});
it("generates an npmrc with scoped repos", async () => {
@@ -55,13 +55,11 @@ describe("jfrog-token", async () => {
const user = "default";
const token = "xxx";
it("can run apply with required variables", async () => {
testRequiredVariables<TestVariables>(import.meta.dir, {
agent_id: "some-agent-id",
jfrog_url: fakeFrogUrl,
artifactory_access_token: "XXXX",
package_managers: "{}",
});
testRequiredVariables<TestVariables>(import.meta.dir, {
agent_id: "some-agent-id",
jfrog_url: fakeFrogUrl,
artifactory_access_token: "XXXX",
package_managers: "{}",
});
it("generates an npmrc with scoped repos", async () => {