mirror of
https://github.com/coder/registry.git
synced 2026-06-02 20:48:14 +00:00
Add IDE metadata output with tests and examples (#526)
## Description Exposes the metadata of the selected IDEs for use in the main template. Also adds tests to verify that the output metadata matches the "default" mappings. ## Type of Change - [ ] New module - [ ] New template - [ ] Bug fix - [x] Feature/enhancement - [ ] Documentation - [ ] Other ## Module Information **Path:** `registry/coder/modules/jetbrains` **New version:** `v1.2.0` **Breaking change:** [ ] Yes [x] No ## Testing & Validation - [N/A] Tests pass (`bun test`) - [x] Code formatted (`bun fmt`) - [x] Changes tested locally ## Related Issues None --------- Co-authored-by: DevCats <christofer@coder.com>
This commit is contained in:
@@ -14,7 +14,7 @@ This module adds JetBrains IDE buttons to launch IDEs directly from the dashboar
|
|||||||
module "jetbrains" {
|
module "jetbrains" {
|
||||||
count = data.coder_workspace.me.start_count
|
count = data.coder_workspace.me.start_count
|
||||||
source = "registry.coder.com/coder/jetbrains/coder"
|
source = "registry.coder.com/coder/jetbrains/coder"
|
||||||
version = "1.1.1"
|
version = "1.2.0"
|
||||||
agent_id = coder_agent.example.id
|
agent_id = coder_agent.example.id
|
||||||
folder = "/home/coder/project"
|
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
|
# tooltip = "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button." # Optional
|
||||||
@@ -40,7 +40,7 @@ When `default` contains IDE codes, those IDEs are created directly without user
|
|||||||
module "jetbrains" {
|
module "jetbrains" {
|
||||||
count = data.coder_workspace.me.start_count
|
count = data.coder_workspace.me.start_count
|
||||||
source = "registry.coder.com/coder/jetbrains/coder"
|
source = "registry.coder.com/coder/jetbrains/coder"
|
||||||
version = "1.1.1"
|
version = "1.2.0"
|
||||||
agent_id = coder_agent.example.id
|
agent_id = coder_agent.example.id
|
||||||
folder = "/home/coder/project"
|
folder = "/home/coder/project"
|
||||||
default = ["PY", "IU"] # Pre-configure GoLand and IntelliJ IDEA
|
default = ["PY", "IU"] # Pre-configure GoLand and IntelliJ IDEA
|
||||||
@@ -53,7 +53,7 @@ module "jetbrains" {
|
|||||||
module "jetbrains" {
|
module "jetbrains" {
|
||||||
count = data.coder_workspace.me.start_count
|
count = data.coder_workspace.me.start_count
|
||||||
source = "registry.coder.com/coder/jetbrains/coder"
|
source = "registry.coder.com/coder/jetbrains/coder"
|
||||||
version = "1.1.1"
|
version = "1.2.0"
|
||||||
agent_id = coder_agent.example.id
|
agent_id = coder_agent.example.id
|
||||||
folder = "/home/coder/project"
|
folder = "/home/coder/project"
|
||||||
# Show parameter with limited options
|
# Show parameter with limited options
|
||||||
@@ -67,7 +67,7 @@ module "jetbrains" {
|
|||||||
module "jetbrains" {
|
module "jetbrains" {
|
||||||
count = data.coder_workspace.me.start_count
|
count = data.coder_workspace.me.start_count
|
||||||
source = "registry.coder.com/coder/jetbrains/coder"
|
source = "registry.coder.com/coder/jetbrains/coder"
|
||||||
version = "1.1.1"
|
version = "1.2.0"
|
||||||
agent_id = coder_agent.example.id
|
agent_id = coder_agent.example.id
|
||||||
folder = "/home/coder/project"
|
folder = "/home/coder/project"
|
||||||
default = ["IU", "PY"]
|
default = ["IU", "PY"]
|
||||||
@@ -82,7 +82,7 @@ module "jetbrains" {
|
|||||||
module "jetbrains" {
|
module "jetbrains" {
|
||||||
count = data.coder_workspace.me.start_count
|
count = data.coder_workspace.me.start_count
|
||||||
source = "registry.coder.com/coder/jetbrains/coder"
|
source = "registry.coder.com/coder/jetbrains/coder"
|
||||||
version = "1.1.1"
|
version = "1.2.0"
|
||||||
agent_id = coder_agent.example.id
|
agent_id = coder_agent.example.id
|
||||||
folder = "/workspace/project"
|
folder = "/workspace/project"
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ module "jetbrains" {
|
|||||||
module "jetbrains_pycharm" {
|
module "jetbrains_pycharm" {
|
||||||
count = data.coder_workspace.me.start_count
|
count = data.coder_workspace.me.start_count
|
||||||
source = "registry.coder.com/coder/jetbrains/coder"
|
source = "registry.coder.com/coder/jetbrains/coder"
|
||||||
version = "1.1.1"
|
version = "1.2.0"
|
||||||
agent_id = coder_agent.example.id
|
agent_id = coder_agent.example.id
|
||||||
folder = "/workspace/project"
|
folder = "/workspace/project"
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ Add helpful tooltip text that appears when users hover over the IDE app buttons:
|
|||||||
module "jetbrains" {
|
module "jetbrains" {
|
||||||
count = data.coder_workspace.me.start_count
|
count = data.coder_workspace.me.start_count
|
||||||
source = "registry.coder.com/coder/jetbrains/coder"
|
source = "registry.coder.com/coder/jetbrains/coder"
|
||||||
version = "1.1.1"
|
version = "1.2.0"
|
||||||
agent_id = coder_agent.example.id
|
agent_id = coder_agent.example.id
|
||||||
folder = "/home/coder/project"
|
folder = "/home/coder/project"
|
||||||
default = ["IU", "PY"]
|
default = ["IU", "PY"]
|
||||||
@@ -136,6 +136,26 @@ module "jetbrains" {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Accessing the IDE Metadata
|
||||||
|
|
||||||
|
You can now reference the output `ide_metadata` as a map.
|
||||||
|
|
||||||
|
```tf
|
||||||
|
# Add metadata to the container showing the installed IDEs and their build versions.
|
||||||
|
resource "coder_metadata" "container_info" {
|
||||||
|
count = data.coder_workspace.me.start_count
|
||||||
|
resource_id = one(docker_container.workspace).id
|
||||||
|
|
||||||
|
dynamic "item" {
|
||||||
|
for_each = length(module.jetbrains) > 0 ? one(module.jetbrains).ide_metadata : {}
|
||||||
|
content {
|
||||||
|
key = item.value.build
|
||||||
|
value = "${item.value.name} [${item.key}]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Behavior
|
## Behavior
|
||||||
|
|
||||||
### Parameter vs Direct Apps
|
### Parameter vs Direct Apps
|
||||||
|
|||||||
@@ -1,3 +1,53 @@
|
|||||||
|
variables {
|
||||||
|
# Default IDE config, mirrored from main.tf for test assertions.
|
||||||
|
# If main.tf defaults change, update this map to match.
|
||||||
|
expected_ide_config = {
|
||||||
|
"CL" = { name = "CLion", icon = "/icon/clion.svg", build = "251.26927.39" },
|
||||||
|
"GO" = { name = "GoLand", icon = "/icon/goland.svg", build = "251.26927.50" },
|
||||||
|
"IU" = { name = "IntelliJ IDEA", icon = "/icon/intellij.svg", build = "251.26927.53" },
|
||||||
|
"PS" = { name = "PhpStorm", icon = "/icon/phpstorm.svg", build = "251.26927.60" },
|
||||||
|
"PY" = { name = "PyCharm", icon = "/icon/pycharm.svg", build = "251.26927.74" },
|
||||||
|
"RD" = { name = "Rider", icon = "/icon/rider.svg", build = "251.26927.67" },
|
||||||
|
"RM" = { name = "RubyMine", icon = "/icon/rubymine.svg", build = "251.26927.47" },
|
||||||
|
"RR" = { name = "RustRover", icon = "/icon/rustrover.svg", build = "251.26927.79" },
|
||||||
|
"WS" = { name = "WebStorm", icon = "/icon/webstorm.svg", build = "251.26927.40" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "validate_test_config_matches_defaults" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
# Provide minimal vars to allow plan to read module variables
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = length(var.ide_config) == length(var.expected_ide_config)
|
||||||
|
error_message = "Test configuration mismatch: 'var.ide_config' in main.tf has ${length(var.ide_config)} items, but 'var.expected_ide_config' in the test file has ${length(var.expected_ide_config)} items. Please update the test file's global variables block."
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
# Check that all keys in the test local are present in the module's default
|
||||||
|
condition = alltrue([
|
||||||
|
for key in keys(var.expected_ide_config) :
|
||||||
|
can(var.ide_config[key])
|
||||||
|
])
|
||||||
|
error_message = "Test configuration mismatch: Keys in 'var.expected_ide_config' are out of sync with 'var.ide_config' defaults. Please update the test file's global variables block."
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
# Check if all build numbers in the test local match the module's defaults
|
||||||
|
# This relies on the previous two assertions passing (same length, same keys)
|
||||||
|
condition = alltrue([
|
||||||
|
for key, config in var.expected_ide_config :
|
||||||
|
var.ide_config[key].build == config.build
|
||||||
|
])
|
||||||
|
error_message = "Test configuration mismatch: One or more build numbers in 'var.expected_ide_config' do not match the defaults in 'var.ide_config'. Please update the test file's global variables block."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
run "requires_agent_and_folder" {
|
run "requires_agent_and_folder" {
|
||||||
command = plan
|
command = plan
|
||||||
|
|
||||||
@@ -160,3 +210,87 @@ run "tooltip_null_when_not_provided" {
|
|||||||
error_message = "Expected coder_app tooltip to be null when not provided"
|
error_message = "Expected coder_app tooltip to be null when not provided"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run "output_empty_when_default_empty" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder"
|
||||||
|
# var.default is empty
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = length(output.ide_metadata) == 0
|
||||||
|
error_message = "Expected ide_metadata output to be empty when var.default is not set"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "output_single_ide_uses_fallback_build" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder"
|
||||||
|
default = ["GO"]
|
||||||
|
# Force HTTP data source to fail to test fallback logic
|
||||||
|
releases_base_link = "https://coder.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = length(output.ide_metadata) == 1
|
||||||
|
error_message = "Expected ide_metadata output to have 1 item"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = can(output.ide_metadata["GO"])
|
||||||
|
error_message = "Expected ide_metadata output to have key 'GO'"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = output.ide_metadata["GO"].name == var.expected_ide_config["GO"].name
|
||||||
|
error_message = "Expected ide_metadata['GO'].name to be '${var.expected_ide_config["GO"].name}'"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = output.ide_metadata["GO"].build == var.expected_ide_config["GO"].build
|
||||||
|
error_message = "Expected ide_metadata['GO'].build to use the fallback '${var.expected_ide_config["GO"].build}'"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = output.ide_metadata["GO"].icon == var.expected_ide_config["GO"].icon
|
||||||
|
error_message = "Expected ide_metadata['GO'].icon to be '${var.expected_ide_config["GO"].icon}'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run "output_multiple_ides" {
|
||||||
|
command = plan
|
||||||
|
|
||||||
|
variables {
|
||||||
|
agent_id = "foo"
|
||||||
|
folder = "/home/coder"
|
||||||
|
default = ["IU", "PY"]
|
||||||
|
# Force HTTP data source to fail to test fallback logic
|
||||||
|
releases_base_link = "https://coder.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = length(output.ide_metadata) == 2
|
||||||
|
error_message = "Expected ide_metadata output to have 2 items"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = can(output.ide_metadata["IU"]) && can(output.ide_metadata["PY"])
|
||||||
|
error_message = "Expected ide_metadata output to have keys 'IU' and 'PY'"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = output.ide_metadata["PY"].name == var.expected_ide_config["PY"].name
|
||||||
|
error_message = "Expected ide_metadata['PY'].name to be '${var.expected_ide_config["PY"].name}'"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {
|
||||||
|
condition = output.ide_metadata["PY"].build == var.expected_ide_config["PY"].build
|
||||||
|
error_message = "Expected ide_metadata['PY'].build to be the fallback '${var.expected_ide_config["PY"].build}'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -257,4 +257,13 @@ resource "coder_app" "jetbrains" {
|
|||||||
local.options_metadata[each.key].build,
|
local.options_metadata[each.key].build,
|
||||||
var.agent_name != null ? "&agent_name=${var.agent_name}" : "",
|
var.agent_name != null ? "&agent_name=${var.agent_name}" : "",
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output "ide_metadata" {
|
||||||
|
description = "A map of the metadata for each selected JetBrains IDE."
|
||||||
|
value = {
|
||||||
|
# We iterate directly over the selected_ides map.
|
||||||
|
# 'key' will be the IDE key (e.g., "IC", "PY")
|
||||||
|
for key, val in local.selected_ides : key => local.options_metadata[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user