Skip to content

Commit 3c377e5

Browse files
committed
combine edit flags
1 parent 4d2f41f commit 3c377e5

File tree

3 files changed

+370
-147
lines changed

3 files changed

+370
-147
lines changed

cli/templatecreate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
4747
r.InitClient(client),
4848
),
4949
Handler: func(inv *clibase.Invocation) error {
50-
err := handleEntitlements(inv.Context(), handleEntitlementsArgs{
50+
err := createEntitlementsCheck(inv.Context(), handleEntitlementsArgs{
5151
client: client,
5252
requireActiveVersion: requireActiveVersion,
5353
defaultTTL: defaultTTL,
@@ -347,7 +347,7 @@ type handleEntitlementsArgs struct {
347347
maxTTL time.Duration
348348
}
349349

350-
func handleEntitlements(ctx context.Context, args handleEntitlementsArgs) error {
350+
func createEntitlementsCheck(ctx context.Context, args handleEntitlementsArgs) error {
351351
isTemplateSchedulingOptionsSet := args.failureTTL != 0 || args.dormancyThreshold != 0 || args.dormancyAutoDeletion != 0 || args.maxTTL != 0
352352

353353
if isTemplateSchedulingOptionsSet || args.requireActiveVersion {

cli/templateedit.go

Lines changed: 215 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"context"
45
"fmt"
56
"net/http"
67
"strings"
@@ -46,58 +47,6 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
4647
),
4748
Short: "Edit the metadata of a template by name.",
4849
Handler: func(inv *clibase.Invocation) error {
49-
// This clause can be removed when workspace_actions is no longer experimental
50-
if failureTTL != 0 || dormancyThreshold != 0 || dormancyAutoDeletion != 0 {
51-
experiments, exErr := client.Experiments(inv.Context())
52-
if exErr != nil {
53-
return xerrors.Errorf("get experiments: %w", exErr)
54-
}
55-
56-
if !experiments.Enabled(codersdk.ExperimentWorkspaceActions) {
57-
return xerrors.Errorf("--failure-ttl, --dormancy-threshold, and --dormancy-auto-deletion are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.")
58-
}
59-
}
60-
61-
unsetAutostopRequirementDaysOfWeek := len(autostopRequirementDaysOfWeek) == 1 && autostopRequirementDaysOfWeek[0] == "none"
62-
requiresScheduling := (len(autostopRequirementDaysOfWeek) > 0 && !unsetAutostopRequirementDaysOfWeek) ||
63-
autostopRequirementWeeks > 0 ||
64-
!allowUserAutostart ||
65-
!allowUserAutostop ||
66-
maxTTL != 0 ||
67-
failureTTL != 0 ||
68-
dormancyThreshold != 0 ||
69-
dormancyAutoDeletion != 0 ||
70-
len(autostartRequirementDaysOfWeek) > 0
71-
72-
requiresEntitlement := requiresScheduling || requireActiveVersion
73-
if requiresEntitlement {
74-
entitlements, err := client.Entitlements(inv.Context())
75-
if cerr, ok := codersdk.AsError(err); ok && cerr.StatusCode() == http.StatusNotFound {
76-
return xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags")
77-
} else if err != nil {
78-
return xerrors.Errorf("get entitlements: %w", err)
79-
}
80-
81-
if requiresScheduling && !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
82-
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")
83-
}
84-
85-
if requireActiveVersion {
86-
if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
87-
return xerrors.Errorf("your license is not entitled to use enterprise access control, so you cannot set --require-active-version")
88-
}
89-
90-
experiments, exErr := client.Experiments(inv.Context())
91-
if exErr != nil {
92-
return xerrors.Errorf("get experiments: %w", exErr)
93-
}
94-
95-
if !experiments.Enabled(codersdk.ExperimentTemplateUpdatePolicies) {
96-
return xerrors.Errorf("--require-active-version is an experimental feature, contact an administrator to enable the 'template_update_policies' experiment on your Coder server")
97-
}
98-
}
99-
}
100-
10150
organization, err := CurrentOrganization(inv, client)
10251
if err != nil {
10352
return xerrors.Errorf("get current organization: %w", err)
@@ -107,71 +56,55 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
10756
return xerrors.Errorf("get workspace template: %w", err)
10857
}
10958

110-
// Copy the default value if the list is empty, or if the user
111-
// specified the "none" value clear the list.
112-
if len(autostopRequirementDaysOfWeek) == 0 {
113-
autostopRequirementDaysOfWeek = template.AutostopRequirement.DaysOfWeek
114-
}
115-
if len(autostartRequirementDaysOfWeek) == 1 && autostartRequirementDaysOfWeek[0] == "all" {
116-
// Set it to every day of the week
117-
autostartRequirementDaysOfWeek = []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}
118-
} else if len(autostartRequirementDaysOfWeek) == 0 {
119-
autostartRequirementDaysOfWeek = template.AutostartRequirement.DaysOfWeek
120-
}
121-
if unsetAutostopRequirementDaysOfWeek {
122-
autostopRequirementDaysOfWeek = []string{}
123-
}
124-
if failureTTL == 0 {
125-
failureTTL = time.Duration(template.FailureTTLMillis) * time.Millisecond
126-
}
127-
if dormancyThreshold == 0 {
128-
dormancyThreshold = time.Duration(template.TimeTilDormantMillis) * time.Millisecond
129-
}
130-
if dormancyAutoDeletion == 0 {
131-
dormancyAutoDeletion = time.Duration(template.TimeTilDormantAutoDeleteMillis) * time.Millisecond
132-
}
133-
134-
// Default values
135-
if !userSetOption(inv, "description") {
136-
description = template.Description
137-
}
59+
unsetAutostopRequirementDaysOfWeek, err := editTemplateEntitlementsCheck(inv.Context(), editTemplateEntitlementsArgs{
60+
client: client,
61+
inv: inv,
62+
template: template,
13863

139-
if !userSetOption(inv, "icon") {
140-
icon = template.Icon
141-
}
64+
name: name,
65+
displayName: displayName,
66+
description: description,
67+
icon: icon,
68+
defaultTTL: defaultTTL,
69+
maxTTL: maxTTL,
70+
autostopRequirementDaysOfWeek: autostopRequirementDaysOfWeek,
71+
autostopRequirementWeeks: autostopRequirementWeeks,
72+
autostartRequirementDaysOfWeek: autostartRequirementDaysOfWeek,
73+
failureTTL: failureTTL,
74+
dormancyThreshold: dormancyThreshold,
75+
dormancyAutoDeletion: dormancyAutoDeletion,
76+
allowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
77+
allowUserAutostart: allowUserAutostart,
78+
allowUserAutostop: allowUserAutostop,
79+
requireActiveVersion: requireActiveVersion,
80+
deprecationMessage: deprecationMessage,
81+
disableEveryone: false, // TODO: Add new flag
82+
})
14283

143-
if !userSetOption(inv, "display-name") {
144-
displayName = template.DisplayName
145-
}
84+
req := updateTemplateMetaRequest(updateTemplateMetaArgs{
85+
client: client,
86+
inv: inv,
87+
template: template,
88+
unsetAutostopRequirementDaysOfWeek: unsetAutostopRequirementDaysOfWeek,
14689

147-
var deprecated *string
148-
if !userSetOption(inv, "deprecated") {
149-
deprecated = &deprecationMessage
150-
}
151-
152-
req := codersdk.UpdateTemplateMeta{
153-
Name: name,
154-
DisplayName: displayName,
155-
Description: description,
156-
Icon: icon,
157-
DefaultTTLMillis: defaultTTL.Milliseconds(),
158-
MaxTTLMillis: maxTTL.Milliseconds(),
159-
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
160-
DaysOfWeek: autostopRequirementDaysOfWeek,
161-
Weeks: autostopRequirementWeeks,
162-
},
163-
AutostartRequirement: &codersdk.TemplateAutostartRequirement{
164-
DaysOfWeek: autostartRequirementDaysOfWeek,
165-
},
166-
FailureTTLMillis: failureTTL.Milliseconds(),
167-
TimeTilDormantMillis: dormancyThreshold.Milliseconds(),
168-
TimeTilDormantAutoDeleteMillis: dormancyAutoDeletion.Milliseconds(),
169-
AllowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
170-
AllowUserAutostart: allowUserAutostart,
171-
AllowUserAutostop: allowUserAutostop,
172-
RequireActiveVersion: requireActiveVersion,
173-
DeprecationMessage: deprecated,
174-
}
90+
name: name,
91+
displayName: displayName,
92+
description: description,
93+
icon: icon,
94+
defaultTTL: defaultTTL,
95+
maxTTL: maxTTL,
96+
autostopRequirementDaysOfWeek: autostopRequirementDaysOfWeek,
97+
autostopRequirementWeeks: autostopRequirementWeeks,
98+
autostartRequirementDaysOfWeek: autostartRequirementDaysOfWeek,
99+
failureTTL: failureTTL,
100+
dormancyThreshold: dormancyThreshold,
101+
dormancyAutoDeletion: dormancyAutoDeletion,
102+
allowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
103+
allowUserAutostart: allowUserAutostart,
104+
allowUserAutostop: allowUserAutostop,
105+
requireActiveVersion: requireActiveVersion,
106+
deprecationMessage: deprecationMessage,
107+
})
175108

176109
_, err = client.UpdateTemplateMeta(inv.Context(), template.ID, req)
177110
if err != nil {
@@ -306,3 +239,171 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
306239

307240
return cmd
308241
}
242+
243+
type editTemplateEntitlementsArgs struct {
244+
client *codersdk.Client
245+
inv *clibase.Invocation
246+
247+
defaultTTL time.Duration
248+
maxTTL time.Duration
249+
autostopRequirementDaysOfWeek []string
250+
autostopRequirementWeeks int64
251+
autostartRequirementDaysOfWeek []string
252+
failureTTL time.Duration
253+
dormancyThreshold time.Duration
254+
dormancyAutoDeletion time.Duration
255+
allowUserCancelWorkspaceJobs bool
256+
allowUserAutostart bool
257+
allowUserAutostop bool
258+
requireActiveVersion bool
259+
}
260+
261+
func editTemplateEntitlementsCheck(ctx context.Context, args editTemplateEntitlementsArgs) (bool, error) {
262+
// This clause can be removed when workspace_actions is no longer experimental
263+
if args.failureTTL != 0 || args.dormancyThreshold != 0 || args.dormancyAutoDeletion != 0 {
264+
experiments, exErr := args.client.Experiments(ctx)
265+
if exErr != nil {
266+
return false, xerrors.Errorf("get experiments: %w", exErr)
267+
}
268+
269+
if !experiments.Enabled(codersdk.ExperimentWorkspaceActions) {
270+
return false, xerrors.Errorf("--failure-ttl, --dormancy-threshold, and --dormancy-auto-deletion are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.")
271+
}
272+
}
273+
274+
unsetAutostopRequirementDaysOfWeek := len(args.autostopRequirementDaysOfWeek) == 1 && args.autostopRequirementDaysOfWeek[0] == "none"
275+
requiresScheduling := (len(args.autostopRequirementDaysOfWeek) > 0 && !unsetAutostopRequirementDaysOfWeek) ||
276+
args.autostopRequirementWeeks > 0 ||
277+
!args.allowUserAutostart ||
278+
!args.allowUserAutostop ||
279+
args.maxTTL != 0 ||
280+
args.failureTTL != 0 ||
281+
args.dormancyThreshold != 0 ||
282+
args.dormancyAutoDeletion != 0 ||
283+
len(args.autostartRequirementDaysOfWeek) > 0
284+
285+
requiresEntitlement := requiresScheduling || args.requireActiveVersion
286+
if requiresEntitlement {
287+
entitlements, err := args.client.Entitlements(ctx)
288+
if cerr, ok := codersdk.AsError(err); ok && cerr.StatusCode() == http.StatusNotFound {
289+
return false, xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags")
290+
} else if err != nil {
291+
return false, xerrors.Errorf("get entitlements: %w", err)
292+
}
293+
294+
if requiresScheduling && !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
295+
return false, 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")
296+
}
297+
298+
if args.requireActiveVersion {
299+
if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
300+
return false, xerrors.Errorf("your license is not entitled to use enterprise access control, so you cannot set --require-active-version")
301+
}
302+
303+
experiments, exErr := args.client.Experiments(ctx)
304+
if exErr != nil {
305+
return false, xerrors.Errorf("get experiments: %w", exErr)
306+
}
307+
308+
if !experiments.Enabled(codersdk.ExperimentTemplateUpdatePolicies) {
309+
return false, xerrors.Errorf("--require-active-version is an experimental feature, contact an administrator to enable the 'template_update_policies' experiment on your Coder server")
310+
}
311+
}
312+
}
313+
314+
return unsetAutostopRequirementDaysOfWeek, nil
315+
}
316+
317+
type updateTemplateMetaArgs struct {
318+
client *codersdk.Client
319+
inv *clibase.Invocation
320+
template codersdk.Template
321+
unsetAutostopRequirementDaysOfWeek bool
322+
323+
name string
324+
displayName string
325+
description string
326+
icon string
327+
defaultTTL time.Duration
328+
maxTTL time.Duration
329+
autostopRequirementDaysOfWeek []string
330+
autostopRequirementWeeks int64
331+
autostartRequirementDaysOfWeek []string
332+
failureTTL time.Duration
333+
dormancyThreshold time.Duration
334+
dormancyAutoDeletion time.Duration
335+
allowUserCancelWorkspaceJobs bool
336+
allowUserAutostart bool
337+
allowUserAutostop bool
338+
requireActiveVersion bool
339+
deprecationMessage string
340+
disableEveryone bool
341+
}
342+
343+
func updateTemplateMetaRequest(args updateTemplateMetaArgs) codersdk.UpdateTemplateMeta {
344+
// Copy the default value if the list is empty, or if the user
345+
// specified the "none" value clear the list.
346+
if len(args.autostopRequirementDaysOfWeek) == 0 {
347+
args.autostopRequirementDaysOfWeek = args.template.AutostopRequirement.DaysOfWeek
348+
}
349+
if len(args.autostartRequirementDaysOfWeek) == 1 && args.autostartRequirementDaysOfWeek[0] == "all" {
350+
// Set it to every day of the week
351+
args.autostartRequirementDaysOfWeek = []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}
352+
} else if len(args.autostartRequirementDaysOfWeek) == 0 {
353+
args.autostartRequirementDaysOfWeek = args.template.AutostartRequirement.DaysOfWeek
354+
}
355+
if args.unsetAutostopRequirementDaysOfWeek {
356+
args.autostopRequirementDaysOfWeek = []string{}
357+
}
358+
if args.failureTTL == 0 {
359+
args.failureTTL = time.Duration(args.template.FailureTTLMillis) * time.Millisecond
360+
}
361+
if args.dormancyThreshold == 0 {
362+
args.dormancyThreshold = time.Duration(args.template.TimeTilDormantMillis) * time.Millisecond
363+
}
364+
if args.dormancyAutoDeletion == 0 {
365+
args.dormancyAutoDeletion = time.Duration(args.template.TimeTilDormantAutoDeleteMillis) * time.Millisecond
366+
}
367+
368+
// Default values
369+
if !userSetOption(args.inv, "description") {
370+
args.description = args.template.Description
371+
}
372+
373+
if !userSetOption(args.inv, "icon") {
374+
args.icon = args.template.Icon
375+
}
376+
377+
if !userSetOption(args.inv, "display-name") {
378+
args.displayName = args.template.DisplayName
379+
}
380+
381+
var deprecated *string
382+
if !userSetOption(args.inv, "deprecated") {
383+
deprecated = &args.deprecationMessage
384+
}
385+
386+
return codersdk.UpdateTemplateMeta{
387+
Name: args.name,
388+
DisplayName: args.displayName,
389+
Description: args.description,
390+
Icon: args.icon,
391+
DefaultTTLMillis: args.defaultTTL.Milliseconds(),
392+
MaxTTLMillis: args.maxTTL.Milliseconds(),
393+
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
394+
DaysOfWeek: args.autostopRequirementDaysOfWeek,
395+
Weeks: args.autostopRequirementWeeks,
396+
},
397+
AutostartRequirement: &codersdk.TemplateAutostartRequirement{
398+
DaysOfWeek: args.autostartRequirementDaysOfWeek,
399+
},
400+
FailureTTLMillis: args.failureTTL.Milliseconds(),
401+
TimeTilDormantMillis: args.dormancyThreshold.Milliseconds(),
402+
TimeTilDormantAutoDeleteMillis: args.dormancyAutoDeletion.Milliseconds(),
403+
AllowUserCancelWorkspaceJobs: args.allowUserCancelWorkspaceJobs,
404+
AllowUserAutostart: args.allowUserAutostart,
405+
AllowUserAutostop: args.allowUserAutostop,
406+
RequireActiveVersion: args.requireActiveVersion,
407+
DeprecationMessage: deprecated,
408+
}
409+
}

0 commit comments

Comments
 (0)