diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index d972e346bf196..772b78cc55325 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -10,12 +10,8 @@ import ( "github.com/coder/serpent" ) -func RichParameter(inv *serpent.Invocation, templateVersionParameter codersdk.TemplateVersionParameter, defaultOverrides map[string]string) (string, error) { - label := templateVersionParameter.Name - if templateVersionParameter.DisplayName != "" { - label = templateVersionParameter.DisplayName - } - +func RichParameter(inv *serpent.Invocation, templateVersionParameter codersdk.TemplateVersionParameter, name, defaultValue string) (string, error) { + label := name if templateVersionParameter.Ephemeral { 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") } - defaultValue := templateVersionParameter.DefaultValue - if v, ok := defaultOverrides[templateVersionParameter.Name]; ok { - defaultValue = v - } - var err error var value string switch { diff --git a/cli/cliui/prompt.go b/cli/cliui/prompt.go index 264ebf2939780..661c256db5c19 100644 --- a/cli/cliui/prompt.go +++ b/cli/cliui/prompt.go @@ -32,12 +32,12 @@ type PromptOptions struct { const skipPromptFlag = "yes" // SkipPromptOption adds a "--yes/-y" flag to the cmd that can be used to skip -// prompts. +// confirmation prompts. func SkipPromptOption() serpent.Option { return serpent.Option{ Flag: skipPromptFlag, FlagShorthand: "y", - Description: "Bypass prompts.", + Description: "Bypass confirmation prompts.", // Discard Value: serpent.BoolOf(new(bool)), } diff --git a/cli/create.go b/cli/create.go index 225d05950e77c..8216e38b15619 100644 --- a/cli/create.go +++ b/cli/create.go @@ -43,9 +43,10 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command { stopAfter time.Duration workspaceName string - parameterFlags workspaceParameterFlags - autoUpdates string - copyParametersFrom string + parameterFlags workspaceParameterFlags + autoUpdates string + copyParametersFrom string + useParameterDefaults bool // Organization context is only required if more than 1 template // shares the same name across multiple organizations. orgContext = NewOrganizationContext() @@ -309,7 +310,7 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command { displayAppliedPreset(inv, preset, presetParameters) } else { // 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 { @@ -330,6 +331,8 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command { RichParameterDefaults: cliBuildParameterDefaults, SourceWorkspaceParameters: sourceWorkspaceParameters, + + UseParameterDefaults: useParameterDefaults, }) if err != nil { return xerrors.Errorf("prepare build: %w", err) @@ -436,6 +439,12 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command { Description: "Specify the source workspace name to copy parameters from.", Value: serpent.StringOf(©ParametersFrom), }, + 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(), ) cmd.Options = append(cmd.Options, parameterFlags.cliParameters()...) @@ -460,6 +469,8 @@ type prepWorkspaceBuildArgs struct { RichParameters []codersdk.WorkspaceBuildParameter RichParameterFile string RichParameterDefaults []codersdk.WorkspaceBuildParameter + + UseParameterDefaults bool } // resolvePreset returns the preset matching the given presetName (if specified), @@ -562,7 +573,8 @@ func prepWorkspaceBuild(inv *serpent.Invocation, client *codersdk.Client, args p WithPromptRichParameters(args.PromptRichParameters). WithRichParameters(args.RichParameters). WithRichParametersFile(parameterFile). - WithRichParametersDefaults(args.RichParameterDefaults) + WithRichParametersDefaults(args.RichParameterDefaults). + WithUseParameterDefaults(args.UseParameterDefaults) buildParameters, err := resolver.Resolve(inv, args.Action, templateVersionParameters) if err != nil { return nil, err diff --git a/cli/create_test.go b/cli/create_test.go index dd26e450d3916..1b3a9327c1d3e 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -316,353 +316,437 @@ func prepareEchoResponses(parameters []*proto.RichParameter, presets ...*proto.P } } +type param struct { + name string + ptype string + value string + mutable bool +} + func TestCreateWithRichParameters(t *testing.T) { t.Parallel() - const ( - firstParameterName = "first_parameter" - firstParameterDescription = "This is first parameter" - firstParameterValue = "1" - - secondParameterName = "second_parameter" - secondParameterDisplayName = "Second Parameter" - secondParameterDescription = "This is second parameter" - secondParameterValue = "2" - - immutableParameterName = "third_parameter" - immutableParameterDescription = "This is not mutable parameter" - immutableParameterValue = "4" - ) - - echoResponses := func() *echo.Responses { - return prepareEchoResponses([]*proto.RichParameter{ - {Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, - {Name: secondParameterName, DisplayName: secondParameterDisplayName, Description: secondParameterDescription, Mutable: true}, - {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, - }) + // Default parameters and their expected values. + params := []param{ + { + name: "number_param", + ptype: "number", + value: "777", + mutable: true, + }, + { + name: "string_param", + ptype: "string", + value: "qux", + mutable: true, + }, + { + name: "bool_param", + // TODO: Setting the type breaks booleans. It claims the default is false + // but when you then accept this default it errors saying that the value + // must be true or false. For now, use a string. + 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) { - 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) + type testContext struct { + client *codersdk.Client + member *codersdk.Client + owner codersdk.CreateFirstUserResponse + template codersdk.Template + workspaceName string + } - 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) - }() + tests := []struct { + name string + // setup runs before the command is started and return arguments that will + // be appended to the create command. + setup func() []string + // handlePty optionally runs after the command is started. It should handle + // all expected prompts from the pty. + handlePty func(pty *ptytest.PTY) + // 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 + // workspace tests). + postRun func(t *testing.T, args testContext) string + // errors contains expected errors. The workspace will not be verified if + // errors are expected. + errors []string + // inputParameters overrides the default parameters. + inputParameters []param + // expectedParameters defaults to inputParameters. + expectedParameters []param + // withDefaults sets DefaultValue to each parameter's value. + withDefaults bool + }{ + { + name: "ValuesFromPrompt", + handlePty: func(pty *ptytest.PTY) { + // Enter the value for each parameter as prompted. + for _, param := range params { + pty.ExpectMatch(param.name) + pty.WriteLine(param.value) + } + // Confirm the creation. + pty.ExpectMatch("Confirm create?") + pty.WriteLine("yes") + }, + }, + { + 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) + } + + 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", + }, + }, + }, + } - 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) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() - if value != "" { - pty.WriteLine(value) + parameters := params + if len(tt.inputParameters) > 0 { + parameters = tt.inputParameters } - } - <-doneChan - }) - - t.Run("ParametersDefaults", 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-default", fmt.Sprintf("%s=%s", firstParameterName, firstParameterValue), - "--parameter-default", fmt.Sprintf("%s=%s", secondParameterName, secondParameterValue), - "--parameter-default", 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{ - 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("") - } - pty.ExpectMatch("Confirm create?") - pty.WriteLine("yes") - <-doneChan - - // Verify that the expected default values were used. - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) - defer cancel() - - workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{ - Name: "my-workspace", - }) - require.NoError(t, err, "can't list available workspaces") - require.Len(t, workspaces.Workspaces, 1) - - workspaceLatestBuild := workspaces.Workspaces[0].LatestBuild - require.Equal(t, version.ID, workspaceLatestBuild.TemplateVersionID) - - buildParameters, err := client.WorkspaceBuildParameters(ctx, workspaceLatestBuild.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("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 { - match := matches[i] - value := matches[i+1] - 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() + // 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 + }) + } - 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) + // 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)) - template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) + 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" + // 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() + }() - 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") + // The test may do something with the pty. + if tt.handlePty != nil { + tt.handlePty(pty) + } - // Verify if the new workspace uses expected parameters. - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) - defer cancel() + // 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, + }) + } - workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{ - Name: otherWorkspace, + 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) + defer cancel() + + workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{Name: workspaceName}) + require.NoError(t, err, "expected to find created workspace") + require.Len(t, workspaces.Workspaces, 1) + + workspaceLatestBuild := workspaces.Workspaces[0].LatestBuild + require.Equal(t, version.ID, workspaceLatestBuild.TemplateVersionID) + + buildParameters, err := client.WorkspaceBuildParameters(ctx, workspaceLatestBuild.ID) + require.NoError(t, err) + if len(tt.expectedParameters) > 0 { + parameters = tt.expectedParameters + } + require.Len(t, buildParameters, len(parameters)) + for _, param := range parameters { + require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: param.name, Value: param.value}) + } + } }) - 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) { diff --git a/cli/parameterresolver.go b/cli/parameterresolver.go index cbd00fb59623e..aa239d85b6f7d 100644 --- a/cli/parameterresolver.go +++ b/cli/parameterresolver.go @@ -34,6 +34,7 @@ type ParameterResolver struct { promptRichParameters bool promptEphemeralParameters bool + useParameterDefaults bool } func (pr *ParameterResolver) WithLastBuildParameters(params []codersdk.WorkspaceBuildParameter) *ParameterResolver { @@ -86,8 +87,21 @@ func (pr *ParameterResolver) WithPromptEphemeralParameters(promptEphemeralParame return pr } -// Resolve gathers workspace build parameters in a layered fashion, applying values from various sources -// in order of precedence: parameter file < CLI/ENV < source build < last build < preset < user input. +func (pr *ParameterResolver) WithUseParameterDefaults(useParameterDefaults bool) *ParameterResolver { + 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) { var staged []codersdk.WorkspaceBuildParameter var err error @@ -262,9 +276,25 @@ func (pr *ParameterResolver) resolveWithInput(resolved []codersdk.WorkspaceBuild (action == WorkspaceUpdate && tvp.Mutable && tvp.Required) || (action == WorkspaceUpdate && !tvp.Mutable && firstTimeUse) || (tvp.Mutable && !tvp.Ephemeral && pr.promptRichParameters) { - parameterValue, err := cliui.RichParameter(inv, tvp, pr.richParametersDefaults) - if err != nil { - return nil, err + 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 { + return nil, err + } } resolved = append(resolved, codersdk.WorkspaceBuildParameter{ diff --git a/cli/testdata/coder_autoupdate_--help.golden b/cli/testdata/coder_autoupdate_--help.golden index 96207daba5b24..04200fa58cbdc 100644 --- a/cli/testdata/coder_autoupdate_--help.golden +++ b/cli/testdata/coder_autoupdate_--help.golden @@ -7,7 +7,7 @@ USAGE: OPTIONS: -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_config-ssh_--help.golden b/cli/testdata/coder_config-ssh_--help.golden index e2b03164d9513..411e7607ff17e 100644 --- a/cli/testdata/coder_config-ssh_--help.golden +++ b/cli/testdata/coder_config-ssh_--help.golden @@ -55,7 +55,7 @@ OPTIONS: configured in the workspace template is used. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_create_--help.golden b/cli/testdata/coder_create_--help.golden index 47e809e8f5af6..1292af1777f90 100644 --- a/cli/testdata/coder_create_--help.golden +++ b/cli/testdata/coder_create_--help.golden @@ -49,8 +49,11 @@ OPTIONS: --template-version string, $CODER_TEMPLATE_VERSION 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 - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_delete_--help.golden b/cli/testdata/coder_delete_--help.golden index f9dfc9b9b93df..d32acdd9c570c 100644 --- a/cli/testdata/coder_delete_--help.golden +++ b/cli/testdata/coder_delete_--help.golden @@ -18,7 +18,7 @@ OPTIONS: resources. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_dotfiles_--help.golden b/cli/testdata/coder_dotfiles_--help.golden index 14991512127da..1f62176089eae 100644 --- a/cli/testdata/coder_dotfiles_--help.golden +++ b/cli/testdata/coder_dotfiles_--help.golden @@ -24,7 +24,7 @@ OPTIONS: empty, will use $HOME. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_logout_--help.golden b/cli/testdata/coder_logout_--help.golden index 8ec08c2ad7553..05b61005f4c18 100644 --- a/cli/testdata/coder_logout_--help.golden +++ b/cli/testdata/coder_logout_--help.golden @@ -7,7 +7,7 @@ USAGE: OPTIONS: -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_organizations_create_--help.golden b/cli/testdata/coder_organizations_create_--help.golden index 729ef373db0a1..bb43fd6d65571 100644 --- a/cli/testdata/coder_organizations_create_--help.golden +++ b/cli/testdata/coder_organizations_create_--help.golden @@ -7,7 +7,7 @@ USAGE: OPTIONS: -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_organizations_roles_create_--help.golden b/cli/testdata/coder_organizations_roles_create_--help.golden index 8bac1a3c788dc..cd5983fb3f98e 100644 --- a/cli/testdata/coder_organizations_roles_create_--help.golden +++ b/cli/testdata/coder_organizations_roles_create_--help.golden @@ -18,7 +18,7 @@ OPTIONS: Reads stdin for the json role definition to upload. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_organizations_roles_update_--help.golden b/cli/testdata/coder_organizations_roles_update_--help.golden index f0c28bd03d078..a04767bcd7732 100644 --- a/cli/testdata/coder_organizations_roles_update_--help.golden +++ b/cli/testdata/coder_organizations_roles_update_--help.golden @@ -23,7 +23,7 @@ OPTIONS: Reads stdin for the json role definition to upload. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_publickey_--help.golden b/cli/testdata/coder_publickey_--help.golden index 7346f892836b0..1c717d3e160a2 100644 --- a/cli/testdata/coder_publickey_--help.golden +++ b/cli/testdata/coder_publickey_--help.golden @@ -13,7 +13,7 @@ OPTIONS: services it's registered with. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_rename_--help.golden b/cli/testdata/coder_rename_--help.golden index 33f9c460006a2..b59f42f68b138 100644 --- a/cli/testdata/coder_rename_--help.golden +++ b/cli/testdata/coder_rename_--help.golden @@ -7,7 +7,7 @@ USAGE: OPTIONS: -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_restart_--help.golden b/cli/testdata/coder_restart_--help.golden index 6208b733457ab..70c54104d9381 100644 --- a/cli/testdata/coder_restart_--help.golden +++ b/cli/testdata/coder_restart_--help.golden @@ -39,7 +39,7 @@ OPTIONS: pairs for the parameters. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_start_--help.golden b/cli/testdata/coder_start_--help.golden index ce1134626c486..096b94e74c93c 100644 --- a/cli/testdata/coder_start_--help.golden +++ b/cli/testdata/coder_start_--help.golden @@ -42,7 +42,7 @@ OPTIONS: pairs for the parameters. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_stop_--help.golden b/cli/testdata/coder_stop_--help.golden index 529c38484668e..fafa524bc97f6 100644 --- a/cli/testdata/coder_stop_--help.golden +++ b/cli/testdata/coder_stop_--help.golden @@ -7,7 +7,7 @@ USAGE: OPTIONS: -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_support_bundle_--help.golden b/cli/testdata/coder_support_bundle_--help.golden index 7b0a5bb18f2a1..fd40548817cd8 100644 --- a/cli/testdata/coder_support_bundle_--help.golden +++ b/cli/testdata/coder_support_bundle_--help.golden @@ -19,7 +19,7 @@ OPTIONS: example, if you need to troubleshoot a specific Coder replica. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_task_delete_--help.golden b/cli/testdata/coder_task_delete_--help.golden index b0169410a9293..15bf1dce3a486 100644 --- a/cli/testdata/coder_task_delete_--help.golden +++ b/cli/testdata/coder_task_delete_--help.golden @@ -21,7 +21,7 @@ USAGE: OPTIONS: -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_templates_archive_--help.golden b/cli/testdata/coder_templates_archive_--help.golden index ebad38db93341..3e0ad402430d3 100644 --- a/cli/testdata/coder_templates_archive_--help.golden +++ b/cli/testdata/coder_templates_archive_--help.golden @@ -14,7 +14,7 @@ OPTIONS: versions are archived. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_templates_create_--help.golden b/cli/testdata/coder_templates_create_--help.golden index 80cccb24a57e3..c0370d93d21ee 100644 --- a/cli/testdata/coder_templates_create_--help.golden +++ b/cli/testdata/coder_templates_create_--help.golden @@ -68,7 +68,7 @@ OPTIONS: Specify a file path with values for Terraform-managed variables. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_templates_delete_--help.golden b/cli/testdata/coder_templates_delete_--help.golden index 4d15b7f34382b..557eef3539751 100644 --- a/cli/testdata/coder_templates_delete_--help.golden +++ b/cli/testdata/coder_templates_delete_--help.golden @@ -12,7 +12,7 @@ OPTIONS: Select which organization (uuid or name) to use. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_templates_edit_--help.golden b/cli/testdata/coder_templates_edit_--help.golden index 76dee16cf993c..baa7999604f06 100644 --- a/cli/testdata/coder_templates_edit_--help.golden +++ b/cli/testdata/coder_templates_edit_--help.golden @@ -91,7 +91,7 @@ OPTIONS: for more details. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_templates_pull_--help.golden b/cli/testdata/coder_templates_pull_--help.golden index 3a04c351f1f86..094f69994dad5 100644 --- a/cli/testdata/coder_templates_pull_--help.golden +++ b/cli/testdata/coder_templates_pull_--help.golden @@ -18,7 +18,7 @@ OPTIONS: the template version to pull. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. --zip bool Output the template as a zip archive to stdout. diff --git a/cli/testdata/coder_templates_push_--help.golden b/cli/testdata/coder_templates_push_--help.golden index edab61a3c55f1..1f1d7cdc428bd 100644 --- a/cli/testdata/coder_templates_push_--help.golden +++ b/cli/testdata/coder_templates_push_--help.golden @@ -48,7 +48,7 @@ OPTIONS: Specify a file path with values for Terraform-managed variables. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_templates_versions_archive_--help.golden b/cli/testdata/coder_templates_versions_archive_--help.golden index eae5a22ff37d6..ca79353671da5 100644 --- a/cli/testdata/coder_templates_versions_archive_--help.golden +++ b/cli/testdata/coder_templates_versions_archive_--help.golden @@ -11,7 +11,7 @@ OPTIONS: Select which organization (uuid or name) to use. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_templates_versions_unarchive_--help.golden b/cli/testdata/coder_templates_versions_unarchive_--help.golden index 6a641929fa20d..c1b381caf65a0 100644 --- a/cli/testdata/coder_templates_versions_unarchive_--help.golden +++ b/cli/testdata/coder_templates_versions_unarchive_--help.golden @@ -11,7 +11,7 @@ OPTIONS: Select which organization (uuid or name) to use. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_users_edit-roles_--help.golden b/cli/testdata/coder_users_edit-roles_--help.golden index 5a21c152e63fc..6af6e4fbeff40 100644 --- a/cli/testdata/coder_users_edit-roles_--help.golden +++ b/cli/testdata/coder_users_edit-roles_--help.golden @@ -11,7 +11,7 @@ OPTIONS: the user may have. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/docs/reference/cli/autoupdate.md b/docs/reference/cli/autoupdate.md index a025616e76031..6446804c4234d 100644 --- a/docs/reference/cli/autoupdate.md +++ b/docs/reference/cli/autoupdate.md @@ -17,4 +17,4 @@ coder autoupdate [flags] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/config-ssh.md b/docs/reference/cli/config-ssh.md index 607aa86849dd2..fbbf7ad61b70e 100644 --- a/docs/reference/cli/config-ssh.md +++ b/docs/reference/cli/config-ssh.md @@ -114,4 +114,4 @@ Disable starting the workspace automatically when connecting via SSH. |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/create.md b/docs/reference/cli/create.md index d18b4ea5c8e05..c3a2cbe352cd9 100644 --- a/docs/reference/cli/create.md +++ b/docs/reference/cli/create.md @@ -83,13 +83,22 @@ Specify automatic updates setting for the workspace (accepts 'always' or 'never' Specify the source workspace name to copy parameters from. +### --use-parameter-defaults + +| | | +|-------------|------------------------------------------------------| +| Type | bool | +| Environment | $CODER_WORKSPACE_USE_PARAMETER_DEFAULTS | + +Automatically accept parameter defaults when no value is provided. + ### -y, --yes | | | |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### --parameter diff --git a/docs/reference/cli/delete.md b/docs/reference/cli/delete.md index 9dc2ea6fa9a19..79d9401ccff54 100644 --- a/docs/reference/cli/delete.md +++ b/docs/reference/cli/delete.md @@ -37,4 +37,4 @@ Delete a workspace without deleting its resources. This can delete a workspace i |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/dotfiles.md b/docs/reference/cli/dotfiles.md index 57074497fee5f..81ef8386c6378 100644 --- a/docs/reference/cli/dotfiles.md +++ b/docs/reference/cli/dotfiles.md @@ -52,4 +52,4 @@ Specifies the directory for the dotfiles repository, relative to global config d |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/external-workspaces_create.md b/docs/reference/cli/external-workspaces_create.md index b0744387a1d70..6d1f21df8fd54 100644 --- a/docs/reference/cli/external-workspaces_create.md +++ b/docs/reference/cli/external-workspaces_create.md @@ -83,13 +83,22 @@ Specify automatic updates setting for the workspace (accepts 'always' or 'never' Specify the source workspace name to copy parameters from. +### --use-parameter-defaults + +| | | +|-------------|------------------------------------------------------| +| Type | bool | +| Environment | $CODER_WORKSPACE_USE_PARAMETER_DEFAULTS | + +Automatically accept parameter defaults when no value is provided. + ### -y, --yes | | | |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### --parameter diff --git a/docs/reference/cli/logout.md b/docs/reference/cli/logout.md index b35369ee36448..a56ed9f52befc 100644 --- a/docs/reference/cli/logout.md +++ b/docs/reference/cli/logout.md @@ -17,4 +17,4 @@ coder logout [flags] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/organizations_create.md b/docs/reference/cli/organizations_create.md index 14f40f55e00d1..414edd948888b 100644 --- a/docs/reference/cli/organizations_create.md +++ b/docs/reference/cli/organizations_create.md @@ -17,4 +17,4 @@ coder organizations create [flags] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/organizations_roles_create.md b/docs/reference/cli/organizations_roles_create.md index 70b2f21c4df2c..0d03ff6c2e6d8 100644 --- a/docs/reference/cli/organizations_roles_create.md +++ b/docs/reference/cli/organizations_roles_create.md @@ -25,7 +25,7 @@ coder organizations roles create [flags] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### --dry-run diff --git a/docs/reference/cli/organizations_roles_update.md b/docs/reference/cli/organizations_roles_update.md index 7179617f76bea..9637f19cd843f 100644 --- a/docs/reference/cli/organizations_roles_update.md +++ b/docs/reference/cli/organizations_roles_update.md @@ -25,7 +25,7 @@ coder organizations roles update [flags] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### --dry-run diff --git a/docs/reference/cli/provisioner_keys_delete.md b/docs/reference/cli/provisioner_keys_delete.md index 4303491106716..cbbbbb90c73da 100644 --- a/docs/reference/cli/provisioner_keys_delete.md +++ b/docs/reference/cli/provisioner_keys_delete.md @@ -21,7 +21,7 @@ coder provisioner keys delete [flags] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### -O, --org diff --git a/docs/reference/cli/publickey.md b/docs/reference/cli/publickey.md index ec68d813b137b..557bdb7c9c666 100644 --- a/docs/reference/cli/publickey.md +++ b/docs/reference/cli/publickey.md @@ -29,4 +29,4 @@ Regenerate your public key. This will require updating the key on any services i |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/rename.md b/docs/reference/cli/rename.md index 511ccc60f8d3b..11ffae03b5d8b 100644 --- a/docs/reference/cli/rename.md +++ b/docs/reference/cli/rename.md @@ -17,4 +17,4 @@ coder rename [flags] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/restart.md b/docs/reference/cli/restart.md index 1c30e3e1fffaa..cc508dc1c8755 100644 --- a/docs/reference/cli/restart.md +++ b/docs/reference/cli/restart.md @@ -17,7 +17,7 @@ coder restart [flags] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### --build-option diff --git a/docs/reference/cli/server_dbcrypt_decrypt.md b/docs/reference/cli/server_dbcrypt_decrypt.md index 5126ef0fccb25..a7e05b7fdda51 100644 --- a/docs/reference/cli/server_dbcrypt_decrypt.md +++ b/docs/reference/cli/server_dbcrypt_decrypt.md @@ -45,4 +45,4 @@ Keys required to decrypt existing data. Must be a comma-separated list of base64 |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/server_dbcrypt_delete.md b/docs/reference/cli/server_dbcrypt_delete.md index a5e7d16715ecf..364386f2a8861 100644 --- a/docs/reference/cli/server_dbcrypt_delete.md +++ b/docs/reference/cli/server_dbcrypt_delete.md @@ -40,4 +40,4 @@ Type of auth to use when connecting to postgres. |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/server_dbcrypt_rotate.md b/docs/reference/cli/server_dbcrypt_rotate.md index 322a909a087b8..e2700c2631624 100644 --- a/docs/reference/cli/server_dbcrypt_rotate.md +++ b/docs/reference/cli/server_dbcrypt_rotate.md @@ -54,4 +54,4 @@ The old external token encryption keys. Must be a comma-separated list of base64 |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/start.md b/docs/reference/cli/start.md index 9f0f30cdfa8c2..795057bf6f668 100644 --- a/docs/reference/cli/start.md +++ b/docs/reference/cli/start.md @@ -25,7 +25,7 @@ Return immediately after starting the workspace. |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### --build-option diff --git a/docs/reference/cli/stop.md b/docs/reference/cli/stop.md index dba81c5cf7e92..a442448de4418 100644 --- a/docs/reference/cli/stop.md +++ b/docs/reference/cli/stop.md @@ -17,4 +17,4 @@ coder stop [flags] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/support_bundle.md b/docs/reference/cli/support_bundle.md index 59b1fa4130deb..b6cf5ea6ac809 100644 --- a/docs/reference/cli/support_bundle.md +++ b/docs/reference/cli/support_bundle.md @@ -23,7 +23,7 @@ This command generates a file containing detailed troubleshooting information ab |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### -O, --output-file diff --git a/docs/reference/cli/task_delete.md b/docs/reference/cli/task_delete.md index 0181ee0ceafd7..2ab3e90b30cb6 100644 --- a/docs/reference/cli/task_delete.md +++ b/docs/reference/cli/task_delete.md @@ -37,4 +37,4 @@ coder task delete [flags] [ ...] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. diff --git a/docs/reference/cli/templates_archive.md b/docs/reference/cli/templates_archive.md index ef09707e5f323..648568c9fed6a 100644 --- a/docs/reference/cli/templates_archive.md +++ b/docs/reference/cli/templates_archive.md @@ -17,7 +17,7 @@ coder templates archive [flags] [template-name...] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### --all diff --git a/docs/reference/cli/templates_create.md b/docs/reference/cli/templates_create.md index cd3754e383ad5..3f46f3e759f78 100644 --- a/docs/reference/cli/templates_create.md +++ b/docs/reference/cli/templates_create.md @@ -102,7 +102,7 @@ Requires workspace builds to use the active template version. This setting does |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### -O, --org diff --git a/docs/reference/cli/templates_delete.md b/docs/reference/cli/templates_delete.md index 9037a39d2b378..45b15c5dcc2d0 100644 --- a/docs/reference/cli/templates_delete.md +++ b/docs/reference/cli/templates_delete.md @@ -21,7 +21,7 @@ coder templates delete [flags] [name...] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### -O, --org diff --git a/docs/reference/cli/templates_edit.md b/docs/reference/cli/templates_edit.md index 5d9f6f0a55a0d..069e7d7a6b679 100644 --- a/docs/reference/cli/templates_edit.md +++ b/docs/reference/cli/templates_edit.md @@ -169,7 +169,7 @@ Disable the default behavior of granting template access to the 'everyone' group |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### -O, --org diff --git a/docs/reference/cli/templates_pull.md b/docs/reference/cli/templates_pull.md index 529b110248475..a5a4731807d43 100644 --- a/docs/reference/cli/templates_pull.md +++ b/docs/reference/cli/templates_pull.md @@ -41,7 +41,7 @@ The name of the template version to pull. Use 'active' to pull the active versio |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### -O, --org diff --git a/docs/reference/cli/templates_push.md b/docs/reference/cli/templates_push.md index 8c7901e86e408..c27442f4f53f6 100644 --- a/docs/reference/cli/templates_push.md +++ b/docs/reference/cli/templates_push.md @@ -74,7 +74,7 @@ Whether the new template will be marked active. |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### -d, --directory diff --git a/docs/reference/cli/templates_versions_archive.md b/docs/reference/cli/templates_versions_archive.md index 1c7f4fd7d82c5..e4da6c4340c40 100644 --- a/docs/reference/cli/templates_versions_archive.md +++ b/docs/reference/cli/templates_versions_archive.md @@ -17,7 +17,7 @@ coder templates versions archive [flags] [template-version-names |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### -O, --org diff --git a/docs/reference/cli/templates_versions_unarchive.md b/docs/reference/cli/templates_versions_unarchive.md index c5351939bcf39..5013bda71a08d 100644 --- a/docs/reference/cli/templates_versions_unarchive.md +++ b/docs/reference/cli/templates_versions_unarchive.md @@ -17,7 +17,7 @@ coder templates versions unarchive [flags] [template-version-nam |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### -O, --org diff --git a/docs/reference/cli/users_edit-roles.md b/docs/reference/cli/users_edit-roles.md index 04f12ce701584..2dda192e4328b 100644 --- a/docs/reference/cli/users_edit-roles.md +++ b/docs/reference/cli/users_edit-roles.md @@ -17,7 +17,7 @@ coder users edit-roles [flags] |------|-------------------| | Type | bool | -Bypass prompts. +Bypass confirmation prompts. ### --roles diff --git a/enterprise/cli/testdata/coder_external-workspaces_create_--help.golden b/enterprise/cli/testdata/coder_external-workspaces_create_--help.golden index 208d2cc2296d7..9ec3834235921 100644 --- a/enterprise/cli/testdata/coder_external-workspaces_create_--help.golden +++ b/enterprise/cli/testdata/coder_external-workspaces_create_--help.golden @@ -49,8 +49,11 @@ OPTIONS: --template-version string, $CODER_TEMPLATE_VERSION 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 - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/enterprise/cli/testdata/coder_provisioner_keys_delete_--help.golden b/enterprise/cli/testdata/coder_provisioner_keys_delete_--help.golden index a8aea08c75187..1aa538585aea2 100644 --- a/enterprise/cli/testdata/coder_provisioner_keys_delete_--help.golden +++ b/enterprise/cli/testdata/coder_provisioner_keys_delete_--help.golden @@ -12,7 +12,7 @@ OPTIONS: Select which organization (uuid or name) to use. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/enterprise/cli/testdata/coder_server_dbcrypt_decrypt_--help.golden b/enterprise/cli/testdata/coder_server_dbcrypt_decrypt_--help.golden index 8f621ab10a63c..3618c3e881d68 100644 --- a/enterprise/cli/testdata/coder_server_dbcrypt_decrypt_--help.golden +++ b/enterprise/cli/testdata/coder_server_dbcrypt_decrypt_--help.golden @@ -17,7 +17,7 @@ OPTIONS: The connection URL for the Postgres database. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/enterprise/cli/testdata/coder_server_dbcrypt_delete_--help.golden b/enterprise/cli/testdata/coder_server_dbcrypt_delete_--help.golden index 8d3eda851dfe1..5b7325782d332 100644 --- a/enterprise/cli/testdata/coder_server_dbcrypt_delete_--help.golden +++ b/enterprise/cli/testdata/coder_server_dbcrypt_delete_--help.golden @@ -15,7 +15,7 @@ OPTIONS: The connection URL for the Postgres database. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/enterprise/cli/testdata/coder_server_dbcrypt_rotate_--help.golden b/enterprise/cli/testdata/coder_server_dbcrypt_rotate_--help.golden index 5961ecebde539..bd75ec9c82419 100644 --- a/enterprise/cli/testdata/coder_server_dbcrypt_rotate_--help.golden +++ b/enterprise/cli/testdata/coder_server_dbcrypt_rotate_--help.golden @@ -20,7 +20,7 @@ OPTIONS: The connection URL for the Postgres database. -y, --yes bool - Bypass prompts. + Bypass confirmation prompts. ——— Run `coder --help` for a list of global options. diff --git a/provisioner/echo/serve.go b/provisioner/echo/serve.go index 26d1fcbe3ad06..278cee3c06289 100644 --- a/provisioner/echo/serve.go +++ b/provisioner/echo/serve.go @@ -465,7 +465,15 @@ data "coder_parameter" "{{ .Name }}" { ephemeral = {{ .Ephemeral }} order = {{ .Order }} {{- if .DefaultValue }} + {{- if eq .Type "list(string)" }} + default = jsonencode({{ .DefaultValue }}) + {{else if eq .Type "bool"}} default = {{ .DefaultValue }} + {{else if eq .Type "number"}} + default = {{ .DefaultValue }} + {{else}} + default = "{{ .DefaultValue }}" + {{- end }} {{- end }} {{- if .Type }} type = "{{ .Type }}"