Skip to content

Commit 982031a

Browse files
committed
feat(cli): add CLI support for creating a workspace with preset
1 parent aae5fc2 commit 982031a

File tree

7 files changed

+1060
-3
lines changed

7 files changed

+1060
-3
lines changed

cli/create.go

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@ import (
2121
"github.com/coder/serpent"
2222
)
2323

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+
2428
func (r *RootCmd) create() *serpent.Command {
2529
var (
2630
templateName string
2731
templateVersion string
32+
presetName string
2833
startAt string
2934
stopAfter time.Duration
3035
workspaceName string
@@ -263,11 +268,58 @@ func (r *RootCmd) create() *serpent.Command {
263268
}
264269
}
265270

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+
266317
richParameters, err := prepWorkspaceBuild(inv, client, prepWorkspaceBuildArgs{
267318
Action: WorkspaceCreate,
268319
TemplateVersionID: templateVersionID,
269320
NewWorkspaceName: workspaceName,
270321

322+
PresetParameters: presetParameters,
271323
RichParameterFile: parameterFlags.richParameterFile,
272324
RichParameters: cliBuildParameters,
273325
RichParameterDefaults: cliBuildParameterDefaults,
@@ -291,14 +343,21 @@ func (r *RootCmd) create() *serpent.Command {
291343
ttlMillis = ptr.Ref(stopAfter.Milliseconds())
292344
}
293345

294-
workspace, err := client.CreateUserWorkspace(inv.Context(), workspaceOwner, codersdk.CreateWorkspaceRequest{
346+
req := codersdk.CreateWorkspaceRequest{
295347
TemplateVersionID: templateVersionID,
296348
Name: workspaceName,
297349
AutostartSchedule: schedSpec,
298350
TTLMillis: ttlMillis,
299351
RichParameterValues: richParameters,
300352
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)
302361
if err != nil {
303362
return xerrors.Errorf("create workspace: %w", err)
304363
}
@@ -333,6 +392,12 @@ func (r *RootCmd) create() *serpent.Command {
333392
Description: "Specify a template version name.",
334393
Value: serpent.StringOf(&templateVersion),
335394
},
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+
},
336401
serpent.Option{
337402
Flag: "start-at",
338403
Env: "CODER_WORKSPACE_START_AT",
@@ -377,6 +442,7 @@ type prepWorkspaceBuildArgs struct {
377442
PromptEphemeralParameters bool
378443
EphemeralParameters []codersdk.WorkspaceBuildParameter
379444

445+
PresetParameters []codersdk.WorkspaceBuildParameter
380446
PromptRichParameters bool
381447
RichParameters []codersdk.WorkspaceBuildParameter
382448
RichParameterFile string
@@ -411,6 +477,7 @@ func prepWorkspaceBuild(inv *serpent.Invocation, client *codersdk.Client, args p
411477
WithSourceWorkspaceParameters(args.SourceWorkspaceParameters).
412478
WithPromptEphemeralParameters(args.PromptEphemeralParameters).
413479
WithEphemeralParameters(args.EphemeralParameters).
480+
WithPresetParameters(args.PresetParameters).
414481
WithPromptRichParameters(args.PromptRichParameters).
415482
WithRichParameters(args.RichParameters).
416483
WithRichParametersFile(parameterFile).

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy