Skip to content

Commit cd7945d

Browse files
feat: add 'hidden' field to 'coder_app' provider (#276)
* feat: add 'hidden' field to 'coder_app' provider * fix: run 'make gen' * test: add integration test for 'coder_app.hidden' * fix: warn on 'hidden' being used with conflicting fields
1 parent 0da135c commit cd7945d

File tree

5 files changed

+182
-1
lines changed

5 files changed

+182
-1
lines changed

docs/resources/app.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ resource "coder_app" "vim" {
6363
- `display_name` (String) A display name to identify the app. Defaults to the slug.
6464
- `external` (Boolean) Specifies whether `url` is opened on the client machine instead of proxied through the workspace.
6565
- `healthcheck` (Block Set, Max: 1) HTTP health checking to determine the application readiness. (see [below for nested schema](#nestedblock--healthcheck))
66+
- `hidden` (Boolean) Determines if the app is visible in the UI.
6667
- `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>"`.
6768
- `order` (Number) The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order).
6869
- `share` (String) Determines the level which the application is shared at. Valid levels are `"owner"` (default), `"authenticated"` and `"public"`. Level `"owner"` disables sharing on the app, so only the workspace owner can access it. Level `"authenticated"` shares the app with all authenticated users. Level `"public"` shares it with any user, including unauthenticated users. Permitted application sharing levels can be configured site-wide via a flag on `coder server` (Enterprise only).

integration/coder-app-hidden/main.tf

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
terraform {
2+
required_providers {
3+
coder = {
4+
source = "coder/coder"
5+
}
6+
local = {
7+
source = "hashicorp/local"
8+
}
9+
}
10+
}
11+
12+
data "coder_workspace" "me" {}
13+
14+
resource "coder_agent" "dev" {
15+
os = "linux"
16+
arch = "amd64"
17+
dir = "/workspace"
18+
}
19+
20+
resource "coder_app" "hidden" {
21+
agent_id = coder_agent.dev.id
22+
slug = "hidden"
23+
share = "owner"
24+
hidden = true
25+
}
26+
27+
resource "coder_app" "visible" {
28+
agent_id = coder_agent.dev.id
29+
slug = "visible"
30+
share = "owner"
31+
hidden = false
32+
}
33+
34+
resource "coder_app" "defaulted" {
35+
agent_id = coder_agent.dev.id
36+
slug = "defaulted"
37+
share = "owner"
38+
}
39+
40+
locals {
41+
# NOTE: these must all be strings in the output
42+
output = {
43+
"coder_app.hidden.hidden" = tostring(coder_app.hidden.hidden)
44+
"coder_app.visible.hidden" = tostring(coder_app.visible.hidden)
45+
"coder_app.defaulted.hidden" = tostring(coder_app.defaulted.hidden)
46+
}
47+
}
48+
49+
variable "output_path" {
50+
type = string
51+
}
52+
53+
resource "local_file" "output" {
54+
filename = var.output_path
55+
content = jsonencode(local.output)
56+
}
57+
58+
output "output" {
59+
value = local.output
60+
sensitive = true
61+
}
62+

integration/integration_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ func TestIntegration(t *testing.T) {
114114
"workspace_owner.ssh_public_key": `(?s)^ssh-ed25519.+$`,
115115
},
116116
},
117+
{
118+
name: "coder-app-hidden",
119+
minVersion: "v0.0.0",
120+
expectedOutput: map[string]string{
121+
"coder_app.hidden.hidden": "true",
122+
"coder_app.visible.hidden": "false",
123+
"coder_app.defaulted.hidden": "false",
124+
},
125+
},
117126
} {
118127
tt := tt
119128
t.Run(tt.name, func(t *testing.T) {

provider/app.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,36 @@ func appResource() *schema.Resource {
3030
Description: "Use this resource to define shortcuts to access applications in a workspace.",
3131
CreateContext: func(c context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
3232
resourceData.SetId(uuid.NewString())
33-
return nil
33+
34+
diags := diag.Diagnostics{}
35+
36+
hiddenData := resourceData.Get("hidden")
37+
if hidden, ok := hiddenData.(bool); !ok {
38+
return diag.Errorf("hidden should be a bool")
39+
} else if hidden {
40+
if _, ok := resourceData.GetOk("display_name"); ok {
41+
diags = append(diags, diag.Diagnostic{
42+
Severity: diag.Warning,
43+
Summary: "`display_name` set when app is hidden",
44+
})
45+
}
46+
47+
if _, ok := resourceData.GetOk("icon"); ok {
48+
diags = append(diags, diag.Diagnostic{
49+
Severity: diag.Warning,
50+
Summary: "`icon` set when app is hidden",
51+
})
52+
}
53+
54+
if _, ok := resourceData.GetOk("order"); ok {
55+
diags = append(diags, diag.Diagnostic{
56+
Severity: diag.Warning,
57+
Summary: "`order` set when app is hidden",
58+
})
59+
}
60+
}
61+
62+
return diags
3463
},
3564
ReadContext: func(c context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
3665
return nil
@@ -187,6 +216,13 @@ func appResource() *schema.Resource {
187216
ForceNew: true,
188217
Optional: true,
189218
},
219+
"hidden": {
220+
Type: schema.TypeBool,
221+
Description: "Determines if the app is visible in the UI.",
222+
Default: false,
223+
ForceNew: true,
224+
Optional: true,
225+
},
190226
},
191227
}
192228
}

provider/app_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func TestApp(t *testing.T) {
4545
threshold = 6
4646
}
4747
order = 4
48+
hidden = false
4849
}
4950
`,
5051
Check: func(state *terraform.State) error {
@@ -66,6 +67,7 @@ func TestApp(t *testing.T) {
6667
"healthcheck.0.interval",
6768
"healthcheck.0.threshold",
6869
"order",
70+
"hidden",
6971
} {
7072
value := resource.Primary.Attributes[key]
7173
t.Logf("%q = %q", key, value)
@@ -246,4 +248,75 @@ func TestApp(t *testing.T) {
246248
})
247249
}
248250
})
251+
252+
t.Run("Hidden", func(t *testing.T) {
253+
t.Parallel()
254+
255+
cases := []struct {
256+
name string
257+
config string
258+
hidden bool
259+
}{{
260+
name: "Is Hidden",
261+
config: `
262+
provider "coder" {}
263+
resource "coder_agent" "dev" {
264+
os = "linux"
265+
arch = "amd64"
266+
}
267+
resource "coder_app" "test" {
268+
agent_id = coder_agent.dev.id
269+
slug = "test"
270+
display_name = "Testing"
271+
url = "https://google.com"
272+
external = true
273+
hidden = true
274+
}
275+
`,
276+
hidden: true,
277+
}, {
278+
name: "Is Not Hidden",
279+
config: `
280+
provider "coder" {}
281+
resource "coder_agent" "dev" {
282+
os = "linux"
283+
arch = "amd64"
284+
}
285+
resource "coder_app" "test" {
286+
agent_id = coder_agent.dev.id
287+
slug = "test"
288+
display_name = "Testing"
289+
url = "https://google.com"
290+
external = true
291+
hidden = false
292+
}
293+
`,
294+
hidden: false,
295+
}}
296+
for _, tc := range cases {
297+
tc := tc
298+
t.Run(tc.name, func(t *testing.T) {
299+
t.Parallel()
300+
resource.Test(t, resource.TestCase{
301+
Providers: map[string]*schema.Provider{
302+
"coder": provider.New(),
303+
},
304+
IsUnitTest: true,
305+
Steps: []resource.TestStep{{
306+
Config: tc.config,
307+
Check: func(state *terraform.State) error {
308+
require.Len(t, state.Modules, 1)
309+
require.Len(t, state.Modules[0].Resources, 2)
310+
resource := state.Modules[0].Resources["coder_app.test"]
311+
require.NotNil(t, resource)
312+
require.Equal(t, strconv.FormatBool(tc.hidden), resource.Primary.Attributes["hidden"])
313+
return nil
314+
},
315+
ExpectError: nil,
316+
}},
317+
})
318+
})
319+
}
320+
})
321+
249322
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy