Skip to content

Commit 7060069

Browse files
authored
fix: prevent change in defaults if user unsets in template edit (#10793)
* fix: template edit not change defaults if user unset
1 parent e6dc9ee commit 7060069

File tree

3 files changed

+68
-6
lines changed

3 files changed

+68
-6
lines changed

cli/templateedit.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,24 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
120120
autostopRequirementDaysOfWeek = []string{}
121121
}
122122

123-
// Only pass explicitly set deprecated values since the empty string
124-
// removes the deprecated message. By default if we pass a nil,
125-
// there is no change to this field.
123+
// Default values
124+
if !userSetOption(inv, "description") {
125+
description = template.Description
126+
}
127+
128+
if !userSetOption(inv, "icon") {
129+
icon = template.Icon
130+
}
131+
132+
if !userSetOption(inv, "display-name") {
133+
displayName = template.DisplayName
134+
}
135+
126136
var deprecated *string
127-
opt := inv.Command.Options.ByName(deprecatedFlagName)
128-
if !(opt.ValueSource == "" || opt.ValueSource == clibase.ValueSourceDefault) {
137+
if !userSetOption(inv, "deprecated") {
129138
deprecated = &deprecationMessage
130139
}
131140

132-
// NOTE: coderd will ignore empty fields.
133141
req := codersdk.UpdateTemplateMeta{
134142
Name: name,
135143
DisplayName: displayName,

cli/templateedit_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ func TestTemplateEdit(t *testing.T) {
228228
"templates",
229229
"edit",
230230
template.Name,
231+
"--description", "",
232+
"--display-name", "",
233+
"--icon", "",
231234
}
232235
inv, root := clitest.New(t, cmdArgs...)
233236
clitest.SetupConfig(t, templateAdmin, root)
@@ -1047,4 +1050,41 @@ func TestTemplateEdit(t *testing.T) {
10471050
require.Error(t, err)
10481051
require.ErrorContains(t, err, "appears to be an AGPL deployment")
10491052
})
1053+
t.Run("DefaultValues", func(t *testing.T) {
1054+
t.Parallel()
1055+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
1056+
owner := coderdtest.CreateFirstUser(t, client)
1057+
1058+
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
1059+
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
1060+
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
1061+
ctr.Name = "random"
1062+
ctr.Icon = "/icon/foobar.png"
1063+
ctr.DisplayName = "Foobar"
1064+
ctr.Description = "Some description"
1065+
})
1066+
1067+
// We need to change some field to get a db write.
1068+
cmdArgs := []string{
1069+
"templates",
1070+
"edit",
1071+
template.Name,
1072+
"--name", "something-new",
1073+
}
1074+
inv, root := clitest.New(t, cmdArgs...)
1075+
//nolint
1076+
clitest.SetupConfig(t, client, root)
1077+
1078+
ctx := testutil.Context(t, testutil.WaitLong)
1079+
err := inv.WithContext(ctx).Run()
1080+
require.NoError(t, err)
1081+
1082+
updated, err := client.Template(context.Background(), template.ID)
1083+
require.NoError(t, err)
1084+
assert.Equal(t, "something-new", updated.Name)
1085+
assert.Equal(t, template.Icon, updated.Icon)
1086+
assert.Equal(t, template.DisplayName, updated.DisplayName)
1087+
assert.Equal(t, template.Description, updated.Description)
1088+
assert.Equal(t, template.DeprecationMessage, updated.DeprecationMessage)
1089+
})
10501090
}

cli/util.go

+14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"golang.org/x/xerrors"
1010

11+
"github.com/coder/coder/v2/cli/clibase"
1112
"github.com/coder/coder/v2/coderd/schedule/cron"
1213
"github.com/coder/coder/v2/coderd/util/tz"
1314
)
@@ -18,6 +19,19 @@ var (
1819
errUnsupportedTimezone = xerrors.New("The location you provided looks like a timezone. Check https://ipinfo.io for your location.")
1920
)
2021

22+
// userSetOption returns true if the option was set by the user.
23+
// This is helpful if the zero value of a flag is meaningful, and you need
24+
// to distinguish between the user setting the flag to the zero value and
25+
// the user not setting the flag at all.
26+
func userSetOption(inv *clibase.Invocation, flagName string) bool {
27+
for _, opt := range inv.Command.Options {
28+
if opt.Name == flagName {
29+
return !(opt.ValueSource == clibase.ValueSourceNone || opt.ValueSource == clibase.ValueSourceDefault)
30+
}
31+
}
32+
return false
33+
}
34+
2135
// durationDisplay formats a duration for easier display:
2236
// - Durations of 24 hours or greater are displays as Xd
2337
// - Durations less than 1 minute are displayed as <1m

0 commit comments

Comments
 (0)