Skip to content

Commit 1775321

Browse files
committed
fix: Add support for empty/default template fields
1 parent 408e19f commit 1775321

File tree

6 files changed

+116
-50
lines changed

6 files changed

+116
-50
lines changed

cli/templateedit.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ func (r *RootCmd) templateEdit() *serpent.Command {
170170
req := codersdk.UpdateTemplateMeta{
171171
Name: name,
172172
DisplayName: displayName,
173-
Description: description,
174-
Icon: icon,
173+
Description: &description,
174+
Icon: &icon,
175175
DefaultTTLMillis: defaultTTL.Milliseconds(),
176176
ActivityBumpMillis: activityBump.Milliseconds(),
177177
AutostopRequirement: &codersdk.TemplateAutostopRequirement{

coderd/templates.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -770,12 +770,15 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
770770
classicTemplateFlow = *req.UseClassicParameterFlow
771771
}
772772

773+
description := ptr.NilToDefault(req.Description, template.Description)
774+
icon := ptr.NilToDefault(req.Icon, template.Icon)
775+
773776
var updated database.Template
774777
err = api.Database.InTx(func(tx database.Store) error {
775778
if req.Name == template.Name &&
776-
req.Description == template.Description &&
779+
description == template.Description &&
777780
req.DisplayName == template.DisplayName &&
778-
req.Icon == template.Icon &&
781+
icon == template.Icon &&
779782
req.AllowUserAutostart == template.AllowUserAutostart &&
780783
req.AllowUserAutostop == template.AllowUserAutostop &&
781784
req.AllowUserCancelWorkspaceJobs == template.AllowUserCancelWorkspaceJobs &&
@@ -827,8 +830,8 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
827830
UpdatedAt: dbtime.Now(),
828831
Name: name,
829832
DisplayName: req.DisplayName,
830-
Description: req.Description,
831-
Icon: req.Icon,
833+
Description: description,
834+
Icon: icon,
832835
AllowUserCancelWorkspaceJobs: req.AllowUserCancelWorkspaceJobs,
833836
GroupACL: groupACL,
834837
MaxPortSharingLevel: maxPortShareLevel,

coderd/templates_test.go

Lines changed: 86 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -862,8 +862,8 @@ func TestPatchTemplateMeta(t *testing.T) {
862862
req := codersdk.UpdateTemplateMeta{
863863
Name: "new-template-name",
864864
DisplayName: "Displayed Name 456",
865-
Description: "lorem ipsum dolor sit amet et cetera",
866-
Icon: "/icon/new-icon.png",
865+
Description: ptr.Ref("lorem ipsum dolor sit amet et cetera"),
866+
Icon: ptr.Ref("/icon/new-icon.png"),
867867
DefaultTTLMillis: 12 * time.Hour.Milliseconds(),
868868
ActivityBumpMillis: 3 * time.Hour.Milliseconds(),
869869
AllowUserCancelWorkspaceJobs: false,
@@ -879,8 +879,8 @@ func TestPatchTemplateMeta(t *testing.T) {
879879
assert.Greater(t, updated.UpdatedAt, template.UpdatedAt)
880880
assert.Equal(t, req.Name, updated.Name)
881881
assert.Equal(t, req.DisplayName, updated.DisplayName)
882-
assert.Equal(t, req.Description, updated.Description)
883-
assert.Equal(t, req.Icon, updated.Icon)
882+
assert.Equal(t, *req.Description, updated.Description)
883+
assert.Equal(t, *req.Icon, updated.Icon)
884884
assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis)
885885
assert.Equal(t, req.ActivityBumpMillis, updated.ActivityBumpMillis)
886886
assert.False(t, req.AllowUserCancelWorkspaceJobs)
@@ -891,8 +891,8 @@ func TestPatchTemplateMeta(t *testing.T) {
891891
assert.Greater(t, updated.UpdatedAt, template.UpdatedAt)
892892
assert.Equal(t, req.Name, updated.Name)
893893
assert.Equal(t, req.DisplayName, updated.DisplayName)
894-
assert.Equal(t, req.Description, updated.Description)
895-
assert.Equal(t, req.Icon, updated.Icon)
894+
assert.Equal(t, *req.Description, updated.Description)
895+
assert.Equal(t, *req.Icon, updated.Icon)
896896
assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis)
897897
assert.Equal(t, req.ActivityBumpMillis, updated.ActivityBumpMillis)
898898
assert.False(t, req.AllowUserCancelWorkspaceJobs)
@@ -1128,8 +1128,8 @@ func TestPatchTemplateMeta(t *testing.T) {
11281128
got, err := client.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
11291129
Name: template.Name,
11301130
DisplayName: template.DisplayName,
1131-
Description: template.Description,
1132-
Icon: template.Icon,
1131+
Description: &template.Description,
1132+
Icon: &template.Icon,
11331133
DefaultTTLMillis: 0,
11341134
AutostopRequirement: &template.AutostopRequirement,
11351135
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
@@ -1163,8 +1163,8 @@ func TestPatchTemplateMeta(t *testing.T) {
11631163
got, err := client.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
11641164
Name: template.Name,
11651165
DisplayName: template.DisplayName,
1166-
Description: template.Description,
1167-
Icon: template.Icon,
1166+
Description: &template.Description,
1167+
Icon: &template.Icon,
11681168
DefaultTTLMillis: template.DefaultTTLMillis,
11691169
AutostopRequirement: &template.AutostopRequirement,
11701170
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
@@ -1224,8 +1224,8 @@ func TestPatchTemplateMeta(t *testing.T) {
12241224
got, err := client.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
12251225
Name: template.Name,
12261226
DisplayName: template.DisplayName,
1227-
Description: template.Description,
1228-
Icon: template.Icon,
1227+
Description: &template.Description,
1228+
Icon: &template.Icon,
12291229
DefaultTTLMillis: template.DefaultTTLMillis,
12301230
AutostopRequirement: &template.AutostopRequirement,
12311231
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
@@ -1255,8 +1255,8 @@ func TestPatchTemplateMeta(t *testing.T) {
12551255
got, err := client.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
12561256
Name: template.Name,
12571257
DisplayName: template.DisplayName,
1258-
Description: template.Description,
1259-
Icon: template.Icon,
1258+
Description: &template.Description,
1259+
Icon: &template.Icon,
12601260
// Increase the default TTL to avoid error "not modified".
12611261
DefaultTTLMillis: template.DefaultTTLMillis + 1,
12621262
AutostopRequirement: &template.AutostopRequirement,
@@ -1286,8 +1286,8 @@ func TestPatchTemplateMeta(t *testing.T) {
12861286

12871287
req := codersdk.UpdateTemplateMeta{
12881288
Name: template.Name,
1289-
Description: template.Description,
1290-
Icon: template.Icon,
1289+
Description: &template.Description,
1290+
Icon: &template.Icon,
12911291
DefaultTTLMillis: template.DefaultTTLMillis,
12921292
ActivityBumpMillis: template.ActivityBumpMillis,
12931293
AutostopRequirement: nil,
@@ -1347,7 +1347,7 @@ func TestPatchTemplateMeta(t *testing.T) {
13471347
ctr.Icon = "/icon/code.png"
13481348
})
13491349
req := codersdk.UpdateTemplateMeta{
1350-
Icon: "",
1350+
Icon: ptr.Ref(""),
13511351
}
13521352

13531353
ctx := testutil.Context(t, testutil.WaitLong)
@@ -1403,8 +1403,8 @@ func TestPatchTemplateMeta(t *testing.T) {
14031403
req := codersdk.UpdateTemplateMeta{
14041404
Name: template.Name,
14051405
DisplayName: template.DisplayName,
1406-
Description: template.Description,
1407-
Icon: template.Icon,
1406+
Description: &template.Description,
1407+
Icon: &template.Icon,
14081408
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
14091409
DefaultTTLMillis: time.Hour.Milliseconds(),
14101410
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
@@ -1480,8 +1480,8 @@ func TestPatchTemplateMeta(t *testing.T) {
14801480
req := codersdk.UpdateTemplateMeta{
14811481
Name: template.Name,
14821482
DisplayName: template.DisplayName,
1483-
Description: template.Description,
1484-
Icon: template.Icon,
1483+
Description: &template.Description,
1484+
Icon: &template.Icon,
14851485
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
14861486
DefaultTTLMillis: time.Hour.Milliseconds(),
14871487
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
@@ -1517,8 +1517,8 @@ func TestPatchTemplateMeta(t *testing.T) {
15171517
req := codersdk.UpdateTemplateMeta{
15181518
Name: template.Name,
15191519
DisplayName: template.DisplayName,
1520-
Description: template.Description,
1521-
Icon: template.Icon,
1520+
Description: &template.Description,
1521+
Icon: &template.Icon,
15221522
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
15231523
DefaultTTLMillis: time.Hour.Milliseconds(),
15241524
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
@@ -1578,6 +1578,69 @@ func TestPatchTemplateMeta(t *testing.T) {
15781578
require.NoError(t, err)
15791579
assert.False(t, updated.UseClassicParameterFlow, "expected false")
15801580
})
1581+
1582+
t.Run("SupportEmptyOrDefault", func(t *testing.T) {
1583+
t.Parallel()
1584+
1585+
client := coderdtest.New(t, nil)
1586+
user := coderdtest.CreateFirstUser(t, client)
1587+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
1588+
1589+
description := "test-description"
1590+
icon := "/icon/icon.png"
1591+
defaultTTLMillis := 10 * time.Hour.Milliseconds()
1592+
1593+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
1594+
ctr.Description = description
1595+
ctr.Icon = icon
1596+
ctr.DefaultTTLMillis = ptr.Ref(defaultTTLMillis)
1597+
})
1598+
1599+
restoreReq := codersdk.UpdateTemplateMeta{
1600+
Description: &description,
1601+
Icon: &icon,
1602+
DefaultTTLMillis: defaultTTLMillis,
1603+
}
1604+
1605+
type expected struct {
1606+
description string
1607+
icon string
1608+
defaultTTLMillis int64
1609+
}
1610+
1611+
type testCase struct {
1612+
name string
1613+
req codersdk.UpdateTemplateMeta
1614+
expected expected
1615+
}
1616+
1617+
tests := []testCase{
1618+
{name: "Only update default_ttl_ms", req: codersdk.UpdateTemplateMeta{DefaultTTLMillis: 99 * time.Hour.Milliseconds()}, expected: expected{description: template.Description, icon: template.Icon, defaultTTLMillis: 99 * time.Hour.Milliseconds()}},
1619+
{name: "Clear description", req: codersdk.UpdateTemplateMeta{Description: ptr.Ref("")}, expected: expected{description: "", icon: template.Icon, defaultTTLMillis: 0}},
1620+
{name: "Clear icon", req: codersdk.UpdateTemplateMeta{Icon: ptr.Ref("")}, expected: expected{description: template.Description, icon: "", defaultTTLMillis: 0}},
1621+
{name: "Nil description defaults to template description", req: codersdk.UpdateTemplateMeta{Description: nil}, expected: expected{description: template.Description, icon: template.Icon, defaultTTLMillis: 0}},
1622+
{name: "Nil icon defaults to template icon", req: codersdk.UpdateTemplateMeta{Icon: nil}, expected: expected{description: template.Description, icon: template.Icon, defaultTTLMillis: 0}},
1623+
}
1624+
1625+
// It is unfortunate we need to sleep, but the test can fail if the
1626+
// updatedAt is too close together.
1627+
time.Sleep(time.Millisecond * 5)
1628+
1629+
for _, tc := range tests {
1630+
t.Run(tc.name, func(t *testing.T) {
1631+
ctx := testutil.Context(t, testutil.WaitLong)
1632+
updated, err := client.UpdateTemplateMeta(ctx, template.ID, tc.req)
1633+
require.NoError(t, err)
1634+
assert.Equal(t, tc.expected.description, updated.Description)
1635+
assert.Equal(t, tc.expected.icon, updated.Icon)
1636+
assert.Equal(t, tc.expected.defaultTTLMillis, updated.DefaultTTLMillis)
1637+
1638+
// Restore template after each test case
1639+
_, err = client.UpdateTemplateMeta(ctx, template.ID, restoreReq)
1640+
require.NoError(t, err)
1641+
})
1642+
}
1643+
})
15811644
}
15821645

15831646
func TestDeleteTemplate(t *testing.T) {

codersdk/templates.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,11 @@ type ACLAvailable struct {
208208
}
209209

210210
type UpdateTemplateMeta struct {
211-
Name string `json:"name,omitempty" validate:"omitempty,template_name"`
212-
DisplayName string `json:"display_name,omitempty" validate:"omitempty,template_display_name"`
213-
Description string `json:"description,omitempty"`
214-
Icon string `json:"icon,omitempty"`
215-
DefaultTTLMillis int64 `json:"default_ttl_ms,omitempty"`
211+
Name string `json:"name,omitempty" validate:"omitempty,template_name"`
212+
DisplayName string `json:"display_name,omitempty" validate:"omitempty,template_display_name"`
213+
Description *string `json:"description,omitempty"`
214+
Icon *string `json:"icon,omitempty"`
215+
DefaultTTLMillis int64 `json:"default_ttl_ms,omitempty"`
216216
// ActivityBumpMillis allows optionally specifying the activity bump
217217
// duration for all workspaces created from this template. Defaults to 1h
218218
// but can be set to 0 to disable activity bumping.

enterprise/cli/templateedit_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,8 @@ func TestTemplateEdit(t *testing.T) {
178178
var (
179179
expectedName = "template"
180180
expectedDisplayName = "template_display"
181-
expectedDescription = "My description"
182-
expectedIcon = "icon.pjg"
181+
expectedDescription = ptr.Ref("My description")
182+
expectedIcon = ptr.Ref("icon.pjg")
183183
expectedDefaultTTLMillis = time.Hour.Milliseconds()
184184
expectedAllowAutostart = false
185185
expectedAllowAutostop = false

enterprise/coderd/templates_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,8 @@ func TestTemplates(t *testing.T) {
262262
updated, err := anotherClient.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
263263
Name: template.Name,
264264
DisplayName: template.DisplayName,
265-
Description: template.Description,
266-
Icon: template.Icon,
265+
Description: &template.Description,
266+
Icon: &template.Icon,
267267
AutostartRequirement: &codersdk.TemplateAutostartRequirement{
268268
DaysOfWeek: []string{"monday", "saturday"},
269269
},
@@ -279,8 +279,8 @@ func TestTemplates(t *testing.T) {
279279
updated, err = anotherClient.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
280280
Name: template.Name,
281281
DisplayName: template.DisplayName,
282-
Description: template.Description,
283-
Icon: template.Icon + "something",
282+
Description: &template.Description,
283+
Icon: ptr.Ref(template.Icon + "something"),
284284
})
285285
require.NoError(t, err)
286286
require.Equal(t, []string{"monday", "saturday"}, updated.AutostartRequirement.DaysOfWeek)
@@ -316,8 +316,8 @@ func TestTemplates(t *testing.T) {
316316
_, err := anotherClient.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
317317
Name: template.Name,
318318
DisplayName: template.DisplayName,
319-
Description: template.Description,
320-
Icon: template.Icon,
319+
Description: &template.Description,
320+
Icon: &template.Icon,
321321
AutostartRequirement: &codersdk.TemplateAutostartRequirement{
322322
DaysOfWeek: []string{"foobar", "saturday"},
323323
},
@@ -352,8 +352,8 @@ func TestTemplates(t *testing.T) {
352352
updated, err := anotherClient.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
353353
Name: template.Name,
354354
DisplayName: template.DisplayName,
355-
Description: template.Description,
356-
Icon: template.Icon,
355+
Description: &template.Description,
356+
Icon: &template.Icon,
357357
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
358358
DefaultTTLMillis: time.Hour.Milliseconds(),
359359
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
@@ -406,8 +406,8 @@ func TestTemplates(t *testing.T) {
406406
updated, err := anotherClient.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
407407
Name: template.Name,
408408
DisplayName: template.DisplayName,
409-
Description: template.Description,
410-
Icon: template.Icon,
409+
Description: &template.Description,
410+
Icon: &template.Icon,
411411
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
412412
TimeTilDormantMillis: inactivityTTL.Milliseconds(),
413413
FailureTTLMillis: failureTTL.Milliseconds(),
@@ -475,8 +475,8 @@ func TestTemplates(t *testing.T) {
475475
_, err := anotherClient.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
476476
Name: template.Name,
477477
DisplayName: template.DisplayName,
478-
Description: template.Description,
479-
Icon: template.Icon,
478+
Description: &template.Description,
479+
Icon: &template.Icon,
480480
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
481481
TimeTilDormantMillis: c.TimeTilDormantMS,
482482
FailureTTLMillis: c.FailureTTLMS,
@@ -1014,8 +1014,8 @@ func TestTemplateACL(t *testing.T) {
10141014
_, err = client.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
10151015
Name: template.Name,
10161016
DisplayName: template.DisplayName,
1017-
Description: template.Description,
1018-
Icon: template.Icon,
1017+
Description: &template.Description,
1018+
Icon: &template.Icon,
10191019
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
10201020
DisableEveryoneGroupAccess: true,
10211021
})

0 commit comments

Comments
 (0)