Skip to content

Commit 825b827

Browse files
committed
feat: add cli support for --require-active-version
1 parent 997493d commit 825b827

File tree

4 files changed

+165
-11
lines changed

4 files changed

+165
-11
lines changed

cli/templatecreate.go

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ import (
2424

2525
func (r *RootCmd) templateCreate() *clibase.Cmd {
2626
var (
27-
provisioner string
28-
provisionerTags []string
29-
variablesFile string
30-
variables []string
31-
disableEveryone bool
27+
provisioner string
28+
provisionerTags []string
29+
variablesFile string
30+
variables []string
31+
disableEveryone bool
32+
requireActiveVersion bool
3233

3334
defaultTTL time.Duration
3435
failureTTL time.Duration
@@ -46,17 +47,35 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
4647
r.InitClient(client),
4748
),
4849
Handler: func(inv *clibase.Invocation) error {
49-
if failureTTL != 0 || inactivityTTL != 0 || maxTTL != 0 {
50+
isTemplateSchedulingOptionsSet := failureTTL != 0 || inactivityTTL != 0 || maxTTL != 0
51+
52+
if isTemplateSchedulingOptionsSet || requireActiveVersion {
5053
entitlements, err := client.Entitlements(inv.Context())
51-
var sdkErr *codersdk.Error
52-
if xerrors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound {
53-
return xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot set --failure-ttl or --inactivityTTL")
54+
if cerr, ok := codersdk.AsError(err); ok && cerr.StatusCode() == http.StatusNotFound {
55+
return xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags")
5456
} else if err != nil {
5557
return xerrors.Errorf("get entitlements: %w", err)
5658
}
5759

58-
if !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
59-
return xerrors.Errorf("your license is not entitled to use advanced template scheduling, so you cannot set --failure-ttl or --inactivityTTL")
60+
if isTemplateSchedulingOptionsSet {
61+
if !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
62+
return xerrors.Errorf("your license is not entitled to use advanced template scheduling, so you cannot set --failure-ttl or --inactivityTTL")
63+
}
64+
}
65+
66+
if requireActiveVersion {
67+
experiments, exErr := client.Experiments(inv.Context())
68+
if exErr != nil {
69+
return xerrors.Errorf("get experiments: %w", exErr)
70+
}
71+
72+
if !experiments.Enabled(codersdk.ExperimentTemplateUpdatePolicies) {
73+
return xerrors.Errorf("--require-active-version is an experimental feature, pass 'template_update_policies' to the CODER_EXPERIMENTS env var to use this option")
74+
}
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+
}
6079
}
6180
}
6281

@@ -129,6 +148,7 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
129148
MaxTTLMillis: ptr.Ref(maxTTL.Milliseconds()),
130149
TimeTilDormantMillis: ptr.Ref(inactivityTTL.Milliseconds()),
131150
DisableEveryoneGroupAccess: disableEveryone,
151+
RequireActiveVersion: requireActiveVersion,
132152
}
133153

134154
_, err = client.CreateTemplate(inv.Context(), organization.ID, createReq)
@@ -205,6 +225,12 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
205225
Value: clibase.StringOf(&provisioner),
206226
Hidden: true,
207227
},
228+
{
229+
Flag: "require-active-version",
230+
Description: "Requires workspace builds to use the active template version. This setting does not apply to template admins. This is an enterprise-only feature.",
231+
Value: clibase.BoolOf(&requireActiveVersion),
232+
},
233+
208234
cliui.SkipPromptOption(),
209235
}
210236
cmd.Options = append(cmd.Options, uploadFlags.options()...)

cli/templatecreate_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/coder/coder/v2/cli/clitest"
1414
"github.com/coder/coder/v2/coderd/coderdtest"
1515
"github.com/coder/coder/v2/coderd/database"
16+
"github.com/coder/coder/v2/codersdk"
1617
"github.com/coder/coder/v2/provisioner/echo"
1718
"github.com/coder/coder/v2/provisionersdk/proto"
1819
"github.com/coder/coder/v2/pty/ptytest"
@@ -393,6 +394,37 @@ func TestTemplateCreate(t *testing.T) {
393394
}
394395
}
395396
})
397+
398+
t.Run("RequireActiveVersionInvalid", func(t *testing.T) {
399+
t.Parallel()
400+
401+
dv := coderdtest.DeploymentValues(t)
402+
dv.Experiments = []string{
403+
string(codersdk.ExperimentTemplateUpdatePolicies),
404+
}
405+
406+
client := coderdtest.New(t, &coderdtest.Options{
407+
IncludeProvisionerDaemon: true,
408+
DeploymentValues: dv,
409+
})
410+
coderdtest.CreateFirstUser(t, client)
411+
source := clitest.CreateTemplateVersionSource(t, completeWithAgent())
412+
args := []string{
413+
"templates",
414+
"create",
415+
"my-template",
416+
"--directory", source,
417+
"--test.provisioner", string(database.ProvisionerTypeEcho),
418+
"--require-active-version",
419+
}
420+
inv, root := clitest.New(t, args...)
421+
clitest.SetupConfig(t, client, root)
422+
423+
err := inv.Run()
424+
require.Error(t, err)
425+
require.Contains(t, err.Error(), "your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags")
426+
})
427+
396428
}
397429

398430
// Need this for Windows because of a known issue with Go:

codersdk/deployment.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,6 +2002,7 @@ const (
20022002
// ExperimentDashboardTheme mutates the dashboard to use a new, dark color scheme.
20032003
ExperimentDashboardTheme Experiment = "dashboard_theme"
20042004

2005+
ExperimentTemplateUpdatePolicies Experiment = "template_update_policies"
20052006
// Add new experiments here!
20062007
// ExperimentExample Experiment = "example"
20072008
)

enterprise/cli/templatecreate_test.go

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

0 commit comments

Comments
 (0)