- Notifications
You must be signed in to change notification settings - Fork948
feat(cli): add CLI support for creating a workspace with preset#18912
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Uh oh!
There was an error while loading.Please reload this page.
Conversation
@@ -21,10 +21,15 @@ import ( | |||
"github.com/coder/serpent" | |||
) | |||
// DefaultPresetName is used when a user runs `create --preset default`. | |||
// It instructs the CLI to use the default preset defined for the template version, if one exists. | |||
const DefaultPresetName = "default" |
ssncferreiraJul 17, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
To preserve current behavior, if no--preset
is provided, the CLI does not apply any preset. I added support for a specialdefault
value to allow users to explicitly use the default preset (if one exists). However, this approach might not be ideal, as it introduces ambiguity, e.g., what if a preset is literally named "default"?
Another approach I considered was assigning a default value (likedefault
) to the--preset
flag itself. But that could lead to unexpected behavior: the user may not realize a preset is being applied at all.
A potentially better UX would be:
- If the template has presets and none is specified via
--preset
, prompt the user to select one. - If there’s a default preset, it should appear as the first option (as in the UI).
- Add a
none
option to explicitly skip using a preset (as in the UI). This means that instead of having a default value for the preset, we can have a none value that explicitly indicates no preset should be used. - This would bring the CLI experience closer to the web interface and make it more intuitive.
However, the downside is that this would break existing automation/scripts that rely on creating workspaces silently when presets exist. Those scripts would now hang, waiting for input.
Let me know what you think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
You've summarised the trade-offs well. My assessment of them is that without a--preset
flag specified, it should use the default as defined in the template. This use case is what we allow a default to be defined for.
I see you've already added a line to the command output to inform the user which preset was chosen, so that should help make it more visible.
Like with the frontend, we can allow for a "None" preset. In fact it might be a good idea to move that from the frontend to the API so that we have it here without any additional trouble.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Solid work@ssncferreira. Thorough tests! Let me know where you land on the default preset matter? :)
@@ -21,10 +21,15 @@ import ( | |||
"github.com/coder/serpent" | |||
) | |||
// DefaultPresetName is used when a user runs `create --preset default`. | |||
// It instructs the CLI to use the default preset defined for the template version, if one exists. | |||
const DefaultPresetName = "default" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
You've summarised the trade-offs well. My assessment of them is that without a--preset
flag specified, it should use the default as defined in the template. This use case is what we allow a default to be defined for.
I see you've already added a line to the command output to inform the user which preset was chosen, so that should help make it more visible.
Like with the frontend, we can allow for a "None" preset. In fact it might be a good idea to move that from the frontend to the API so that we have it here without any additional trouble.
@@ -100,6 +100,14 @@ func (wpf *workspaceParameterFlags) alwaysPrompt() serpent.Option { | |||
} | |||
} | |||
func presetParameterAsWorkspaceBuildParameters(presetParameters []codersdk.PresetParameter) ([]codersdk.WorkspaceBuildParameter, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
why does this return an error? I don't see the return used in the function.
@@ -411,6 +477,7 @@ func prepWorkspaceBuild(inv *serpent.Invocation, client *codersdk.Client, args p | |||
WithSourceWorkspaceParameters(args.SourceWorkspaceParameters). | |||
WithPromptEphemeralParameters(args.PromptEphemeralParameters). | |||
WithEphemeralParameters(args.EphemeralParameters). | |||
WithPresetParameters(args.PresetParameters). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Should this not be last in the list? Otherwise we allow preset parameters to be overwritten.
DefaultValue: firstParameterValue, | ||
Options: []*proto.RichParameterOption{ | ||
{ | ||
Name: firstOptionalParameterName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Nonblocking: the naming here made me have to think twice, but I'm not sure what a better name would have been. The current name implies that its a parameter like the others instead of an option on an actual parameter. Feel free to leave it as is if no better name comes to mind.
) { | ||
t.Helper() | ||
state, err := reconciler.SnapshotState(ctx, db) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This duplicates business logic that we already have in the reconciliation loop. Perhaps look for some of the prebuild claim tests. Yevhenii wrote a nice test that spins up an actual reconciliation loop with minimal LoC and I think it might work nicely here. Nevermind. I see that you are using the reconciler to a reasonable extent. Nice tests!
Uh oh!
There was an error while loading.Please reload this page.
Description
This PR introduces a
--preset
flag for thecreate
command to allow users to apply a predefined preset to their workspace build.Changes
--preset
flag on thecreate
command integrates with the parameter resolution logic and takes precedence over other sources (e.g., CLI/env vars, last build, etc.).Relates to PR:#18910 - please consider both PRs together as they’re part of the same workflow
Relates to issue:#16594