Skip to content

Commit c9a6321

Browse files
committed
feat: add icon and description fields to workspace preset
1 parent f239e51 commit c9a6321

File tree

5 files changed

+88
-5
lines changed

5 files changed

+88
-5
lines changed

docs/data-sources/workspace_preset.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ data "coder_workspace_preset" "standard" {
4949
### Optional
5050

5151
- `default` (Boolean) Whether this preset should be selected by default when creating a workspace. Only one preset per template can be marked as default.
52+
- `description` (String) Describe what this preset does.
53+
- `icon` (String) A URL to an icon that will display in the dashboard. View built-in icons [here](https://github.com/coder/coder/tree/main/site/static/icon). Use a built-in icon with `"${data.coder_workspace.me.access_url}/icon/<path>"`.
5254
- `parameters` (Map of String) Workspace parameters that will be set by the workspace preset. For simple templates that only need prebuilds, you may define a preset with zero parameters. Because workspace parameters may change between Coder template versions, preset parameters are allowed to define values for parameters that do not exist in the current template version.
5355
- `prebuilds` (Block Set, Max: 1) Configuration for prebuilt workspaces associated with this preset. Coder will maintain a pool of standby workspaces based on this configuration. When a user creates a workspace using this preset, they are assigned a prebuilt workspace instead of waiting for a new one to build. See prebuilt workspace documentation [here](https://coder.com/docs/admin/templates/extending-templates/prebuilt-workspaces.md) (see [below for nested schema](#nestedblock--prebuilds))
5456

integration/integration_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ func TestIntegration(t *testing.T) {
9393
"workspace_parameter.value": `param value`,
9494
"workspace_parameter.icon": `param icon`,
9595
"workspace_preset.name": `preset`,
96+
"workspace_preset.description": `preset description`,
97+
"workspace_preset.icon": `preset icon`,
9698
"workspace_preset.default": `true`,
9799
"workspace_preset.parameters.param": `preset param value`,
98100
"workspace_preset.prebuilds.instances": `1`,

integration/test-data-source/main.tf

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ data "coder_parameter" "param" {
2020
icon = "param icon"
2121
}
2222
data "coder_workspace_preset" "preset" {
23-
name = "preset"
24-
default = true
23+
name = "preset"
24+
description = "preset description"
25+
icon = "preset icon"
26+
default = true
2527
parameters = {
2628
(data.coder_parameter.param.name) = "preset param value"
2729
}
@@ -65,6 +67,8 @@ locals {
6567
"workspace_parameter.value" : data.coder_parameter.param.value,
6668
"workspace_parameter.icon" : data.coder_parameter.param.icon,
6769
"workspace_preset.name" : data.coder_workspace_preset.preset.name,
70+
"workspace_preset.description" : data.coder_workspace_preset.preset.description,
71+
"workspace_preset.icon" : data.coder_workspace_preset.preset.icon,
6872
"workspace_preset.default" : tostring(data.coder_workspace_preset.preset.default),
6973
"workspace_preset.parameters.param" : data.coder_workspace_preset.preset.parameters.param,
7074
"workspace_preset.prebuilds.instances" : tostring(one(data.coder_workspace_preset.preset.prebuilds).instances),

provider/workspace_preset.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package provider
33
import (
44
"context"
55
"fmt"
6+
"net/url"
67
"strings"
78
"time"
89

@@ -18,9 +19,11 @@ import (
1819
var PrebuildsCRONParser = rbcron.NewParser(rbcron.Minute | rbcron.Hour | rbcron.Dom | rbcron.Month | rbcron.Dow)
1920

2021
type WorkspacePreset struct {
21-
Name string `mapstructure:"name"`
22-
Default bool `mapstructure:"default"`
23-
Parameters map[string]string `mapstructure:"parameters"`
22+
Name string `mapstructure:"name"`
23+
Description string `mapstructure:"description"`
24+
Icon string `mapstructure:"icon"`
25+
Default bool `mapstructure:"default"`
26+
Parameters map[string]string `mapstructure:"parameters"`
2427
// There should always be only one prebuild block, but Terraform's type system
2528
// still parses them as a slice, so we need to handle it as such. We could use
2629
// an anonymous type and rd.Get to avoid a slice here, but that would not be possible
@@ -93,6 +96,29 @@ func workspacePresetDataSource() *schema.Resource {
9396
Required: true,
9497
ValidateFunc: validation.StringIsNotEmpty,
9598
},
99+
"description": {
100+
Type: schema.TypeString,
101+
Optional: true,
102+
Description: "Describe what this preset does.",
103+
},
104+
"icon": {
105+
Type: schema.TypeString,
106+
Description: "A URL to an icon that will display in the dashboard. View built-in " +
107+
"icons [here](https://github.com/coder/coder/tree/main/site/static/icon). Use a " +
108+
"built-in icon with `\"${data.coder_workspace.me.access_url}/icon/<path>\"`.",
109+
ForceNew: true,
110+
Optional: true,
111+
ValidateFunc: func(value interface{}, label string) ([]string, []error) {
112+
val, ok := value.(string)
113+
if !ok {
114+
return nil, []error{fmt.Errorf("expected %q to be a string", label)}
115+
}
116+
if _, err := url.Parse(val); err != nil {
117+
return nil, []error{err}
118+
}
119+
return nil, nil
120+
},
121+
},
96122
"default": {
97123
Type: schema.TypeBool,
98124
Description: "Whether this preset should be selected by default when creating a workspace. Only one preset per template can be marked as default.",

provider/workspace_preset_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ func TestWorkspacePreset(t *testing.T) {
2323
Config: `
2424
data "coder_workspace_preset" "preset_1" {
2525
name = "preset_1"
26+
description = <<-EOT
27+
# Select the machine image
28+
See the [registry](https://container.registry.blah/namespace) for options.
29+
EOT
30+
icon = "/icon/region.svg"
2631
parameters = {
2732
"region" = "us-east1-a"
2833
}
@@ -34,6 +39,8 @@ func TestWorkspacePreset(t *testing.T) {
3439
require.NotNil(t, resource)
3540
attrs := resource.Primary.Attributes
3641
require.Equal(t, attrs["name"], "preset_1")
42+
require.Equal(t, attrs["description"], "# Select the machine image\nSee the [registry](https://container.registry.blah/namespace) for options.\n")
43+
require.Equal(t, attrs["icon"], "/icon/region.svg")
3744
require.Equal(t, attrs["parameters.region"], "us-east1-a")
3845
return nil
3946
},
@@ -76,6 +83,48 @@ func TestWorkspacePreset(t *testing.T) {
7683
// So we test it here to make sure we don't regress.
7784
ExpectError: regexp.MustCompile("Incorrect attribute value type"),
7885
},
86+
{
87+
Name: "Description field is empty",
88+
Config: `
89+
data "coder_workspace_preset" "preset_1" {
90+
name = "preset_1"
91+
description = ""
92+
parameters = {
93+
"region" = "us-east1-a"
94+
}
95+
}`,
96+
// This validation is done by Terraform, but it could still break if we misconfigure the schema.
97+
// So we test it here to make sure we don't regress.
98+
ExpectError: nil,
99+
},
100+
{
101+
Name: "Icon field is empty",
102+
Config: `
103+
data "coder_workspace_preset" "preset_1" {
104+
name = "preset_1"
105+
icon = ""
106+
parameters = {
107+
"region" = "us-east1-a"
108+
}
109+
}`,
110+
// This validation is done by Terraform, but it could still break if we misconfigure the schema.
111+
// So we test it here to make sure we don't regress.
112+
ExpectError: nil,
113+
},
114+
{
115+
Name: "Icon field is an invalid URL",
116+
Config: `
117+
data "coder_workspace_preset" "preset_1" {
118+
name = "preset_1"
119+
icon = "/icon%.svg"
120+
parameters = {
121+
"region" = "us-east1-a"
122+
}
123+
}`,
124+
// This validation is done by Terraform, but it could still break if we misconfigure the schema.
125+
// So we test it here to make sure we don't regress.
126+
ExpectError: regexp.MustCompile("invalid URL escape"),
127+
},
79128
{
80129
Name: "Parameters field is not provided",
81130
Config: `

0 commit comments

Comments
 (0)