@@ -21,10 +21,15 @@ import (
21
21
"github.com/coder/serpent"
22
22
)
23
23
24
+ // DefaultPresetName is used when a user runs `create --preset default`.
25
+ // It instructs the CLI to use the default preset defined for the template version, if one exists.
26
+ const DefaultPresetName = "default"
27
+
24
28
func (r * RootCmd ) create () * serpent.Command {
25
29
var (
26
30
templateName string
27
31
templateVersion string
32
+ presetName string
28
33
startAt string
29
34
stopAfter time.Duration
30
35
workspaceName string
@@ -263,11 +268,58 @@ func (r *RootCmd) create() *serpent.Command {
263
268
}
264
269
}
265
270
271
+ // If a preset name is provided, resolve the preset to use.
272
+ var preset * codersdk.Preset
273
+ var presetParameters []codersdk.WorkspaceBuildParameter
274
+ isDefaultPreset := false
275
+ if len (presetName ) > 0 {
276
+ tvPresets , err := client .TemplateVersionPresets (inv .Context (), templateVersionID )
277
+ if err != nil {
278
+ return xerrors .Errorf ("failed to get presets: %w" , err )
279
+ }
280
+
281
+ for _ , tvPreset := range tvPresets {
282
+ // If the preset name is the special "default" keyword,
283
+ // fetch the template version's default preset (if any).
284
+ if presetName == DefaultPresetName && tvPreset .Default {
285
+ preset = & tvPreset
286
+ isDefaultPreset = true
287
+ break
288
+ }
289
+ if tvPreset .Name == presetName {
290
+ preset = & tvPreset
291
+ break
292
+ }
293
+ }
294
+
295
+ if preset == nil {
296
+ return xerrors .Errorf ("preset %q not found" , presetName )
297
+ }
298
+
299
+ // Convert preset parameters into workspace build parameters.
300
+ presetBuildParameters , err := presetParameterAsWorkspaceBuildParameters (preset .Parameters )
301
+ if err != nil {
302
+ return xerrors .Errorf ("failed to parse preset parameters: %w" , err )
303
+ }
304
+ presetParameters = append (presetParameters , presetBuildParameters ... )
305
+
306
+ // Inform the user which preset was applied and its parameters.
307
+ presetLabel := fmt .Sprintf ("Preset '%s'" , preset .Name )
308
+ if isDefaultPreset {
309
+ presetLabel += " (default)"
310
+ }
311
+ _ , _ = fmt .Fprintf (inv .Stdout , "%s applied:" , cliui .Bold (presetLabel ))
312
+ for _ , p := range presetParameters {
313
+ _ , _ = fmt .Fprintf (inv .Stdout , " %s: '%s'\n " , cliui .Bold (p .Name ), p .Value )
314
+ }
315
+ }
316
+
266
317
richParameters , err := prepWorkspaceBuild (inv , client , prepWorkspaceBuildArgs {
267
318
Action : WorkspaceCreate ,
268
319
TemplateVersionID : templateVersionID ,
269
320
NewWorkspaceName : workspaceName ,
270
321
322
+ PresetParameters : presetParameters ,
271
323
RichParameterFile : parameterFlags .richParameterFile ,
272
324
RichParameters : cliBuildParameters ,
273
325
RichParameterDefaults : cliBuildParameterDefaults ,
@@ -291,14 +343,21 @@ func (r *RootCmd) create() *serpent.Command {
291
343
ttlMillis = ptr .Ref (stopAfter .Milliseconds ())
292
344
}
293
345
294
- workspace , err := client . CreateUserWorkspace ( inv . Context (), workspaceOwner , codersdk.CreateWorkspaceRequest {
346
+ req := codersdk.CreateWorkspaceRequest {
295
347
TemplateVersionID : templateVersionID ,
296
348
Name : workspaceName ,
297
349
AutostartSchedule : schedSpec ,
298
350
TTLMillis : ttlMillis ,
299
351
RichParameterValues : richParameters ,
300
352
AutomaticUpdates : codersdk .AutomaticUpdates (autoUpdates ),
301
- })
353
+ }
354
+
355
+ // If a preset exists, update the create workspace request's preset ID
356
+ if preset != nil {
357
+ req .TemplateVersionPresetID = preset .ID
358
+ }
359
+
360
+ workspace , err := client .CreateUserWorkspace (inv .Context (), workspaceOwner , req )
302
361
if err != nil {
303
362
return xerrors .Errorf ("create workspace: %w" , err )
304
363
}
@@ -333,6 +392,12 @@ func (r *RootCmd) create() *serpent.Command {
333
392
Description : "Specify a template version name." ,
334
393
Value : serpent .StringOf (& templateVersion ),
335
394
},
395
+ serpent.Option {
396
+ Flag : "preset" ,
397
+ Env : "CODER_PRESET_NAME" ,
398
+ Description : "Specify a template version preset name. Use 'default' to apply the default preset defined in the template version, if available." ,
399
+ Value : serpent .StringOf (& presetName ),
400
+ },
336
401
serpent.Option {
337
402
Flag : "start-at" ,
338
403
Env : "CODER_WORKSPACE_START_AT" ,
@@ -377,6 +442,7 @@ type prepWorkspaceBuildArgs struct {
377
442
PromptEphemeralParameters bool
378
443
EphemeralParameters []codersdk.WorkspaceBuildParameter
379
444
445
+ PresetParameters []codersdk.WorkspaceBuildParameter
380
446
PromptRichParameters bool
381
447
RichParameters []codersdk.WorkspaceBuildParameter
382
448
RichParameterFile string
@@ -411,6 +477,7 @@ func prepWorkspaceBuild(inv *serpent.Invocation, client *codersdk.Client, args p
411
477
WithSourceWorkspaceParameters (args .SourceWorkspaceParameters ).
412
478
WithPromptEphemeralParameters (args .PromptEphemeralParameters ).
413
479
WithEphemeralParameters (args .EphemeralParameters ).
480
+ WithPresetParameters (args .PresetParameters ).
414
481
WithPromptRichParameters (args .PromptRichParameters ).
415
482
WithRichParameters (args .RichParameters ).
416
483
WithRichParametersFile (parameterFile ).
0 commit comments