From 0153119e95ecf0be7b5e126498fd3357ffdbf501 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Tue, 21 Oct 2025 17:15:37 +0000 Subject: [PATCH 1/6] feat: add order to coder_metadata --- provider/metadata.go | 6 ++++++ provider/metadata_test.go | 2 ++ 2 files changed, 8 insertions(+) diff --git a/provider/metadata.go b/provider/metadata.go index 5ed6d478..45622868 100644 --- a/provider/metadata.go +++ b/provider/metadata.go @@ -103,6 +103,12 @@ func metadataResource() *schema.Resource { ForceNew: true, Computed: true, }, + "order": { + Type: schema.TypeInt, + Description: "The order in which this item will be displayed relative to other items. Lower numbers appear first.", + ForceNew: true, + Computed: true, + }, }, }, }, diff --git a/provider/metadata_test.go b/provider/metadata_test.go index 3164e65b..a467fb16 100644 --- a/provider/metadata_test.go +++ b/provider/metadata_test.go @@ -30,6 +30,7 @@ func TestMetadata(t *testing.T) { item { key = "foo" value = "bar" + order = 4 } item { key = "secret" @@ -66,6 +67,7 @@ func TestMetadata(t *testing.T) { "item.0.key": "foo", "item.0.value": "bar", "item.0.sensitive": "false", + "item.0.order": "4", "item.1.key": "secret", "item.1.value": "squirrel", "item.1.sensitive": "true", From 51a268534731733a88c3b01bc04d9f95117df1c3 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Tue, 21 Oct 2025 17:18:15 +0000 Subject: [PATCH 2/6] improve description --- provider/metadata.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider/metadata.go b/provider/metadata.go index 45622868..45b14d29 100644 --- a/provider/metadata.go +++ b/provider/metadata.go @@ -105,7 +105,7 @@ func metadataResource() *schema.Resource { }, "order": { Type: schema.TypeInt, - Description: "The order in which this item will be displayed relative to other items. Lower numbers appear first.", + Description: "The order determines the position of item in the UI presentation. The lowest order is shown first and items with equal order are sorted by key (ascending order).", ForceNew: true, Computed: true, }, From 9716cd31846c0bdcf23ef282751d4293e37df47e Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Wed, 22 Oct 2025 13:12:25 +0000 Subject: [PATCH 3/6] replace computed field --- provider/metadata.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider/metadata.go b/provider/metadata.go index 45b14d29..b70bb451 100644 --- a/provider/metadata.go +++ b/provider/metadata.go @@ -107,7 +107,7 @@ func metadataResource() *schema.Resource { Type: schema.TypeInt, Description: "The order determines the position of item in the UI presentation. The lowest order is shown first and items with equal order are sorted by key (ascending order).", ForceNew: true, - Computed: true, + Optional: true, }, }, }, From db2d0cb1a292a984ca18beaa82cd1d8d3c0b1478 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Wed, 22 Oct 2025 17:08:25 +0000 Subject: [PATCH 4/6] make gen --- docs/resources/metadata.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/resources/metadata.md b/docs/resources/metadata.md index d8329ea9..f815a0d1 100644 --- a/docs/resources/metadata.md +++ b/docs/resources/metadata.md @@ -84,6 +84,7 @@ Required: Optional: +- `order` (Number) The order determines the position of item in the UI presentation. The lowest order is shown first and items with equal order are sorted by key (ascending order). - `sensitive` (Boolean) Set to `true` to for items such as API keys whose values should be hidden from view by default. Note that this does not prevent metadata from being retrieved using the API, so it is not suitable for secrets that should not be exposed to workspace users. - `value` (String) The value of this metadata item. Supports basic Markdown, including hyperlinks. From a7da0554061511096d52d13afa631682d270c701 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Thu, 23 Oct 2025 16:21:48 +0000 Subject: [PATCH 5/6] fix test --- docs/resources/metadata.md | 3 +++ examples/resources/coder_metadata/resource.tf | 3 +++ provider/metadata_test.go | 11 +++++++++-- provider/provider.go | 11 +++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/resources/metadata.md b/docs/resources/metadata.md index f815a0d1..cbf9d288 100644 --- a/docs/resources/metadata.md +++ b/docs/resources/metadata.md @@ -43,16 +43,19 @@ resource "coder_metadata" "pod_info" { item { key = "description" value = "This description will show up in the Coder dashboard." + order = 1 } item { key = "pod_uid" value = kubernetes_pod.dev[0].uid + order = 2 } item { key = "public_key" value = tls_private_key.example_key_pair.public_key_openssh # The value of this item will be hidden from view by default sensitive = true + order = 3 } } ``` diff --git a/examples/resources/coder_metadata/resource.tf b/examples/resources/coder_metadata/resource.tf index 0491ce57..b73f6427 100644 --- a/examples/resources/coder_metadata/resource.tf +++ b/examples/resources/coder_metadata/resource.tf @@ -25,15 +25,18 @@ resource "coder_metadata" "pod_info" { item { key = "description" value = "This description will show up in the Coder dashboard." + order = 1 } item { key = "pod_uid" value = kubernetes_pod.dev[0].uid + order = 2 } item { key = "public_key" value = tls_private_key.example_key_pair.public_key_openssh # The value of this item will be hidden from view by default sensitive = true + order = 3 } } diff --git a/provider/metadata_test.go b/provider/metadata_test.go index a467fb16..5dbd31e0 100644 --- a/provider/metadata_test.go +++ b/provider/metadata_test.go @@ -30,23 +30,26 @@ func TestMetadata(t *testing.T) { item { key = "foo" value = "bar" - order = 4 } item { key = "secret" value = "squirrel" sensitive = true + order = 1 } item { key = "implicit_null" + order = 2 } item { key = "explicit_null" value = null + order = 3 } item { key = "empty" value = "" + order = 4 } } `, @@ -67,20 +70,24 @@ func TestMetadata(t *testing.T) { "item.0.key": "foo", "item.0.value": "bar", "item.0.sensitive": "false", - "item.0.order": "4", + "item.0.order": "0", "item.1.key": "secret", "item.1.value": "squirrel", "item.1.sensitive": "true", + "item.1.order": "1", "item.2.key": "implicit_null", "item.2.is_null": "true", "item.2.sensitive": "false", + "item.2.order": "2", "item.3.key": "explicit_null", "item.3.is_null": "true", "item.3.sensitive": "false", + "item.3.order": "3", "item.4.key": "empty", "item.4.value": "", "item.4.is_null": "false", "item.4.sensitive": "false", + "item.4.order": "4", } { require.Equal(t, expected, metadata.Primary.Attributes[key]) } diff --git a/provider/provider.go b/provider/provider.go index 2b6409ba..72c8f6ba 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/go-cty/cty/gocty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "golang.org/x/xerrors" @@ -103,6 +104,7 @@ func populateIsNull(resourceData *schema.ResourceData) (result interface{}, err "key": key, "value": valueAsString(item.GetAttr("value")), "sensitive": valueAsBool(item.GetAttr("sensitive")), + "order": valueAsInt(item.GetAttr("order")), } if item.GetAttr("value").IsNull() { resultItem["is_null"] = true @@ -132,6 +134,15 @@ func valueAsBool(value cty.Value) interface{} { return value.True() } +func valueAsInt(value cty.Value) interface{} { + if value.IsNull() { + return nil + } + var valueAsInt int64 + gocty.FromCtyValue(value, &valueAsInt) + return valueAsInt +} + // errorAsDiagnostic transforms a Go error to a diag.Diagnostics object representing a fatal error. func errorAsDiagnostics(err error) diag.Diagnostics { return []diag.Diagnostic{{ From 5e47b1dbaf36e2e80806b5fc12654a7b0ffa845f Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Thu, 23 Oct 2025 17:48:19 +0000 Subject: [PATCH 6/6] handle parse error --- provider/provider.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/provider/provider.go b/provider/provider.go index 72c8f6ba..bbcfebf9 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -100,11 +100,16 @@ func populateIsNull(resourceData *schema.ResourceData) (result interface{}, err var resultItems []interface{} for _, item := range items { key := valueAsString(item.GetAttr("key")) + order, err := valueAsInt(item.GetAttr("order")) + if err != nil { + return nil, xerrors.Errorf("unable to parse order for coder_metadata item %q: %w", key, err) + } + resultItem := map[string]interface{}{ "key": key, "value": valueAsString(item.GetAttr("value")), "sensitive": valueAsBool(item.GetAttr("sensitive")), - "order": valueAsInt(item.GetAttr("order")), + "order": order, } if item.GetAttr("value").IsNull() { resultItem["is_null"] = true @@ -134,13 +139,13 @@ func valueAsBool(value cty.Value) interface{} { return value.True() } -func valueAsInt(value cty.Value) interface{} { +func valueAsInt(value cty.Value) (interface{}, error) { if value.IsNull() { - return nil + return nil, nil } var valueAsInt int64 - gocty.FromCtyValue(value, &valueAsInt) - return valueAsInt + err := gocty.FromCtyValue(value, &valueAsInt) + return valueAsInt, err } // errorAsDiagnostic transforms a Go error to a diag.Diagnostics object representing a fatal error.