Compare commits

..

6 Commits

Author SHA1 Message Date
Yevhenii Shcherbina 28fc956110 fix: minor boundary bug in claude-code module (#637)
Removing existing boundary directory to allow re-running the script
safely
2026-01-07 10:17:40 -05:00
Atif Ali 2701dc09af feat(coder/modules/jetbrains): update to latest build numbers and clean up tests (#636)
Co-authored-by: DevCats <christofer@coder.com>
2026-01-07 01:06:31 +05:00
Scai 60611ed593 feat: make dynamic locations & server types on Hetzner template (#618)
## Description

Make Server Types & Locations dynamic based on API endpoints provided by
Hetzner Docs.

## Type of Change

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

## Template Information

**Path:** `registry/Excellencedev/templates/hetzner-linux`

## Testing & Validation

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

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: DevCats <christofer@coder.com>
2026-01-06 08:29:40 -06:00
dependabot[bot] 7df0cb25c5 chore(deps): bump crate-ci/typos from 1.40.0 to 1.41.0 in the github-actions group (#632)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 22:10:18 +00:00
DevCats cbb39bda6f chore: remove test from cloud-dev template (#635)
## Description

Remove test from `cloud-dev` template since templates generally have no
tests.
<!-- Briefly describe what this PR does and why -->

## Type of Change

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

## Template Information

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

**Path:** `registry/nboyers/templates/cloud-dev`

## Testing & Validation

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

## Related Issues

<!-- Link related issues or write "None" if not applicable -->
2026-01-05 15:59:03 -06:00
DevCats 99bd4a4139 fix(github-upload-public-key): resolve issues with flaky tests (#634)
## Description

Better test cleanup, and resolve flakiness.
<!-- Briefly describe what this PR does and why -->

## Type of Change

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

## Module Information

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

**Path:** `registry/coder/modules/github-upload-public-key`  
**New version:** `v1.0.32`  
**Breaking change:** [ ] Yes [ ] No

## Testing & Validation

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

## Related Issues

<!-- Link related issues or write "None" if not applicable -->
2026-01-05 14:59:06 -06:00
9 changed files with 200 additions and 1173 deletions
+1 -1
View File
@@ -93,7 +93,7 @@ jobs:
- name: Validate formatting
run: bun fmt:ci
- name: Check for typos
uses: crate-ci/typos@v1.40.0
uses: crate-ci/typos@v1.41.0
with:
config: .github/typos.toml
validate-readme-files:
@@ -1,27 +0,0 @@
{
"type_meta": {
"cx22": { "cores": 2, "memory_gb": 4, "disk_gb": 40 },
"cx32": { "cores": 4, "memory_gb": 8, "disk_gb": 80 },
"cx42": { "cores": 8, "memory_gb": 16, "disk_gb": 160 },
"cx52": { "cores": 16, "memory_gb": 32, "disk_gb": 320 },
"cpx11": { "cores": 2, "memory_gb": 2, "disk_gb": 40 },
"cpx21": { "cores": 3, "memory_gb": 4, "disk_gb": 80 },
"cpx31": { "cores": 4, "memory_gb": 8, "disk_gb": 160 },
"cpx41": { "cores": 8, "memory_gb": 16, "disk_gb": 240 },
"cpx51": { "cores": 16, "memory_gb": 32, "disk_gb": 360 },
"ccx13": { "cores": 2, "memory_gb": 8, "disk_gb": 80 },
"ccx23": { "cores": 4, "memory_gb": 16, "disk_gb": 160 },
"ccx33": { "cores": 8, "memory_gb": 32, "disk_gb": 240 },
"ccx43": { "cores": 16, "memory_gb": 64, "disk_gb": 360 },
"ccx53": { "cores": 32, "memory_gb": 128, "disk_gb": 600 },
"ccx63": { "cores": 48, "memory_gb": 192, "disk_gb": 960 }
},
"availability": {
"fsn1": ["cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"],
"ash": ["cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"],
"hel1": ["cx22", "cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"],
"hil": ["cpx11", "cpx21", "cpx31", "cpx41", "ccx13", "ccx23", "ccx33"],
"nbg1": ["cx22", "cx32", "cx42", "cx52", "cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"],
"sin": ["cpx11", "cpx21", "cpx31", "cpx41", "cpx51", "ccx13", "ccx23", "ccx33"]
}
}
@@ -6,6 +6,10 @@ terraform {
coder = {
source = "coder/coder"
}
http = {
source = "hashicorp/http"
version = "~> 3.0"
}
}
}
@@ -17,6 +21,24 @@ provider "hcloud" {
token = var.hcloud_token
}
data "http" "hcloud_locations" {
url = "https://api.hetzner.cloud/v1/locations"
request_headers = {
Authorization = "Bearer ${var.hcloud_token}"
Accept = "application/json"
}
}
data "http" "hcloud_server_types" {
url = "https://api.hetzner.cloud/v1/server_types"
request_headers = {
Authorization = "Bearer ${var.hcloud_token}"
Accept = "application/json"
}
}
# Available locations: https://docs.hetzner.com/cloud/general/locations/
data "coder_parameter" "hcloud_location" {
name = "hcloud_location"
@@ -24,29 +46,18 @@ data "coder_parameter" "hcloud_location" {
description = "Select the Hetzner Cloud location for your workspace."
type = "string"
default = "fsn1"
option {
name = "DE Falkenstein"
value = "fsn1"
}
option {
name = "US Ashburn, VA"
value = "ash"
}
option {
name = "US Hillsboro, OR"
value = "hil"
}
option {
name = "SG Singapore"
value = "sin"
}
option {
name = "DE Nuremberg"
value = "nbg1"
}
option {
name = "FI Helsinki"
value = "hel1"
dynamic "option" {
for_each = local.hcloud_locations
content {
name = format(
"%s (%s, %s)",
upper(option.value.name),
option.value.city,
option.value.country
)
value = option.value.name
}
}
}
@@ -109,17 +120,47 @@ resource "hcloud_volume_attachment" "home_volume_attachment" {
locals {
username = lower(data.coder_workspace_owner.me.name)
# Data source: local JSON file under the module directory
# Check API for latest server types & availability: https://docs.hetzner.cloud/reference/cloud#server-types
hcloud_server_types_data = jsondecode(file("${path.module}/hetzner_server_types.json"))
hcloud_server_type_meta = local.hcloud_server_types_data.type_meta
hcloud_server_types_by_location = local.hcloud_server_types_data.availability
# --------------------
# Locations
# --------------------
hcloud_locations = [
for loc in jsondecode(data.http.hcloud_locations.response_body).locations : {
name = loc.name
city = loc.city
country = loc.country
}
]
# --------------------
# Server Types
# --------------------
hcloud_server_types = {
for st in jsondecode(data.http.hcloud_server_types.response_body).server_types :
st.name => {
cores = st.cores
memory_gb = st.memory
disk_gb = st.disk
locations = [for l in st.locations : l.name]
deprecated = st.deprecated
}
if st.deprecated == false
}
hcloud_server_type_options_for_selected_location = [
for type_name in lookup(local.hcloud_server_types_by_location, data.coder_parameter.hcloud_location.value, []) : {
name = format("%s (%d vCPU, %dGB RAM, %dGB)", upper(type_name), local.hcloud_server_type_meta[type_name].cores, local.hcloud_server_type_meta[type_name].memory_gb, local.hcloud_server_type_meta[type_name].disk_gb)
value = type_name
for name, meta in local.hcloud_server_types : {
name = format(
"%s (%d vCPU, %dGB RAM, %dGB)",
upper(name),
meta.cores,
meta.memory_gb,
meta.disk_gb
)
value = name
}
if contains(
meta.locations,
data.coder_parameter.hcloud_location.value
)
]
}
@@ -180,4 +221,4 @@ module "code-server" {
agent_id = coder_agent.main.id
order = 1
}
}
+7 -7
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 = "4.2.8"
version = "4.2.9"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
claude_api_key = "xxxx-xxxxx-xxxx"
@@ -45,7 +45,7 @@ This example shows how to configure the Claude Code module to run the agent behi
```tf
module "claude-code" {
source = "dev.registry.coder.com/coder/claude-code/coder"
version = "4.2.8"
version = "4.2.9"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
enable_boundary = true
@@ -72,7 +72,7 @@ data "coder_parameter" "ai_prompt" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.8"
version = "4.2.9"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
@@ -108,7 +108,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 = "4.2.8"
version = "4.2.9"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
install_claude_code = true
@@ -130,7 +130,7 @@ variable "claude_code_oauth_token" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.8"
version = "4.2.9"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
claude_code_oauth_token = var.claude_code_oauth_token
@@ -203,7 +203,7 @@ resource "coder_env" "bedrock_api_key" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.8"
version = "4.2.9"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
@@ -260,7 +260,7 @@ resource "coder_env" "google_application_credentials" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "4.2.8"
version = "4.2.9"
agent_id = coder_agent.main.id
workdir = "/home/coder/project"
model = "claude-sonnet-4@20250514"
@@ -48,6 +48,13 @@ function install_boundary() {
if [ "${ARG_COMPILE_FROM_SOURCE:-false}" = "true" ]; then
# Install boundary by compiling from source
echo "Compiling boundary from source (version: $ARG_BOUNDARY_VERSION)"
echo "Removing existing boundary directory to allow re-running the script safely"
if [ -d boundary ]; then
rm -rf boundary
fi
echo "Clone boundary repository"
git clone https://github.com/coder/boundary.git
cd boundary
git checkout "$ARG_BOUNDARY_VERSION"
+8 -16
View File
@@ -14,10 +14,9 @@ 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.2.1"
version = "1.3.0"
agent_id = coder_agent.main.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
}
```
@@ -40,7 +39,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.2.1"
version = "1.3.0"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
default = ["PY", "IU"] # Pre-configure GoLand and IntelliJ IDEA
@@ -53,7 +52,7 @@ module "jetbrains" {
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.2.1"
version = "1.3.0"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
# Show parameter with limited options
@@ -67,7 +66,7 @@ module "jetbrains" {
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.2.1"
version = "1.3.0"
agent_id = coder_agent.main.id
folder = "/home/coder/project"
default = ["IU", "PY"]
@@ -82,7 +81,7 @@ module "jetbrains" {
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.2.1"
version = "1.3.0"
agent_id = coder_agent.main.id
folder = "/workspace/project"
@@ -109,7 +108,7 @@ module "jetbrains" {
module "jetbrains_pycharm" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.2.1"
version = "1.3.0"
agent_id = coder_agent.main.id
folder = "/workspace/project"
@@ -129,11 +128,11 @@ Add helpful tooltip text that appears when users hover over the IDE app buttons:
module "jetbrains" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/jetbrains/coder"
version = "1.2.1"
version = "1.3.0"
agent_id = coder_agent.main.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."
tooltip = "You need to install [JetBrains Toolbox App](https://www.jetbrains.com/toolbox-app/) to use this button."
}
```
@@ -170,13 +169,6 @@ resource "coder_metadata" "container_info" {
- 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:
@@ -2,15 +2,15 @@ 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" }
"CL" = { name = "CLion", icon = "/icon/clion.svg", build = "253.29346.141" },
"GO" = { name = "GoLand", icon = "/icon/goland.svg", build = "253.28294.337" },
"IU" = { name = "IntelliJ IDEA", icon = "/icon/intellij.svg", build = "253.29346.138" },
"PS" = { name = "PhpStorm", icon = "/icon/phpstorm.svg", build = "253.29346.151" },
"PY" = { name = "PyCharm", icon = "/icon/pycharm.svg", build = "253.29346.142" },
"RD" = { name = "Rider", icon = "/icon/rider.svg", build = "253.29346.144" },
"RM" = { name = "RubyMine", icon = "/icon/rubymine.svg", build = "253.29346.140" },
"RR" = { name = "RustRover", icon = "/icon/rustrover.svg", build = "253.29346.139" },
"WS" = { name = "WebStorm", icon = "/icon/webstorm.svg", build = "253.29346.143" }
}
}
@@ -187,16 +187,16 @@ run "tooltip_when_provided" {
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."
tooltip = "You need to install [JetBrains Toolbox App](https://www.jetbrains.com/toolbox-app/) 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."])
condition = anytrue([for app in values(resource.coder_app.jetbrains) : app.tooltip == "You need to install [JetBrains Toolbox App](https://www.jetbrains.com/toolbox-app/) to use this button."])
error_message = "Expected coder_app tooltip to be set when provided"
}
}
run "tooltip_null_when_not_provided" {
run "tooltip_default_when_not_provided" {
command = plan
variables {
@@ -206,8 +206,41 @@ run "tooltip_null_when_not_provided" {
}
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"
condition = anytrue([for app in values(resource.coder_app.jetbrains) : app.tooltip == "You need to install [JetBrains Toolbox App](https://www.jetbrains.com/toolbox-app/) to use this button."])
error_message = "Expected coder_app tooltip to be the default JetBrains Toolbox message when not provided"
}
}
run "channel_eap" {
command = plan
variables {
agent_id = "foo"
folder = "/home/coder"
default = ["GO"]
channel = "eap"
major_version = "latest"
}
assert {
condition = output.ide_metadata["GO"].json_data.type == "eap"
error_message = "Expected the API to return a release of type 'eap', but got '${output.ide_metadata["GO"].json_data.type}'"
}
}
run "specific_major_version" {
command = plan
variables {
agent_id = "foo"
folder = "/home/coder"
default = ["GO"]
major_version = "2025.3"
}
assert {
condition = output.ide_metadata["GO"].json_data.majorVersion == "2025.3"
error_message = "Expected the API to return a release for major version '2025.3', but got '${output.ide_metadata["GO"].json_data.majorVersion}'"
}
}
@@ -294,3 +327,27 @@ run "output_multiple_ides" {
error_message = "Expected ide_metadata['PY'].build to be the fallback '${var.expected_ide_config["PY"].build}'"
}
}
run "validate_output_schema" {
command = plan
variables {
agent_id = "foo"
folder = "/home/coder"
default = ["GO"]
}
assert {
condition = alltrue([
for key, meta in output.ide_metadata : (
can(meta.icon) &&
can(meta.name) &&
can(meta.identifier) &&
can(meta.key) &&
can(meta.build) &&
# json_data can be null, but the key must exist
can(meta.json_data)
)
])
error_message = "The ide_metadata output schema has changed. Please update the 'main.tf' and this test."
}
}
File diff suppressed because it is too large Load Diff
+33 -22
View File
@@ -62,7 +62,7 @@ variable "coder_parameter_order" {
variable "tooltip" {
type = string
description = "Markdown text that is displayed when hovering over workspace apps."
default = null
default = "You need to install [JetBrains Toolbox App](https://www.jetbrains.com/toolbox-app/) to use this button."
}
variable "major_version" {
@@ -70,8 +70,8 @@ variable "major_version" {
description = "The major version of the IDE. i.e. 2025.1"
default = "latest"
validation {
condition = can(regex("^[0-9]{4}\\.[0-2]{1}$", var.major_version)) || var.major_version == "latest"
error_message = "The major_version must be a valid version number. i.e. 2025.1 or latest"
condition = can(regex("^[0-9]{4}\\.[1-3]$", var.major_version)) || var.major_version == "latest"
error_message = "The major_version must be a valid version number (e.g., 2025.1) or 'latest'"
}
}
@@ -126,7 +126,7 @@ variable "download_base_link" {
data "http" "jetbrains_ide_versions" {
for_each = length(var.default) == 0 ? var.options : var.default
url = "${var.releases_base_link}/products/releases?code=${each.key}&type=${var.channel}&latest=true${var.major_version == "latest" ? "" : "&major_version=${var.major_version}"}"
url = "${var.releases_base_link}/products/releases?code=${each.key}&type=${var.channel}${var.major_version == "latest" ? "&latest=true" : ""}"
}
variable "ide_config" {
@@ -138,9 +138,9 @@ variable "ide_config" {
- build: The build number of the IDE.
Example:
{
"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" },
"CL" = { name = "CLion", icon = "/icon/clion.svg", build = "253.29346.141" },
"GO" = { name = "GoLand", icon = "/icon/goland.svg", build = "253.28294.337" },
"IU" = { name = "IntelliJ IDEA", icon = "/icon/intellij.svg", build = "253.29346.138" },
}
EOT
type = map(object({
@@ -149,15 +149,15 @@ variable "ide_config" {
build = string
}))
default = {
"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" }
"CL" = { name = "CLion", icon = "/icon/clion.svg", build = "253.29346.141" },
"GO" = { name = "GoLand", icon = "/icon/goland.svg", build = "253.28294.337" },
"IU" = { name = "IntelliJ IDEA", icon = "/icon/intellij.svg", build = "253.29346.138" },
"PS" = { name = "PhpStorm", icon = "/icon/phpstorm.svg", build = "253.29346.151" },
"PY" = { name = "PyCharm", icon = "/icon/pycharm.svg", build = "253.29346.142" },
"RD" = { name = "Rider", icon = "/icon/rider.svg", build = "253.29346.144" },
"RM" = { name = "RubyMine", icon = "/icon/rubymine.svg", build = "253.29346.140" },
"RR" = { name = "RustRover", icon = "/icon/rustrover.svg", build = "253.29346.139" },
"WS" = { name = "WebStorm", icon = "/icon/webstorm.svg", build = "253.29346.143" }
}
validation {
condition = length(var.ide_config) > 0
@@ -182,6 +182,20 @@ locals {
)
}
# Filter the parsed response for the requested major version if not "latest"
filtered_releases = {
for code in length(var.default) == 0 ? var.options : var.default : code => [
for r in try(local.parsed_responses[code][keys(local.parsed_responses[code])[0]], []) :
r if var.major_version == "latest" || r.majorVersion == var.major_version
]
}
# Select the latest release for the requested major version (first item in the filtered list)
selected_releases = {
for code in length(var.default) == 0 ? var.options : var.default : code =>
length(local.filtered_releases[code]) > 0 ? local.filtered_releases[code][0] : null
}
# Dynamically generate IDE configurations based on options with fallback to ide_config
options_metadata = {
for code in length(var.default) == 0 ? var.options : var.default : code => {
@@ -191,13 +205,10 @@ locals {
key = code
# Use API build number if available, otherwise fall back to ide_config build number
build = length(keys(local.parsed_responses[code])) > 0 ? (
local.parsed_responses[code][keys(local.parsed_responses[code])[0]][0].build
) : var.ide_config[code].build
build = local.selected_releases[code] != null ? local.selected_releases[code].build : var.ide_config[code].build
# Store API data for potential future use (only if API is available)
json_data = length(keys(local.parsed_responses[code])) > 0 ? local.parsed_responses[code][keys(local.parsed_responses[code])[0]][0] : null
response_key = length(keys(local.parsed_responses[code])) > 0 ? keys(local.parsed_responses[code])[0] : null
# Store API data for potential future use
json_data = local.selected_releases[code]
}
}