Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fbcaad614a |
+49
-15
@@ -46,6 +46,7 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
|
||||
autoUpdates string
|
||||
copyParametersFrom string
|
||||
useParameterDefaults bool
|
||||
nonInteractive bool
|
||||
// Organization context is only required if more than 1 template
|
||||
// shares the same name across multiple organizations.
|
||||
orgContext = NewOrganizationContext()
|
||||
@@ -75,6 +76,9 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
|
||||
}
|
||||
|
||||
if workspaceName == "" {
|
||||
if nonInteractive {
|
||||
return xerrors.New("workspace name must be provided as an argument in non-interactive mode")
|
||||
}
|
||||
workspaceName, err = cliui.Prompt(inv, cliui.PromptOptions{
|
||||
Text: "Specify a name for your workspace:",
|
||||
Validate: func(workspaceName string) error {
|
||||
@@ -122,13 +126,25 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
|
||||
var templateVersionID uuid.UUID
|
||||
switch {
|
||||
case templateName == "":
|
||||
_, _ = fmt.Fprintln(inv.Stdout, pretty.Sprint(cliui.DefaultStyles.Wrap, "Select a template below to preview the provisioned infrastructure:"))
|
||||
|
||||
templates, err := client.Templates(inv.Context(), codersdk.TemplateFilter{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(templates) == 0 {
|
||||
return xerrors.New("no templates available")
|
||||
}
|
||||
|
||||
if nonInteractive {
|
||||
if len(templates) == 1 {
|
||||
_, _ = fmt.Fprintf(inv.Stdout, "Using the only available template: %q\n", templates[0].Name)
|
||||
template = templates[0]
|
||||
templateVersionID = template.ActiveVersionID
|
||||
break
|
||||
}
|
||||
return xerrors.New("multiple templates available; use --template to specify which to use")
|
||||
}
|
||||
|
||||
slices.SortFunc(templates, func(a, b codersdk.Template) int {
|
||||
return slice.Descending(a.ActiveUserCount, b.ActiveUserCount)
|
||||
})
|
||||
@@ -167,6 +183,8 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
|
||||
templateByName[templateName] = template
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(inv.Stdout, pretty.Sprint(cliui.DefaultStyles.Wrap, "Select a template below to preview the provisioned infrastructure:"))
|
||||
|
||||
// Move the cursor up a single line for nicer display!
|
||||
option, err := cliui.Select(inv, cliui.SelectOptions{
|
||||
Options: templateNames,
|
||||
@@ -297,19 +315,24 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
|
||||
if !errors.Is(err, ErrNoPresetFound) {
|
||||
return xerrors.Errorf("unable to resolve preset: %w", err)
|
||||
}
|
||||
// If no preset found, prompt the user to choose a preset
|
||||
if preset, err = promptPresetSelection(inv, tvPresets); err != nil {
|
||||
return xerrors.Errorf("unable to prompt user for preset: %w", err)
|
||||
// If no preset found, prompt the user to choose a preset, unless in
|
||||
// non-interactive mode, in which case no preset is used.
|
||||
if !nonInteractive {
|
||||
if preset, err = promptPresetSelection(inv, tvPresets); err != nil {
|
||||
return xerrors.Errorf("unable to prompt user for preset: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if preset == nil {
|
||||
// Inform the user when no preset will be applied.
|
||||
_, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.Bold("No preset applied."))
|
||||
} else {
|
||||
// Convert preset parameters into workspace build parameters
|
||||
presetParameters = presetParameterAsWorkspaceBuildParameters(preset.Parameters)
|
||||
// Inform the user which preset was applied and its parameters
|
||||
displayAppliedPreset(inv, preset, presetParameters)
|
||||
} else {
|
||||
// Inform the user that no preset was applied
|
||||
_, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.Bold("No preset applied."))
|
||||
}
|
||||
|
||||
if opts.BeforeCreate != nil {
|
||||
@@ -332,17 +355,20 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
|
||||
SourceWorkspaceParameters: sourceWorkspaceParameters,
|
||||
|
||||
UseParameterDefaults: useParameterDefaults,
|
||||
NonInteractive: nonInteractive,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("prepare build: %w", err)
|
||||
}
|
||||
|
||||
_, err = cliui.Prompt(inv, cliui.PromptOptions{
|
||||
Text: "Confirm create?",
|
||||
IsConfirm: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
if !nonInteractive {
|
||||
_, err = cliui.Prompt(inv, cliui.PromptOptions{
|
||||
Text: "Confirm create?",
|
||||
IsConfirm: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var ttlMillis *int64
|
||||
@@ -444,6 +470,12 @@ func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
|
||||
Description: "Automatically accept parameter defaults when no value is provided.",
|
||||
Value: serpent.BoolOf(&useParameterDefaults),
|
||||
},
|
||||
serpent.Option{
|
||||
Flag: "non-interactive",
|
||||
Env: "CODER_NON_INTERACTIVE",
|
||||
Description: "Automatically accept all defaults and error when there is no default for a required input.",
|
||||
Value: serpent.BoolOf(&nonInteractive),
|
||||
},
|
||||
cliui.SkipPromptOption(),
|
||||
)
|
||||
cmd.Options = append(cmd.Options, parameterFlags.cliParameters()...)
|
||||
@@ -470,6 +502,7 @@ type prepWorkspaceBuildArgs struct {
|
||||
RichParameterDefaults []codersdk.WorkspaceBuildParameter
|
||||
|
||||
UseParameterDefaults bool
|
||||
NonInteractive bool
|
||||
}
|
||||
|
||||
// resolvePreset returns the preset matching the given presetName (if specified),
|
||||
@@ -573,7 +606,8 @@ func prepWorkspaceBuild(inv *serpent.Invocation, client *codersdk.Client, args p
|
||||
WithRichParameters(args.RichParameters).
|
||||
WithRichParametersFile(parameterFile).
|
||||
WithRichParametersDefaults(args.RichParameterDefaults).
|
||||
WithUseParameterDefaults(args.UseParameterDefaults)
|
||||
WithUseParameterDefaults(args.UseParameterDefaults).
|
||||
WithNonInteractive(args.NonInteractive)
|
||||
buildParameters, err := resolver.Resolve(inv, args.Action, templateVersionParameters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+229
-9
@@ -297,6 +297,117 @@ func TestCreate(t *testing.T) {
|
||||
assert.Nil(t, ws.AutostartSchedule, "expected workspace autostart schedule to be nil")
|
||||
}
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
// name is the name of the test.
|
||||
name string
|
||||
// setup runs before the command is started and returns arguments that
|
||||
// will be appended to the create command.
|
||||
setup func(client *codersdk.Client, owner codersdk.CreateFirstUserResponse) []string
|
||||
// handlePty optionally runs after the command is started. It should handle
|
||||
// all expected prompts from the pty.
|
||||
handlePty func(ctx context.Context, pty *ptytest.PTY)
|
||||
// errors contains expected errors. The workspace will not be verified if
|
||||
// errors are expected.
|
||||
errors []string
|
||||
}{
|
||||
{
|
||||
name: "NoWorkspaceNameNonInteractive",
|
||||
setup: func(_ *codersdk.Client, _ codersdk.CreateFirstUserResponse) []string {
|
||||
return []string{"--non-interactive"}
|
||||
},
|
||||
errors: []string{
|
||||
"workspace name must be provided",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OneTemplateNonInteractive",
|
||||
setup: func(_ *codersdk.Client, _ codersdk.CreateFirstUserResponse) []string {
|
||||
return []string{"my-workspace", "--non-interactive"}
|
||||
},
|
||||
handlePty: func(ctx context.Context, pty *ptytest.PTY) {
|
||||
pty.ExpectMatchContext(ctx, "Using the only available template")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MultipleTemplatesNonInteractive",
|
||||
setup: func(client *codersdk.Client, owner codersdk.CreateFirstUserResponse) []string {
|
||||
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||
_ = coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
|
||||
return []string{"my-workspace", "--non-interactive"}
|
||||
},
|
||||
errors: []string{
|
||||
"multiple templates available; use --template to specify which to use",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MultipleTemplatesInteractive",
|
||||
setup: func(client *codersdk.Client, owner codersdk.CreateFirstUserResponse) []string {
|
||||
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||
_ = coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
|
||||
return []string{"my-workspace", "--yes"}
|
||||
},
|
||||
handlePty: func(ctx context.Context, pty *ptytest.PTY) {
|
||||
pty.ExpectMatchContext(ctx, "Select a template below")
|
||||
pty.WriteLine("") // Select whatever is first.
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// 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, nil)
|
||||
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||
_ = coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
|
||||
|
||||
// Run the command, after running any additional test setup.
|
||||
args := []string{"create"}
|
||||
if tt.setup != nil {
|
||||
args = append(args, tt.setup(client, owner)...)
|
||||
}
|
||||
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()
|
||||
}()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
|
||||
defer cancel()
|
||||
|
||||
// The test may do something with the pty.
|
||||
if tt.handlePty != nil {
|
||||
tt.handlePty(ctx, pty)
|
||||
}
|
||||
|
||||
// Wait for the command to exit.
|
||||
err := <-doneChan
|
||||
|
||||
if len(tt.errors) > 0 {
|
||||
require.Error(t, err)
|
||||
for _, errstr := range tt.errors {
|
||||
require.ErrorContains(t, err, errstr)
|
||||
}
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify the workspace was created.
|
||||
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{Name: "my-workspace"})
|
||||
require.NoError(t, err, "expected to find created workspace")
|
||||
require.Len(t, workspaces.Workspaces, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func prepareEchoResponses(parameters []*proto.RichParameter, presets ...*proto.Preset) *echo.Responses {
|
||||
@@ -319,10 +430,11 @@ func prepareEchoResponses(parameters []*proto.RichParameter, presets ...*proto.P
|
||||
}
|
||||
|
||||
type param struct {
|
||||
name string
|
||||
ptype string
|
||||
value string
|
||||
mutable bool
|
||||
name string
|
||||
ptype string
|
||||
value string
|
||||
mutable bool
|
||||
required bool
|
||||
}
|
||||
|
||||
func TestCreateWithRichParameters(t *testing.T) {
|
||||
@@ -369,7 +481,7 @@ func TestCreateWithRichParameters(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
// setup runs before the command is started and return arguments that will
|
||||
// setup runs before the command is started and returns arguments that will
|
||||
// be appended to the create command.
|
||||
setup func() []string
|
||||
// handlePty optionally runs after the command is started. It should handle
|
||||
@@ -538,7 +650,7 @@ func TestCreateWithRichParameters(t *testing.T) {
|
||||
// Simply accept the defaults.
|
||||
for _, param := range params {
|
||||
pty.ExpectMatch(param.name)
|
||||
pty.ExpectMatch(`Enter a value (default: "` + param.value + `")`)
|
||||
pty.ExpectMatch(fmt.Sprintf("Enter a value (default: %q)", param.value))
|
||||
pty.WriteLine("")
|
||||
}
|
||||
// Confirm the creation.
|
||||
@@ -555,7 +667,7 @@ func TestCreateWithRichParameters(t *testing.T) {
|
||||
handlePty: func(pty *ptytest.PTY) {
|
||||
// Default values should get printed.
|
||||
for _, param := range params {
|
||||
pty.ExpectMatch(fmt.Sprintf("%s: '%s'", param.name, param.value))
|
||||
pty.ExpectMatch(fmt.Sprintf("%q: '%s'", param.name, param.value))
|
||||
}
|
||||
// No prompts, we only need to confirm.
|
||||
pty.ExpectMatch("Confirm create?")
|
||||
@@ -563,6 +675,19 @@ func TestCreateWithRichParameters(t *testing.T) {
|
||||
},
|
||||
withDefaults: true,
|
||||
},
|
||||
{
|
||||
name: "ValuesFromTemplateDefaultsNonInteractive",
|
||||
setup: func() []string {
|
||||
return []string{"--non-interactive"}
|
||||
},
|
||||
handlePty: func(pty *ptytest.PTY) {
|
||||
// Default values should get printed.
|
||||
for _, param := range params {
|
||||
pty.ExpectMatch(fmt.Sprintf("%q: '%s'", param.name, param.value))
|
||||
}
|
||||
},
|
||||
withDefaults: true,
|
||||
},
|
||||
{
|
||||
name: "ValuesFromDefaultFlagsNoPrompt",
|
||||
setup: func() []string {
|
||||
@@ -576,13 +701,45 @@ func TestCreateWithRichParameters(t *testing.T) {
|
||||
handlePty: func(pty *ptytest.PTY) {
|
||||
// Default values should get printed.
|
||||
for _, param := range params {
|
||||
pty.ExpectMatch(fmt.Sprintf("%s: '%s'", param.name, param.value))
|
||||
pty.ExpectMatch(fmt.Sprintf("%q: '%s'", param.name, param.value))
|
||||
}
|
||||
// No prompts, we only need to confirm.
|
||||
pty.ExpectMatch("Confirm create?")
|
||||
pty.WriteLine("yes")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ValuesFromDefaultFlagsNonInteractive",
|
||||
setup: func() []string {
|
||||
// Provide the defaults on the command line.
|
||||
args := []string{"--non-interactive"}
|
||||
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("%q: '%s'", param.name, param.value))
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ValuesMissingNonInteractive",
|
||||
setup: func() []string {
|
||||
return []string{"--non-interactive"}
|
||||
},
|
||||
inputParameters: []param{
|
||||
{
|
||||
name: "required_param",
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
errors: []string{
|
||||
"parameter \"required_param\" is required and has no default value",
|
||||
},
|
||||
},
|
||||
{
|
||||
// File and flags should override template defaults. Additionally, if a
|
||||
// value has no default value we should still get a prompt for it.
|
||||
@@ -671,6 +828,7 @@ cli_param: from file`)
|
||||
Name: param.name,
|
||||
Type: param.ptype,
|
||||
Mutable: param.mutable,
|
||||
Required: param.required,
|
||||
DefaultValue: defaultValue,
|
||||
Order: int32(i), //nolint:gosec
|
||||
})
|
||||
@@ -721,7 +879,7 @@ cli_param: from file`)
|
||||
if len(tt.errors) > 0 {
|
||||
require.Error(t, err)
|
||||
for _, errstr := range tt.errors {
|
||||
assert.ErrorContains(t, err, errstr)
|
||||
require.ErrorContains(t, err, errstr)
|
||||
}
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
@@ -1027,6 +1185,68 @@ func TestCreateWithPreset(t *testing.T) {
|
||||
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: thirdParameterName, Value: thirdParameterValue})
|
||||
})
|
||||
|
||||
t.Run("NoDefaultPresetNonInteractive", 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)
|
||||
|
||||
// Given: a template and a template version with a preset but no default.
|
||||
preset := proto.Preset{
|
||||
Name: "preset-test",
|
||||
Description: "Preset Test.",
|
||||
Parameters: []*proto.PresetParameter{
|
||||
{Name: firstParameterName, Value: secondOptionalParameterValue},
|
||||
{Name: thirdParameterName, Value: thirdParameterValue},
|
||||
},
|
||||
}
|
||||
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses(&preset))
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
|
||||
|
||||
// When: running the create command without specifying a preset
|
||||
workspaceName := "my-workspace"
|
||||
inv, root := clitest.New(t, "create", workspaceName, "--template", template.Name,
|
||||
"--parameter", fmt.Sprintf("%s=%s", firstParameterName, firstOptionalParameterValue),
|
||||
"--parameter", fmt.Sprintf("%s=%s", thirdParameterName, thirdParameterValue),
|
||||
"--non-interactive")
|
||||
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)
|
||||
}()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
|
||||
defer cancel()
|
||||
|
||||
// Should not prompt the user for the preset.
|
||||
pty.ExpectMatchContext(ctx, "No preset applied")
|
||||
|
||||
<-doneChan
|
||||
|
||||
tvPresets, err := client.TemplateVersionPresets(ctx, version.ID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, tvPresets, 1)
|
||||
|
||||
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{Name: workspaceName})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, workspaces.Workspaces, 1)
|
||||
|
||||
// Should: create a workspace using the expected template version and no preset
|
||||
workspaceLatestBuild := workspaces.Workspaces[0].LatestBuild
|
||||
require.Equal(t, version.ID, workspaceLatestBuild.TemplateVersionID)
|
||||
require.Nil(t, workspaceLatestBuild.TemplateVersionPresetID)
|
||||
buildParameters, err := client.WorkspaceBuildParameters(ctx, workspaceLatestBuild.ID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, buildParameters, 2)
|
||||
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: firstParameterName, Value: firstOptionalParameterValue})
|
||||
require.Contains(t, buildParameters, codersdk.WorkspaceBuildParameter{Name: thirdParameterName, Value: thirdParameterValue})
|
||||
})
|
||||
|
||||
// This test verifies that when a template version has no presets,
|
||||
// the CLI does not prompt the user to select a preset and proceeds
|
||||
// with workspace creation without applying any preset.
|
||||
|
||||
@@ -35,6 +35,7 @@ type ParameterResolver struct {
|
||||
promptRichParameters bool
|
||||
promptEphemeralParameters bool
|
||||
useParameterDefaults bool
|
||||
nonInteractive bool
|
||||
}
|
||||
|
||||
func (pr *ParameterResolver) WithLastBuildParameters(params []codersdk.WorkspaceBuildParameter) *ParameterResolver {
|
||||
@@ -92,6 +93,11 @@ func (pr *ParameterResolver) WithUseParameterDefaults(useParameterDefaults bool)
|
||||
return pr
|
||||
}
|
||||
|
||||
func (pr *ParameterResolver) WithNonInteractive(nonInteractive bool) *ParameterResolver {
|
||||
pr.nonInteractive = nonInteractive
|
||||
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)
|
||||
@@ -286,10 +292,16 @@ func (pr *ParameterResolver) resolveWithInput(resolved []codersdk.WorkspaceBuild
|
||||
parameterValue = v
|
||||
}
|
||||
|
||||
switch {
|
||||
// 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 {
|
||||
case (pr.nonInteractive || pr.useParameterDefaults) && parameterValue != "":
|
||||
_, _ = fmt.Fprintf(inv.Stdout, "Using default value for %q: '%s'\n", tvp.Name, parameterValue)
|
||||
case pr.nonInteractive && tvp.Required:
|
||||
return nil, xerrors.Errorf("parameter %q is required and has no default value", tvp.Name)
|
||||
case pr.nonInteractive:
|
||||
_, _ = fmt.Fprintf(inv.Stdout, "Skipping optional parameter %q\n", tvp.Name)
|
||||
continue
|
||||
default:
|
||||
var err error
|
||||
parameterValue, err = cliui.RichParameter(inv, tvp, name, parameterValue)
|
||||
if err != nil {
|
||||
|
||||
+4
@@ -20,6 +20,10 @@ OPTIONS:
|
||||
--copy-parameters-from string, $CODER_WORKSPACE_COPY_PARAMETERS_FROM
|
||||
Specify the source workspace name to copy parameters from.
|
||||
|
||||
--non-interactive bool, $CODER_NON_INTERACTIVE
|
||||
Automatically accept all defaults and error when there is no default
|
||||
for a required input.
|
||||
|
||||
--parameter string-array, $CODER_RICH_PARAMETER
|
||||
Rich parameter value in the format "name=value".
|
||||
|
||||
|
||||
Generated
+9
@@ -92,6 +92,15 @@ Specify the source workspace name to copy parameters from.
|
||||
|
||||
Automatically accept parameter defaults when no value is provided.
|
||||
|
||||
### --non-interactive
|
||||
|
||||
| | |
|
||||
|-------------|-------------------------------------|
|
||||
| Type | <code>bool</code> |
|
||||
| Environment | <code>$CODER_NON_INTERACTIVE</code> |
|
||||
|
||||
Automatically accept all defaults and error when there is no default for a required input.
|
||||
|
||||
### -y, --yes
|
||||
|
||||
| | |
|
||||
|
||||
@@ -92,6 +92,15 @@ Specify the source workspace name to copy parameters from.
|
||||
|
||||
Automatically accept parameter defaults when no value is provided.
|
||||
|
||||
### --non-interactive
|
||||
|
||||
| | |
|
||||
|-------------|-------------------------------------|
|
||||
| Type | <code>bool</code> |
|
||||
| Environment | <code>$CODER_NON_INTERACTIVE</code> |
|
||||
|
||||
Automatically accept all defaults and error when there is no default for a required input.
|
||||
|
||||
### -y, --yes
|
||||
|
||||
| | |
|
||||
|
||||
@@ -20,6 +20,10 @@ OPTIONS:
|
||||
--copy-parameters-from string, $CODER_WORKSPACE_COPY_PARAMETERS_FROM
|
||||
Specify the source workspace name to copy parameters from.
|
||||
|
||||
--non-interactive bool, $CODER_NON_INTERACTIVE
|
||||
Automatically accept all defaults and error when there is no default
|
||||
for a required input.
|
||||
|
||||
--parameter string-array, $CODER_RICH_PARAMETER
|
||||
Rich parameter value in the format "name=value".
|
||||
|
||||
|
||||
Reference in New Issue
Block a user