Skip to content

Commit 8644201

Browse files
committed
add support for template edit
1 parent 825b827 commit 8644201

File tree

5 files changed

+161
-10
lines changed

5 files changed

+161
-10
lines changed

cli/templatecreate.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
6464
}
6565

6666
if requireActiveVersion {
67+
if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
68+
return xerrors.Errorf("your license is not entitled to use template access control, so you cannot set --require-active-version")
69+
}
70+
6771
experiments, exErr := client.Experiments(inv.Context())
6872
if exErr != nil {
6973
return xerrors.Errorf("get experiments: %w", exErr)
@@ -72,10 +76,6 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
7276
if !experiments.Enabled(codersdk.ExperimentTemplateUpdatePolicies) {
7377
return xerrors.Errorf("--require-active-version is an experimental feature, pass 'template_update_policies' to the CODER_EXPERIMENTS env var to use this option")
7478
}
75-
76-
if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
77-
return xerrors.Errorf("your license is not entitled to use template access control, so you cannot set --require-active-version")
78-
}
7979
}
8080
}
8181

@@ -229,6 +229,7 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
229229
Flag: "require-active-version",
230230
Description: "Requires workspace builds to use the active template version. This setting does not apply to template admins. This is an enterprise-only feature.",
231231
Value: clibase.BoolOf(&requireActiveVersion),
232+
Default: "false",
232233
},
233234

234235
cliui.SkipPromptOption(),

cli/templateedit.go

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
3131
allowUserCancelWorkspaceJobs bool
3232
allowUserAutostart bool
3333
allowUserAutostop bool
34+
requireActiveVersion bool
3435
)
3536
client := new(codersdk.Client)
3637

@@ -43,7 +44,7 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
4344
Short: "Edit the metadata of a template by name.",
4445
Handler: func(inv *clibase.Invocation) error {
4546
unsetAutostopRequirementDaysOfWeek := len(autostopRequirementDaysOfWeek) == 1 && autostopRequirementDaysOfWeek[0] == "none"
46-
requiresEntitlement := (len(autostopRequirementDaysOfWeek) > 0 && !unsetAutostopRequirementDaysOfWeek) ||
47+
requiresScheduling := (len(autostopRequirementDaysOfWeek) > 0 && !unsetAutostopRequirementDaysOfWeek) ||
4748
autostopRequirementWeeks > 0 ||
4849
!allowUserAutostart ||
4950
!allowUserAutostop ||
@@ -52,18 +53,37 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
5253
inactivityTTL != 0 ||
5354
len(autostartRequirementDaysOfWeek) > 0
5455

56+
requiresEntitlement := requiresScheduling || requireActiveVersion
5557
if requiresEntitlement {
5658
entitlements, err := client.Entitlements(inv.Context())
57-
var sdkErr *codersdk.Error
58-
if xerrors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound {
59-
return xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot set --max-ttl, --failure-ttl, --inactivityTTL, --allow-user-autostart=false or --allow-user-autostop=false")
59+
if cerr, ok := codersdk.AsError(err); ok && cerr.StatusCode() == http.StatusNotFound {
60+
return xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags")
6061
} else if err != nil {
6162
return xerrors.Errorf("get entitlements: %w", err)
6263
}
6364

64-
if !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
65+
if requiresScheduling && !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
6566
return xerrors.Errorf("your license is not entitled to use advanced template scheduling, so you cannot set --max-ttl, --failure-ttl, --inactivityTTL, --allow-user-autostart=false or --allow-user-autostop=false")
6667
}
68+
69+
if requireActiveVersion {
70+
if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
71+
return xerrors.Errorf("your license is not entitled to use template access control, so you cannot set --require-active-version")
72+
}
73+
74+
experiments, exErr := client.Experiments(inv.Context())
75+
if exErr != nil {
76+
return xerrors.Errorf("get experiments: %w", exErr)
77+
}
78+
79+
if !experiments.Enabled(codersdk.ExperimentTemplateUpdatePolicies) {
80+
return xerrors.Errorf("--require-active-version is an experimental feature, pass 'template_update_policies' to the CODER_EXPERIMENTS env var to use this option")
81+
}
82+
if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
83+
return xerrors.Errorf("your license is not entitled to use template access control, so you cannot set --require-active-version")
84+
85+
}
86+
}
6787
}
6888

6989
organization, err := CurrentOrganization(inv, client)
@@ -110,6 +130,7 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
110130
AllowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
111131
AllowUserAutostart: allowUserAutostart,
112132
AllowUserAutostop: allowUserAutostop,
133+
RequireActiveVersion: requireActiveVersion,
113134
}
114135

115136
_, err = client.UpdateTemplateMeta(inv.Context(), template.ID, req)
@@ -222,6 +243,12 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
222243
Default: "true",
223244
Value: clibase.BoolOf(&allowUserAutostop),
224245
},
246+
{
247+
Flag: "require-active-version",
248+
Description: "Requires workspace builds to use the active template version. This setting does not apply to template admins. This is an enterprise-only feature.",
249+
Value: clibase.BoolOf(&requireActiveVersion),
250+
Default: "false",
251+
},
225252
cliui.SkipPromptOption(),
226253
}
227254

cli/templateedit_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,4 +1021,30 @@ func TestTemplateEdit(t *testing.T) {
10211021
assert.Equal(t, template.TimeTilDormantMillis, updated.TimeTilDormantMillis)
10221022
})
10231023
})
1024+
1025+
t.Run("RequireActiveVersion", func(t *testing.T) {
1026+
t.Parallel()
1027+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
1028+
owner := coderdtest.CreateFirstUser(t, client)
1029+
1030+
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
1031+
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
1032+
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {})
1033+
1034+
// Test the cli command with --allow-user-autostart.
1035+
cmdArgs := []string{
1036+
"templates",
1037+
"edit",
1038+
template.Name,
1039+
"--require-active-version",
1040+
}
1041+
inv, root := clitest.New(t, cmdArgs...)
1042+
//nolint
1043+
clitest.SetupConfig(t, client, root)
1044+
1045+
ctx := testutil.Context(t, testutil.WaitLong)
1046+
err := inv.WithContext(ctx).Run()
1047+
require.Error(t, err)
1048+
require.ErrorContains(t, err, "appears to be an AGPL deployment")
1049+
})
10241050
}

enterprise/cli/templatecreate_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func TestTemplateCreate(t *testing.T) {
6262
require.True(t, template.RequireActiveVersion)
6363
})
6464

65-
t.Run("NoEntitlement", func(t *testing.T) {
65+
t.Run("NotEntitled", func(t *testing.T) {
6666
t.Parallel()
6767

6868
dv := coderdtest.DeploymentValues(t)

enterprise/cli/templateedit_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package cli_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/coder/coder/v2/cli/clitest"
7+
"github.com/coder/coder/v2/coderd/coderdtest"
8+
"github.com/coder/coder/v2/coderd/rbac"
9+
"github.com/coder/coder/v2/codersdk"
10+
"github.com/coder/coder/v2/enterprise/coderd/coderdenttest"
11+
"github.com/coder/coder/v2/enterprise/coderd/license"
12+
"github.com/coder/coder/v2/testutil"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestTemplateEdit(t *testing.T) {
17+
t.Parallel()
18+
19+
t.Run("OK", func(t *testing.T) {
20+
t.Parallel()
21+
22+
dv := coderdtest.DeploymentValues(t)
23+
dv.Experiments = []string{
24+
string(codersdk.ExperimentTemplateUpdatePolicies),
25+
}
26+
27+
ownerClient, owner := coderdenttest.New(t, &coderdenttest.Options{
28+
LicenseOptions: &coderdenttest.LicenseOptions{
29+
Features: license.Features{
30+
codersdk.FeatureAccessControl: 1,
31+
},
32+
},
33+
Options: &coderdtest.Options{
34+
DeploymentValues: dv,
35+
IncludeProvisionerDaemon: true,
36+
},
37+
})
38+
39+
templateAdmin, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.RoleTemplateAdmin())
40+
version := coderdtest.CreateTemplateVersion(t, templateAdmin, owner.OrganizationID, nil)
41+
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, templateAdmin, version.ID)
42+
template := coderdtest.CreateTemplate(t, templateAdmin, owner.OrganizationID, version.ID)
43+
require.False(t, template.RequireActiveVersion)
44+
45+
inv, conf := newCLI(t, "templates",
46+
"edit", template.Name,
47+
"--require-active-version",
48+
"-y",
49+
)
50+
51+
clitest.SetupConfig(t, templateAdmin, conf)
52+
53+
err := inv.Run()
54+
require.NoError(t, err)
55+
56+
ctx := testutil.Context(t, testutil.WaitMedium)
57+
template, err = templateAdmin.Template(ctx, template.ID)
58+
require.NoError(t, err)
59+
require.True(t, template.RequireActiveVersion)
60+
})
61+
62+
t.Run("NotEntitled", func(t *testing.T) {
63+
t.Parallel()
64+
65+
dv := coderdtest.DeploymentValues(t)
66+
dv.Experiments = []string{
67+
string(codersdk.ExperimentTemplateUpdatePolicies),
68+
}
69+
70+
client, owner := coderdenttest.New(t, &coderdenttest.Options{
71+
LicenseOptions: &coderdenttest.LicenseOptions{
72+
Features: license.Features{},
73+
},
74+
Options: &coderdtest.Options{
75+
DeploymentValues: dv,
76+
IncludeProvisionerDaemon: true,
77+
},
78+
})
79+
80+
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
81+
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
82+
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
83+
require.False(t, template.RequireActiveVersion)
84+
85+
inv, conf := newCLI(t, "templates",
86+
"edit", template.Name,
87+
"--require-active-version",
88+
"-y",
89+
)
90+
91+
clitest.SetupConfig(t, client, conf)
92+
93+
err := inv.Run()
94+
require.Error(t, err)
95+
require.Contains(t, err.Error(), "your license is not entitled to use template access control, so you cannot set --require-active-version")
96+
})
97+
}

0 commit comments

Comments
 (0)