mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: add --use-parameter-defaults flag (#21119)
This is like `--yes`, but for parameter prompts.
This commit is contained in:
+2
-11
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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)),
|
||||
}
|
||||
|
||||
+17
-5
@@ -42,9 +42,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()
|
||||
@@ -308,7 +309,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 {
|
||||
@@ -329,6 +330,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)
|
||||
@@ -435,6 +438,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()...)
|
||||
@@ -459,6 +468,8 @@ type prepWorkspaceBuildArgs struct {
|
||||
RichParameters []codersdk.WorkspaceBuildParameter
|
||||
RichParameterFile string
|
||||
RichParameterDefaults []codersdk.WorkspaceBuildParameter
|
||||
|
||||
UseParameterDefaults bool
|
||||
}
|
||||
|
||||
// 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).
|
||||
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
|
||||
|
||||
+411
-327
@@ -318,353 +318,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()
|
||||
type testContext struct {
|
||||
client *codersdk.Client
|
||||
member *codersdk.Client
|
||||
owner codersdk.CreateFirstUserResponse
|
||||
template codersdk.Template
|
||||
workspaceName string
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
|
||||
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)
|
||||
|
||||
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)
|
||||
}()
|
||||
// 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")
|
||||
|
||||
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)
|
||||
// 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",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if value != "" {
|
||||
pty.WriteLine(value)
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
parameters := params
|
||||
if len(tt.inputParameters) > 0 {
|
||||
parameters = tt.inputParameters
|
||||
}
|
||||
}
|
||||
<-doneChan
|
||||
})
|
||||
|
||||
t.Run("ParametersDefaults", 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)
|
||||
|
||||
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)
|
||||
}()
|
||||
// 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()
|
||||
}()
|
||||
|
||||
matches := []string{
|
||||
firstParameterDescription, firstParameterValue,
|
||||
secondParameterDescription, secondParameterValue,
|
||||
immutableParameterDescription, immutableParameterValue,
|
||||
}
|
||||
for i := 0; i < len(matches); i += 2 {
|
||||
match := matches[i]
|
||||
defaultValue := matches[i+1]
|
||||
// The test may do something with the pty.
|
||||
if tt.handlePty != nil {
|
||||
tt.handlePty(pty)
|
||||
}
|
||||
|
||||
pty.ExpectMatch(match)
|
||||
pty.ExpectMatch(`Enter a value (default: "` + defaultValue + `")`)
|
||||
pty.WriteLine("")
|
||||
}
|
||||
pty.ExpectMatch("Confirm create?")
|
||||
pty.WriteLine("yes")
|
||||
<-doneChan
|
||||
// Wait for the command to exit.
|
||||
err := <-doneChan
|
||||
|
||||
// Verify that the expected default values were used.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
|
||||
defer cancel()
|
||||
// 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: "my-workspace",
|
||||
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)
|
||||
|
||||
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()
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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{
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ USAGE:
|
||||
|
||||
OPTIONS:
|
||||
-y, --yes bool
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+4
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ OPTIONS:
|
||||
resources.
|
||||
|
||||
-y, --yes bool
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ USAGE:
|
||||
|
||||
OPTIONS:
|
||||
-y, --yes bool
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ USAGE:
|
||||
|
||||
OPTIONS:
|
||||
-y, --yes bool
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ USAGE:
|
||||
|
||||
OPTIONS:
|
||||
-y, --yes bool
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ USAGE:
|
||||
|
||||
OPTIONS:
|
||||
-y, --yes bool
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ USAGE:
|
||||
|
||||
OPTIONS:
|
||||
-y, --yes bool
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
Generated
+1
-1
@@ -17,4 +17,4 @@ coder autoupdate [flags] <workspace> <always|never>
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
Generated
+1
-1
@@ -114,4 +114,4 @@ Disable starting the workspace automatically when connecting via SSH.
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
Generated
+10
-1
@@ -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 | <code>bool</code> |
|
||||
| Environment | <code>$CODER_WORKSPACE_USE_PARAMETER_DEFAULTS</code> |
|
||||
|
||||
Automatically accept parameter defaults when no value is provided.
|
||||
|
||||
### -y, --yes
|
||||
|
||||
| | |
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### --parameter
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -37,4 +37,4 @@ Delete a workspace without deleting its resources. This can delete a workspace i
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
Generated
+1
-1
@@ -52,4 +52,4 @@ Specifies the directory for the dotfiles repository, relative to global config d
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
+10
-1
@@ -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 | <code>bool</code> |
|
||||
| Environment | <code>$CODER_WORKSPACE_USE_PARAMETER_DEFAULTS</code> |
|
||||
|
||||
Automatically accept parameter defaults when no value is provided.
|
||||
|
||||
### -y, --yes
|
||||
|
||||
| | |
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### --parameter
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -17,4 +17,4 @@ coder logout [flags]
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
+1
-1
@@ -17,4 +17,4 @@ coder organizations create [flags] <organization name>
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ coder organizations roles create [flags] <role_name>
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### --dry-run
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ coder organizations roles update [flags] <role_name>
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### --dry-run
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ coder provisioner keys delete [flags] <name>
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### -O, --org
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -29,4 +29,4 @@ Regenerate your public key. This will require updating the key on any services i
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
Generated
+1
-1
@@ -17,4 +17,4 @@ coder rename [flags] <workspace> <new name>
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
Generated
+1
-1
@@ -17,7 +17,7 @@ coder restart [flags] <workspace>
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### --build-option
|
||||
|
||||
|
||||
+1
-1
@@ -45,4 +45,4 @@ Keys required to decrypt existing data. Must be a comma-separated list of base64
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
+1
-1
@@ -40,4 +40,4 @@ Type of auth to use when connecting to postgres.
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
+1
-1
@@ -54,4 +54,4 @@ The old external token encryption keys. Must be a comma-separated list of base64
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
Generated
+1
-1
@@ -25,7 +25,7 @@ Return immediately after starting the workspace.
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### --build-option
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -17,4 +17,4 @@ coder stop [flags] <workspace>
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
Generated
+1
-1
@@ -23,7 +23,7 @@ This command generates a file containing detailed troubleshooting information ab
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### -O, --output-file
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -37,4 +37,4 @@ coder task delete [flags] <task> [<task> ...]
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
Generated
+1
-1
@@ -17,7 +17,7 @@ coder templates archive [flags] [template-name...]
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### --all
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -102,7 +102,7 @@ Requires workspace builds to use the active template version. This setting does
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### -O, --org
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -21,7 +21,7 @@ coder templates delete [flags] [name...]
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### -O, --org
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -169,7 +169,7 @@ Disable the default behavior of granting template access to the 'everyone' group
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### -O, --org
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -41,7 +41,7 @@ The name of the template version to pull. Use 'active' to pull the active versio
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### -O, --org
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -74,7 +74,7 @@ Whether the new template will be marked active.
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### -d, --directory
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ coder templates versions archive [flags] <template-name> [template-version-names
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### -O, --org
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ coder templates versions unarchive [flags] <template-name> [template-version-nam
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### -O, --org
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -17,7 +17,7 @@ coder users edit-roles [flags] <username|user_id>
|
||||
|------|-------------------|
|
||||
| Type | <code>bool</code> |
|
||||
|
||||
Bypass prompts.
|
||||
Bypass confirmation prompts.
|
||||
|
||||
### --roles
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -660,7 +660,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 }}"
|
||||
|
||||
Reference in New Issue
Block a user