feat: add --use-parameter-defaults flag (#21119)

This is like `--yes`, but for parameter prompts.
This commit is contained in:
Asher
2026-01-16 18:04:57 -08:00
committed by GitHub
parent ff9ed91811
commit 4d414a0df7
66 changed files with 559 additions and 410 deletions
+2 -11
View File
@@ -10,12 +10,8 @@ import (
"github.com/coder/serpent" "github.com/coder/serpent"
) )
func RichParameter(inv *serpent.Invocation, templateVersionParameter codersdk.TemplateVersionParameter, defaultOverrides map[string]string) (string, error) { func RichParameter(inv *serpent.Invocation, templateVersionParameter codersdk.TemplateVersionParameter, name, defaultValue string) (string, error) {
label := templateVersionParameter.Name label := name
if templateVersionParameter.DisplayName != "" {
label = templateVersionParameter.DisplayName
}
if templateVersionParameter.Ephemeral { if templateVersionParameter.Ephemeral {
label += pretty.Sprint(DefaultStyles.Warn, " (build option)") label += pretty.Sprint(DefaultStyles.Warn, " (build option)")
} }
@@ -26,11 +22,6 @@ func RichParameter(inv *serpent.Invocation, templateVersionParameter codersdk.Te
_, _ = fmt.Fprintln(inv.Stdout, " "+strings.TrimSpace(strings.Join(strings.Split(templateVersionParameter.DescriptionPlaintext, "\n"), "\n "))+"\n") _, _ = fmt.Fprintln(inv.Stdout, " "+strings.TrimSpace(strings.Join(strings.Split(templateVersionParameter.DescriptionPlaintext, "\n"), "\n "))+"\n")
} }
defaultValue := templateVersionParameter.DefaultValue
if v, ok := defaultOverrides[templateVersionParameter.Name]; ok {
defaultValue = v
}
var err error var err error
var value string var value string
switch { switch {
+2 -2
View File
@@ -32,12 +32,12 @@ type PromptOptions struct {
const skipPromptFlag = "yes" const skipPromptFlag = "yes"
// SkipPromptOption adds a "--yes/-y" flag to the cmd that can be used to skip // SkipPromptOption adds a "--yes/-y" flag to the cmd that can be used to skip
// prompts. // confirmation prompts.
func SkipPromptOption() serpent.Option { func SkipPromptOption() serpent.Option {
return serpent.Option{ return serpent.Option{
Flag: skipPromptFlag, Flag: skipPromptFlag,
FlagShorthand: "y", FlagShorthand: "y",
Description: "Bypass prompts.", Description: "Bypass confirmation prompts.",
// Discard // Discard
Value: serpent.BoolOf(new(bool)), Value: serpent.BoolOf(new(bool)),
} }
+14 -2
View File
@@ -45,6 +45,7 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
parameterFlags workspaceParameterFlags parameterFlags workspaceParameterFlags
autoUpdates string autoUpdates string
copyParametersFrom string copyParametersFrom string
useParameterDefaults bool
// Organization context is only required if more than 1 template // Organization context is only required if more than 1 template
// shares the same name across multiple organizations. // shares the same name across multiple organizations.
orgContext = NewOrganizationContext() orgContext = NewOrganizationContext()
@@ -308,7 +309,7 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
displayAppliedPreset(inv, preset, presetParameters) displayAppliedPreset(inv, preset, presetParameters)
} else { } else {
// Inform the user that no preset was applied // Inform the user that no preset was applied
_, _ = fmt.Fprintf(inv.Stdout, "%s", cliui.Bold("No preset applied.")) _, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.Bold("No preset applied."))
} }
if opts.BeforeCreate != nil { if opts.BeforeCreate != nil {
@@ -329,6 +330,8 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
RichParameterDefaults: cliBuildParameterDefaults, RichParameterDefaults: cliBuildParameterDefaults,
SourceWorkspaceParameters: sourceWorkspaceParameters, SourceWorkspaceParameters: sourceWorkspaceParameters,
UseParameterDefaults: useParameterDefaults,
}) })
if err != nil { if err != nil {
return xerrors.Errorf("prepare build: %w", err) return xerrors.Errorf("prepare build: %w", err)
@@ -435,6 +438,12 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
Description: "Specify the source workspace name to copy parameters from.", Description: "Specify the source workspace name to copy parameters from.",
Value: serpent.StringOf(&copyParametersFrom), Value: serpent.StringOf(&copyParametersFrom),
}, },
serpent.Option{
Flag: "use-parameter-defaults",
Env: "CODER_WORKSPACE_USE_PARAMETER_DEFAULTS",
Description: "Automatically accept parameter defaults when no value is provided.",
Value: serpent.BoolOf(&useParameterDefaults),
},
cliui.SkipPromptOption(), cliui.SkipPromptOption(),
) )
cmd.Options = append(cmd.Options, parameterFlags.cliParameters()...) cmd.Options = append(cmd.Options, parameterFlags.cliParameters()...)
@@ -459,6 +468,8 @@ type prepWorkspaceBuildArgs struct {
RichParameters []codersdk.WorkspaceBuildParameter RichParameters []codersdk.WorkspaceBuildParameter
RichParameterFile string RichParameterFile string
RichParameterDefaults []codersdk.WorkspaceBuildParameter RichParameterDefaults []codersdk.WorkspaceBuildParameter
UseParameterDefaults bool
} }
// resolvePreset returns the preset matching the given presetName (if specified), // resolvePreset returns the preset matching the given presetName (if specified),
@@ -561,7 +572,8 @@ func prepWorkspaceBuild(inv *serpent.Invocation, client *codersdk.Client, args p
WithPromptRichParameters(args.PromptRichParameters). WithPromptRichParameters(args.PromptRichParameters).
WithRichParameters(args.RichParameters). WithRichParameters(args.RichParameters).
WithRichParametersFile(parameterFile). WithRichParametersFile(parameterFile).
WithRichParametersDefaults(args.RichParameterDefaults) WithRichParametersDefaults(args.RichParameterDefaults).
WithUseParameterDefaults(args.UseParameterDefaults)
buildParameters, err := resolver.Resolve(inv, args.Action, templateVersionParameters) buildParameters, err := resolver.Resolve(inv, args.Action, templateVersionParameters)
if err != nil { if err != nil {
return nil, err return nil, err
+406 -322
View File
@@ -318,121 +318,420 @@ func prepareEchoResponses(parameters []*proto.RichParameter, presets ...*proto.P
} }
} }
type param struct {
name string
ptype string
value string
mutable bool
}
func TestCreateWithRichParameters(t *testing.T) { func TestCreateWithRichParameters(t *testing.T) {
t.Parallel() t.Parallel()
const ( // Default parameters and their expected values.
firstParameterName = "first_parameter" params := []param{
firstParameterDescription = "This is first parameter" {
firstParameterValue = "1" name: "number_param",
ptype: "number",
secondParameterName = "second_parameter" value: "777",
secondParameterDisplayName = "Second Parameter" mutable: true,
secondParameterDescription = "This is second parameter" },
secondParameterValue = "2" {
name: "string_param",
immutableParameterName = "third_parameter" ptype: "string",
immutableParameterDescription = "This is not mutable parameter" value: "qux",
immutableParameterValue = "4" mutable: true,
) },
{
echoResponses := func() *echo.Responses { name: "bool_param",
return prepareEchoResponses([]*proto.RichParameter{ // TODO: Setting the type breaks booleans. It claims the default is false
{Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, // but when you then accept this default it errors saying that the value
{Name: secondParameterName, DisplayName: secondParameterDisplayName, Description: secondParameterDescription, Mutable: true}, // must be true or false. For now, use a string.
{Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, ptype: "string",
}) value: "false",
mutable: true,
},
{
name: "immutable_string_param",
ptype: "string",
value: "i am eternal",
mutable: false,
},
} }
t.Run("InputParameters", func(t *testing.T) { type testContext struct {
t.Parallel() client *codersdk.Client
member *codersdk.Client
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) owner codersdk.CreateFirstUserResponse
owner := coderdtest.CreateFirstUser(t, client) template codersdk.Template
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) workspaceName string
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses())
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
inv, root := clitest.New(t, "create", "my-workspace", "--template", template.Name)
clitest.SetupConfig(t, member, root)
doneChan := make(chan struct{})
pty := ptytest.New(t).Attach(inv)
go func() {
defer close(doneChan)
err := inv.Run()
assert.NoError(t, err)
}()
matches := []string{
firstParameterDescription, firstParameterValue,
secondParameterDisplayName, "",
secondParameterDescription, secondParameterValue,
immutableParameterDescription, immutableParameterValue,
"Confirm create?", "yes",
} }
for i := 0; i < len(matches); i += 2 {
match := matches[i]
value := matches[i+1]
pty.ExpectMatch(match)
if value != "" { tests := []struct {
pty.WriteLine(value) name string
} // setup runs before the command is started and return arguments that will
} // be appended to the create command.
<-doneChan setup func() []string
}) // handlePty optionally runs after the command is started. It should handle
// all expected prompts from the pty.
t.Run("ParametersDefaults", func(t *testing.T) { handlePty func(pty *ptytest.PTY)
t.Parallel() // postRun runs after the command has finished but before the workspace is
// verified. It must return the workspace name to check (used for the copy
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) // workspace tests).
owner := coderdtest.CreateFirstUser(t, client) postRun func(t *testing.T, args testContext) string
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) // errors contains expected errors. The workspace will not be verified if
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses()) // errors are expected.
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) errors []string
// inputParameters overrides the default parameters.
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) inputParameters []param
// expectedParameters defaults to inputParameters.
inv, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, expectedParameters []param
"--parameter-default", fmt.Sprintf("%s=%s", firstParameterName, firstParameterValue), // withDefaults sets DefaultValue to each parameter's value.
"--parameter-default", fmt.Sprintf("%s=%s", secondParameterName, secondParameterValue), withDefaults bool
"--parameter-default", fmt.Sprintf("%s=%s", immutableParameterName, immutableParameterValue)) }{
clitest.SetupConfig(t, member, root) {
doneChan := make(chan struct{}) name: "ValuesFromPrompt",
pty := ptytest.New(t).Attach(inv) handlePty: func(pty *ptytest.PTY) {
go func() { // Enter the value for each parameter as prompted.
defer close(doneChan) for _, param := range params {
err := inv.Run() pty.ExpectMatch(param.name)
assert.NoError(t, err) pty.WriteLine(param.value)
}()
matches := []string{
firstParameterDescription, firstParameterValue,
secondParameterDescription, secondParameterValue,
immutableParameterDescription, immutableParameterValue,
}
for i := 0; i < len(matches); i += 2 {
match := matches[i]
defaultValue := matches[i+1]
pty.ExpectMatch(match)
pty.ExpectMatch(`Enter a value (default: "` + defaultValue + `")`)
pty.WriteLine("")
} }
// Confirm the creation.
pty.ExpectMatch("Confirm create?") pty.ExpectMatch("Confirm create?")
pty.WriteLine("yes") pty.WriteLine("yes")
<-doneChan },
},
{
name: "ValuesFromDefaultFlags",
setup: func() []string {
// Provide the defaults on the command line.
args := []string{}
for _, param := range params {
args = append(args, "--parameter-default", fmt.Sprintf("%s=%s", param.name, param.value))
}
return args
},
handlePty: func(pty *ptytest.PTY) {
// Simply accept the defaults.
for _, param := range params {
pty.ExpectMatch(param.name)
pty.ExpectMatch(`Enter a value (default: "` + param.value + `")`)
pty.WriteLine("")
}
// Confirm the creation.
pty.ExpectMatch("Confirm create?")
pty.WriteLine("yes")
},
},
{
name: "ValuesFromFile",
setup: func() []string {
// Create a file with the values.
tempDir := t.TempDir()
removeTmpDirUntilSuccessAfterTest(t, tempDir)
parameterFile, _ := os.CreateTemp(tempDir, "testParameterFile*.yaml")
for _, param := range params {
_, err := parameterFile.WriteString(fmt.Sprintf("%s: %s\n", param.name, param.value))
require.NoError(t, err)
}
// Verify that the expected default values were used. return []string{"--rich-parameter-file", parameterFile.Name()}
},
handlePty: func(pty *ptytest.PTY) {
// No prompts, we only need to confirm.
pty.ExpectMatch("Confirm create?")
pty.WriteLine("yes")
},
},
{
name: "ValuesFromFlags",
setup: func() []string {
// Provide the values on the command line.
var args []string
for _, param := range params {
args = append(args, "--parameter", fmt.Sprintf("%s=%s", param.name, param.value))
}
return args
},
handlePty: func(pty *ptytest.PTY) {
// No prompts, we only need to confirm.
pty.ExpectMatch("Confirm create?")
pty.WriteLine("yes")
},
},
{
name: "MisspelledParameter",
setup: func() []string {
// Provide the values on the command line.
args := []string{}
for i, param := range params {
if i == 0 {
// Slightly misspell the first parameter with an extra character.
args = append(args, "--parameter", fmt.Sprintf("n%s=%s", param.name, param.value))
} else {
args = append(args, "--parameter", fmt.Sprintf("%s=%s", param.name, param.value))
}
}
return args
},
errors: []string{
"parameter \"n" + params[0].name + "\" is not present in the template",
"Did you mean: " + params[0].name,
},
},
{
name: "ValuesFromWorkspace",
setup: func() []string {
// Provide the values on the command line.
args := []string{"-y"}
for _, param := range params {
args = append(args, "--parameter", fmt.Sprintf("%s=%s", param.name, param.value))
}
return args
},
postRun: func(t *testing.T, tctx testContext) string {
inv, root := clitest.New(t, "create", "--copy-parameters-from", tctx.workspaceName, "other-workspace", "-y")
clitest.SetupConfig(t, tctx.member, root)
pty := ptytest.New(t).Attach(inv)
inv.Stdout = pty.Output()
inv.Stderr = pty.Output()
err := inv.Run()
require.NoError(t, err, "failed to create a workspace based on the source workspace")
return "other-workspace"
},
},
{
name: "ValuesFromOutdatedWorkspace",
setup: func() []string {
// Provide the values on the command line.
args := []string{"-y"}
for _, param := range params {
args = append(args, "--parameter", fmt.Sprintf("%s=%s", param.name, param.value))
}
return args
},
postRun: func(t *testing.T, tctx testContext) string {
// Update the template to a new version.
version2 := coderdtest.CreateTemplateVersion(t, tctx.client, tctx.owner.OrganizationID, prepareEchoResponses([]*proto.RichParameter{
{Name: "another_parameter", Type: "string", DefaultValue: "not-relevant"},
}), func(ctvr *codersdk.CreateTemplateVersionRequest) {
ctvr.TemplateID = tctx.template.ID
})
coderdtest.AwaitTemplateVersionJobCompleted(t, tctx.client, version2.ID)
coderdtest.UpdateActiveTemplateVersion(t, tctx.client, tctx.template.ID, version2.ID)
// Then create the copy. It should use the old template version.
inv, root := clitest.New(t, "create", "--copy-parameters-from", tctx.workspaceName, "other-workspace", "-y")
clitest.SetupConfig(t, tctx.member, root)
pty := ptytest.New(t).Attach(inv)
inv.Stdout = pty.Output()
inv.Stderr = pty.Output()
err := inv.Run()
require.NoError(t, err, "failed to create a workspace based on the source workspace")
return "other-workspace"
},
},
{
name: "ValuesFromTemplateDefaults",
handlePty: func(pty *ptytest.PTY) {
// Simply accept the defaults.
for _, param := range params {
pty.ExpectMatch(param.name)
pty.ExpectMatch(`Enter a value (default: "` + param.value + `")`)
pty.WriteLine("")
}
// Confirm the creation.
pty.ExpectMatch("Confirm create?")
pty.WriteLine("yes")
},
withDefaults: true,
},
{
name: "ValuesFromTemplateDefaultsNoPrompt",
setup: func() []string {
return []string{"--use-parameter-defaults"}
},
handlePty: func(pty *ptytest.PTY) {
// Default values should get printed.
for _, param := range params {
pty.ExpectMatch(fmt.Sprintf("%s: '%s'", param.name, param.value))
}
// No prompts, we only need to confirm.
pty.ExpectMatch("Confirm create?")
pty.WriteLine("yes")
},
withDefaults: true,
},
{
name: "ValuesFromDefaultFlagsNoPrompt",
setup: func() []string {
// Provide the defaults on the command line.
args := []string{"--use-parameter-defaults"}
for _, param := range params {
args = append(args, "--parameter-default", fmt.Sprintf("%s=%s", param.name, param.value))
}
return args
},
handlePty: func(pty *ptytest.PTY) {
// Default values should get printed.
for _, param := range params {
pty.ExpectMatch(fmt.Sprintf("%s: '%s'", param.name, param.value))
}
// No prompts, we only need to confirm.
pty.ExpectMatch("Confirm create?")
pty.WriteLine("yes")
},
},
{
// File and flags should override template defaults. Additionally, if a
// value has no default value we should still get a prompt for it.
name: "ValuesFromMultipleSources",
setup: func() []string {
tempDir := t.TempDir()
removeTmpDirUntilSuccessAfterTest(t, tempDir)
parameterFile, _ := os.CreateTemp(tempDir, "testParameterFile*.yaml")
_, err := parameterFile.WriteString(`
file_param: from file
cli_param: from file`)
require.NoError(t, err)
return []string{
"--use-parameter-defaults",
"--rich-parameter-file", parameterFile.Name(),
"--parameter-default", "file_param=from cli default",
"--parameter-default", "cli_param=from cli default",
"--parameter", "cli_param=from cli",
}
},
handlePty: func(pty *ptytest.PTY) {
// Should get prompted for the input param since it has no default.
pty.ExpectMatch("input_param")
pty.WriteLine("from input")
// Confirm the creation.
pty.ExpectMatch("Confirm create?")
pty.WriteLine("yes")
},
withDefaults: true,
inputParameters: []param{
{
name: "template_param",
value: "from template default",
},
{
name: "file_param",
value: "from template default",
},
{
name: "cli_param",
value: "from template default",
},
{
name: "input_param",
},
},
expectedParameters: []param{
{
name: "template_param",
value: "from template default",
},
{
name: "file_param",
value: "from file",
},
{
name: "cli_param",
value: "from cli",
},
{
name: "input_param",
value: "from input",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
parameters := params
if len(tt.inputParameters) > 0 {
parameters = tt.inputParameters
}
// Convert parameters for the echo provisioner response.
var rparams []*proto.RichParameter
for i, param := range parameters {
defaultValue := ""
if tt.withDefaults {
defaultValue = param.value
}
rparams = append(rparams, &proto.RichParameter{
Name: param.name,
Type: param.ptype,
Mutable: param.mutable,
DefaultValue: defaultValue,
Order: int32(i), //nolint:gosec
})
}
// Set up the template.
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, client)
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, prepareEchoResponses(rparams))
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
// Run the command, possibly setting up values.
workspaceName := "my-workspace"
args := []string{"create", workspaceName, "--template", template.Name}
if tt.setup != nil {
args = append(args, tt.setup()...)
}
inv, root := clitest.New(t, args...)
clitest.SetupConfig(t, member, root)
doneChan := make(chan error)
pty := ptytest.New(t).Attach(inv)
go func() {
doneChan <- inv.Run()
}()
// The test may do something with the pty.
if tt.handlePty != nil {
tt.handlePty(pty)
}
// Wait for the command to exit.
err := <-doneChan
// The test may want to run additional setup like copying the workspace.
if tt.postRun != nil {
workspaceName = tt.postRun(t, testContext{
client: client,
member: member,
owner: owner,
template: template,
workspaceName: workspaceName,
})
}
if len(tt.errors) > 0 {
require.Error(t, err)
for _, errstr := range tt.errors {
assert.ErrorContains(t, err, errstr)
}
} else {
require.NoError(t, err)
// Verify the workspace was created and has the right template and values.
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel() defer cancel()
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{ workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{Name: workspaceName})
Name: "my-workspace", require.NoError(t, err, "expected to find created workspace")
})
require.NoError(t, err, "can't list available workspaces")
require.Len(t, workspaces.Workspaces, 1) require.Len(t, workspaces.Workspaces, 1)
workspaceLatestBuild := workspaces.Workspaces[0].LatestBuild workspaceLatestBuild := workspaces.Workspaces[0].LatestBuild
@@ -440,231 +739,16 @@ func TestCreateWithRichParameters(t *testing.T) {
buildParameters, err := client.WorkspaceBuildParameters(ctx, workspaceLatestBuild.ID) buildParameters, err := client.WorkspaceBuildParameters(ctx, workspaceLatestBuild.ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, buildParameters, 3) if len(tt.expectedParameters) > 0 {
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: firstParameterName, Value: firstParameterValue}) parameters = tt.expectedParameters
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: secondParameterName, Value: secondParameterValue})
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: immutableParameterName, Value: immutableParameterValue})
})
t.Run("RichParametersFile", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, client)
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses())
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
tempDir := t.TempDir()
removeTmpDirUntilSuccessAfterTest(t, tempDir)
parameterFile, _ := os.CreateTemp(tempDir, "testParameterFile*.yaml")
_, _ = parameterFile.WriteString(
firstParameterName + ": " + firstParameterValue + "\n" +
secondParameterName + ": " + secondParameterValue + "\n" +
immutableParameterName + ": " + immutableParameterValue)
inv, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "--rich-parameter-file", parameterFile.Name())
clitest.SetupConfig(t, member, root)
doneChan := make(chan struct{})
pty := ptytest.New(t).Attach(inv)
go func() {
defer close(doneChan)
err := inv.Run()
assert.NoError(t, err)
}()
matches := []string{
"Confirm create?", "yes",
} }
for i := 0; i < len(matches); i += 2 { require.Len(t, buildParameters, len(parameters))
match := matches[i] for _, param := range parameters {
value := matches[i+1] require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: param.name, Value: param.value})
pty.ExpectMatch(match)
pty.WriteLine(value)
} }
<-doneChan
})
t.Run("ParameterFlags", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, client)
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses())
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
inv, root := clitest.New(t, "create", "my-workspace", "--template", template.Name,
"--parameter", fmt.Sprintf("%s=%s", firstParameterName, firstParameterValue),
"--parameter", fmt.Sprintf("%s=%s", secondParameterName, secondParameterValue),
"--parameter", fmt.Sprintf("%s=%s", immutableParameterName, immutableParameterValue))
clitest.SetupConfig(t, member, root)
doneChan := make(chan struct{})
pty := ptytest.New(t).Attach(inv)
go func() {
defer close(doneChan)
err := inv.Run()
assert.NoError(t, err)
}()
matches := []string{
"Confirm create?", "yes",
} }
for i := 0; i < len(matches); i += 2 { })
match := matches[i]
value := matches[i+1]
pty.ExpectMatch(match)
pty.WriteLine(value)
} }
<-doneChan
})
t.Run("WrongParameterName/DidYouMean", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, client)
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses())
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
wrongFirstParameterName := "frst-prameter"
inv, root := clitest.New(t, "create", "my-workspace", "--template", template.Name,
"--parameter", fmt.Sprintf("%s=%s", wrongFirstParameterName, firstParameterValue),
"--parameter", fmt.Sprintf("%s=%s", secondParameterName, secondParameterValue),
"--parameter", fmt.Sprintf("%s=%s", immutableParameterName, immutableParameterValue))
clitest.SetupConfig(t, member, root)
pty := ptytest.New(t).Attach(inv)
inv.Stdout = pty.Output()
inv.Stderr = pty.Output()
err := inv.Run()
assert.ErrorContains(t, err, "parameter \""+wrongFirstParameterName+"\" is not present in the template")
assert.ErrorContains(t, err, "Did you mean: "+firstParameterName)
})
t.Run("CopyParameters", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, client)
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses())
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
// Firstly, create a regular workspace using template with parameters.
inv, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "-y",
"--parameter", fmt.Sprintf("%s=%s", firstParameterName, firstParameterValue),
"--parameter", fmt.Sprintf("%s=%s", secondParameterName, secondParameterValue),
"--parameter", fmt.Sprintf("%s=%s", immutableParameterName, immutableParameterValue))
clitest.SetupConfig(t, member, root)
pty := ptytest.New(t).Attach(inv)
inv.Stdout = pty.Output()
inv.Stderr = pty.Output()
err := inv.Run()
require.NoError(t, err, "can't create first workspace")
// Secondly, create a new workspace using parameters from the previous workspace.
const otherWorkspace = "other-workspace"
inv, root = clitest.New(t, "create", "--copy-parameters-from", "my-workspace", otherWorkspace, "-y")
clitest.SetupConfig(t, member, root)
pty = ptytest.New(t).Attach(inv)
inv.Stdout = pty.Output()
inv.Stderr = pty.Output()
err = inv.Run()
require.NoError(t, err, "can't create a workspace based on the source workspace")
// Verify if the new workspace uses expected parameters.
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
Name: otherWorkspace,
})
require.NoError(t, err, "can't list available workspaces")
require.Len(t, workspaces.Workspaces, 1)
otherWorkspaceLatestBuild := workspaces.Workspaces[0].LatestBuild
buildParameters, err := client.WorkspaceBuildParameters(ctx, otherWorkspaceLatestBuild.ID)
require.NoError(t, err)
require.Len(t, buildParameters, 3)
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: firstParameterName, Value: firstParameterValue})
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: secondParameterName, Value: secondParameterValue})
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: immutableParameterName, Value: immutableParameterValue})
})
t.Run("CopyParametersFromNotUpdatedWorkspace", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, client)
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses())
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
// Firstly, create a regular workspace using template with parameters.
inv, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "-y",
"--parameter", fmt.Sprintf("%s=%s", firstParameterName, firstParameterValue),
"--parameter", fmt.Sprintf("%s=%s", secondParameterName, secondParameterValue),
"--parameter", fmt.Sprintf("%s=%s", immutableParameterName, immutableParameterValue))
clitest.SetupConfig(t, member, root)
pty := ptytest.New(t).Attach(inv)
inv.Stdout = pty.Output()
inv.Stderr = pty.Output()
err := inv.Run()
require.NoError(t, err, "can't create first workspace")
// Secondly, update the template to the newer version.
version2 := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, prepareEchoResponses([]*proto.RichParameter{
{Name: "third_parameter", Type: "string", DefaultValue: "not-relevant"},
}), func(ctvr *codersdk.CreateTemplateVersionRequest) {
ctvr.TemplateID = template.ID
})
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version2.ID)
coderdtest.UpdateActiveTemplateVersion(t, client, template.ID, version2.ID)
// Thirdly, create a new workspace using parameters from the previous workspace.
const otherWorkspace = "other-workspace"
inv, root = clitest.New(t, "create", "--copy-parameters-from", "my-workspace", otherWorkspace, "-y")
clitest.SetupConfig(t, member, root)
pty = ptytest.New(t).Attach(inv)
inv.Stdout = pty.Output()
inv.Stderr = pty.Output()
err = inv.Run()
require.NoError(t, err, "can't create a workspace based on the source workspace")
// Verify if the new workspace uses expected parameters.
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
Name: otherWorkspace,
})
require.NoError(t, err, "can't list available workspaces")
require.Len(t, workspaces.Workspaces, 1)
otherWorkspaceLatestBuild := workspaces.Workspaces[0].LatestBuild
require.Equal(t, version.ID, otherWorkspaceLatestBuild.TemplateVersionID)
buildParameters, err := client.WorkspaceBuildParameters(ctx, otherWorkspaceLatestBuild.ID)
require.NoError(t, err)
require.Len(t, buildParameters, 3)
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: firstParameterName, Value: firstParameterValue})
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: secondParameterName, Value: secondParameterValue})
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: immutableParameterName, Value: immutableParameterValue})
})
} }
func TestCreateWithPreset(t *testing.T) { func TestCreateWithPreset(t *testing.T) {
+33 -3
View File
@@ -34,6 +34,7 @@ type ParameterResolver struct {
promptRichParameters bool promptRichParameters bool
promptEphemeralParameters bool promptEphemeralParameters bool
useParameterDefaults bool
} }
func (pr *ParameterResolver) WithLastBuildParameters(params []codersdk.WorkspaceBuildParameter) *ParameterResolver { func (pr *ParameterResolver) WithLastBuildParameters(params []codersdk.WorkspaceBuildParameter) *ParameterResolver {
@@ -86,8 +87,21 @@ func (pr *ParameterResolver) WithPromptEphemeralParameters(promptEphemeralParame
return pr return pr
} }
// Resolve gathers workspace build parameters in a layered fashion, applying values from various sources func (pr *ParameterResolver) WithUseParameterDefaults(useParameterDefaults bool) *ParameterResolver {
// in order of precedence: parameter file < CLI/ENV < source build < last build < preset < user input. pr.useParameterDefaults = useParameterDefaults
return pr
}
// Resolve gathers workspace build parameters in a layered fashion, applying
// values from various sources in order of precedence:
// 1. template defaults (if auto-accepting defaults)
// 2. cli parameter defaults (if auto-accepting defaults)
// 3. parameter file
// 4. CLI/ENV
// 5. source build
// 6. last build
// 7. preset
// 8. user input (unless auto-accepting defaults)
func (pr *ParameterResolver) Resolve(inv *serpent.Invocation, action WorkspaceCLIAction, templateVersionParameters []codersdk.TemplateVersionParameter) ([]codersdk.WorkspaceBuildParameter, error) { func (pr *ParameterResolver) Resolve(inv *serpent.Invocation, action WorkspaceCLIAction, templateVersionParameters []codersdk.TemplateVersionParameter) ([]codersdk.WorkspaceBuildParameter, error) {
var staged []codersdk.WorkspaceBuildParameter var staged []codersdk.WorkspaceBuildParameter
var err error var err error
@@ -262,10 +276,26 @@ func (pr *ParameterResolver) resolveWithInput(resolved []codersdk.WorkspaceBuild
(action == WorkspaceUpdate && tvp.Mutable && tvp.Required) || (action == WorkspaceUpdate && tvp.Mutable && tvp.Required) ||
(action == WorkspaceUpdate && !tvp.Mutable && firstTimeUse) || (action == WorkspaceUpdate && !tvp.Mutable && firstTimeUse) ||
(tvp.Mutable && !tvp.Ephemeral && pr.promptRichParameters) { (tvp.Mutable && !tvp.Ephemeral && pr.promptRichParameters) {
parameterValue, err := cliui.RichParameter(inv, tvp, pr.richParametersDefaults) name := tvp.Name
if tvp.DisplayName != "" {
name = tvp.DisplayName
}
parameterValue := tvp.DefaultValue
if v, ok := pr.richParametersDefaults[tvp.Name]; ok {
parameterValue = v
}
// Auto-accept the default if there is one.
if pr.useParameterDefaults && parameterValue != "" {
_, _ = fmt.Fprintf(inv.Stdout, "Using default value for %s: '%s'\n", name, parameterValue)
} else {
var err error
parameterValue, err = cliui.RichParameter(inv, tvp, name, parameterValue)
if err != nil { if err != nil {
return nil, err return nil, err
} }
}
resolved = append(resolved, codersdk.WorkspaceBuildParameter{ resolved = append(resolved, codersdk.WorkspaceBuildParameter{
Name: tvp.Name, Name: tvp.Name,
+1 -1
View File
@@ -7,7 +7,7 @@ USAGE:
OPTIONS: OPTIONS:
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -55,7 +55,7 @@ OPTIONS:
configured in the workspace template is used. configured in the workspace template is used.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+4 -1
View File
@@ -49,8 +49,11 @@ OPTIONS:
--template-version string, $CODER_TEMPLATE_VERSION --template-version string, $CODER_TEMPLATE_VERSION
Specify a template version name. Specify a template version name.
--use-parameter-defaults bool, $CODER_WORKSPACE_USE_PARAMETER_DEFAULTS
Automatically accept parameter defaults when no value is provided.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -18,7 +18,7 @@ OPTIONS:
resources. resources.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -24,7 +24,7 @@ OPTIONS:
empty, will use $HOME. empty, will use $HOME.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -7,7 +7,7 @@ USAGE:
OPTIONS: OPTIONS:
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -7,7 +7,7 @@ USAGE:
OPTIONS: OPTIONS:
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
@@ -18,7 +18,7 @@ OPTIONS:
Reads stdin for the json role definition to upload. Reads stdin for the json role definition to upload.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
@@ -23,7 +23,7 @@ OPTIONS:
Reads stdin for the json role definition to upload. Reads stdin for the json role definition to upload.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -13,7 +13,7 @@ OPTIONS:
services it's registered with. services it's registered with.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -7,7 +7,7 @@ USAGE:
OPTIONS: OPTIONS:
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -39,7 +39,7 @@ OPTIONS:
pairs for the parameters. pairs for the parameters.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -42,7 +42,7 @@ OPTIONS:
pairs for the parameters. pairs for the parameters.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -7,7 +7,7 @@ USAGE:
OPTIONS: OPTIONS:
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -19,7 +19,7 @@ OPTIONS:
example, if you need to troubleshoot a specific Coder replica. example, if you need to troubleshoot a specific Coder replica.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -21,7 +21,7 @@ USAGE:
OPTIONS: OPTIONS:
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -14,7 +14,7 @@ OPTIONS:
versions are archived. versions are archived.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -68,7 +68,7 @@ OPTIONS:
Specify a file path with values for Terraform-managed variables. Specify a file path with values for Terraform-managed variables.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -12,7 +12,7 @@ OPTIONS:
Select which organization (uuid or name) to use. Select which organization (uuid or name) to use.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -91,7 +91,7 @@ OPTIONS:
for more details. for more details.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -18,7 +18,7 @@ OPTIONS:
the template version to pull. the template version to pull.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
--zip bool --zip bool
Output the template as a zip archive to stdout. Output the template as a zip archive to stdout.
+1 -1
View File
@@ -48,7 +48,7 @@ OPTIONS:
Specify a file path with values for Terraform-managed variables. Specify a file path with values for Terraform-managed variables.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
@@ -11,7 +11,7 @@ OPTIONS:
Select which organization (uuid or name) to use. Select which organization (uuid or name) to use.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
@@ -11,7 +11,7 @@ OPTIONS:
Select which organization (uuid or name) to use. Select which organization (uuid or name) to use.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -11,7 +11,7 @@ OPTIONS:
the user may have. the user may have.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+1 -1
View File
@@ -17,4 +17,4 @@ coder autoupdate [flags] <workspace> <always|never>
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -114,4 +114,4 @@ Disable starting the workspace automatically when connecting via SSH.
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+10 -1
View File
@@ -83,13 +83,22 @@ Specify automatic updates setting for the workspace (accepts 'always' or 'never'
Specify the source workspace name to copy parameters from. Specify the source workspace name to copy parameters from.
### --use-parameter-defaults
| | |
|-------------|------------------------------------------------------|
| Type | <code>bool</code> |
| Environment | <code>$CODER_WORKSPACE_USE_PARAMETER_DEFAULTS</code> |
Automatically accept parameter defaults when no value is provided.
### -y, --yes ### -y, --yes
| | | | | |
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### --parameter ### --parameter
+1 -1
View File
@@ -37,4 +37,4 @@ Delete a workspace without deleting its resources. This can delete a workspace i
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -52,4 +52,4 @@ Specifies the directory for the dotfiles repository, relative to global config d
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+10 -1
View File
@@ -83,13 +83,22 @@ Specify automatic updates setting for the workspace (accepts 'always' or 'never'
Specify the source workspace name to copy parameters from. Specify the source workspace name to copy parameters from.
### --use-parameter-defaults
| | |
|-------------|------------------------------------------------------|
| Type | <code>bool</code> |
| Environment | <code>$CODER_WORKSPACE_USE_PARAMETER_DEFAULTS</code> |
Automatically accept parameter defaults when no value is provided.
### -y, --yes ### -y, --yes
| | | | | |
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### --parameter ### --parameter
+1 -1
View File
@@ -17,4 +17,4 @@ coder logout [flags]
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -17,4 +17,4 @@ coder organizations create [flags] <organization name>
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -25,7 +25,7 @@ coder organizations roles create [flags] <role_name>
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### --dry-run ### --dry-run
+1 -1
View File
@@ -25,7 +25,7 @@ coder organizations roles update [flags] <role_name>
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### --dry-run ### --dry-run
+1 -1
View File
@@ -21,7 +21,7 @@ coder provisioner keys delete [flags] <name>
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### -O, --org ### -O, --org
+1 -1
View File
@@ -29,4 +29,4 @@ Regenerate your public key. This will require updating the key on any services i
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -17,4 +17,4 @@ coder rename [flags] <workspace> <new name>
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -17,7 +17,7 @@ coder restart [flags] <workspace>
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### --build-option ### --build-option
+1 -1
View File
@@ -45,4 +45,4 @@ Keys required to decrypt existing data. Must be a comma-separated list of base64
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -40,4 +40,4 @@ Type of auth to use when connecting to postgres.
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -54,4 +54,4 @@ The old external token encryption keys. Must be a comma-separated list of base64
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -25,7 +25,7 @@ Return immediately after starting the workspace.
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### --build-option ### --build-option
+1 -1
View File
@@ -17,4 +17,4 @@ coder stop [flags] <workspace>
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -23,7 +23,7 @@ This command generates a file containing detailed troubleshooting information ab
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### -O, --output-file ### -O, --output-file
+1 -1
View File
@@ -37,4 +37,4 @@ coder task delete [flags] <task> [<task> ...]
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
+1 -1
View File
@@ -17,7 +17,7 @@ coder templates archive [flags] [template-name...]
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### --all ### --all
+1 -1
View File
@@ -102,7 +102,7 @@ Requires workspace builds to use the active template version. This setting does
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### -O, --org ### -O, --org
+1 -1
View File
@@ -21,7 +21,7 @@ coder templates delete [flags] [name...]
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### -O, --org ### -O, --org
+1 -1
View File
@@ -169,7 +169,7 @@ Disable the default behavior of granting template access to the 'everyone' group
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### -O, --org ### -O, --org
+1 -1
View File
@@ -41,7 +41,7 @@ The name of the template version to pull. Use 'active' to pull the active versio
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### -O, --org ### -O, --org
+1 -1
View File
@@ -74,7 +74,7 @@ Whether the new template will be marked active.
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### -d, --directory ### -d, --directory
+1 -1
View File
@@ -17,7 +17,7 @@ coder templates versions archive [flags] <template-name> [template-version-names
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### -O, --org ### -O, --org
+1 -1
View File
@@ -17,7 +17,7 @@ coder templates versions unarchive [flags] <template-name> [template-version-nam
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### -O, --org ### -O, --org
+1 -1
View File
@@ -17,7 +17,7 @@ coder users edit-roles [flags] <username|user_id>
|------|-------------------| |------|-------------------|
| Type | <code>bool</code> | | Type | <code>bool</code> |
Bypass prompts. Bypass confirmation prompts.
### --roles ### --roles
@@ -49,8 +49,11 @@ OPTIONS:
--template-version string, $CODER_TEMPLATE_VERSION --template-version string, $CODER_TEMPLATE_VERSION
Specify a template version name. Specify a template version name.
--use-parameter-defaults bool, $CODER_WORKSPACE_USE_PARAMETER_DEFAULTS
Automatically accept parameter defaults when no value is provided.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
@@ -12,7 +12,7 @@ OPTIONS:
Select which organization (uuid or name) to use. Select which organization (uuid or name) to use.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
@@ -17,7 +17,7 @@ OPTIONS:
The connection URL for the Postgres database. The connection URL for the Postgres database.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
@@ -15,7 +15,7 @@ OPTIONS:
The connection URL for the Postgres database. The connection URL for the Postgres database.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
@@ -20,7 +20,7 @@ OPTIONS:
The connection URL for the Postgres database. The connection URL for the Postgres database.
-y, --yes bool -y, --yes bool
Bypass prompts. Bypass confirmation prompts.
——— ———
Run `coder --help` for a list of global options. Run `coder --help` for a list of global options.
+8
View File
@@ -660,7 +660,15 @@ data "coder_parameter" "{{ .Name }}" {
ephemeral = {{ .Ephemeral }} ephemeral = {{ .Ephemeral }}
order = {{ .Order }} order = {{ .Order }}
{{- if .DefaultValue }} {{- if .DefaultValue }}
{{- if eq .Type "list(string)" }}
default = jsonencode({{ .DefaultValue }})
{{else if eq .Type "bool"}}
default = {{ .DefaultValue }} default = {{ .DefaultValue }}
{{else if eq .Type "number"}}
default = {{ .DefaultValue }}
{{else}}
default = "{{ .DefaultValue }}"
{{- end }}
{{- end }} {{- end }}
{{- if .Type }} {{- if .Type }}
type = "{{ .Type }}" type = "{{ .Type }}"