feat(cli): support ephemeral parameters (#8415)

This commit is contained in:
Marcin Tojek
2023-07-13 12:56:02 +02:00
committed by GitHub
parent cdf9b9045f
commit 5432c3f5ea
18 changed files with 507 additions and 21 deletions
+5
View File
@@ -15,7 +15,12 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te
label = templateVersionParameter.DisplayName
}
if templateVersionParameter.Ephemeral {
label += DefaultStyles.Warn.Render(" (build option)")
}
_, _ = fmt.Fprintln(inv.Stdout, DefaultStyles.Bold.Render(label))
if templateVersionParameter.DescriptionPlaintext != "" {
_, _ = fmt.Fprintln(inv.Stdout, " "+strings.TrimSpace(strings.Join(strings.Split(templateVersionParameter.DescriptionPlaintext, "\n"), "\n "))+"\n")
}
+10 -1
View File
@@ -23,6 +23,8 @@ func (r *RootCmd) create() *clibase.Cmd {
startAt string
stopAfter time.Duration
workspaceName string
parameterFlags workspaceParameterFlags
)
client := new(codersdk.Client)
cmd := &clibase.Cmd{
@@ -123,6 +125,7 @@ func (r *RootCmd) create() *clibase.Cmd {
Template: template,
RichParameterFile: richParameterFile,
NewWorkspaceName: workspaceName,
BuildOptions: parameterFlags.buildOptions,
})
if err != nil {
return xerrors.Errorf("prepare build: %w", err)
@@ -191,6 +194,7 @@ func (r *RootCmd) create() *clibase.Cmd {
},
cliui.SkipPromptOption(),
)
cmd.Options = append(cmd.Options, parameterFlags.options()...)
return cmd
}
@@ -202,6 +206,7 @@ type prepWorkspaceBuildArgs struct {
NewWorkspaceName string
UpdateWorkspace bool
BuildOptions bool
WorkspaceID uuid.UUID
}
@@ -240,13 +245,17 @@ func prepWorkspaceBuild(inv *clibase.Invocation, client *codersdk.Client, args p
richParameters := make([]codersdk.WorkspaceBuildParameter, 0)
PromptRichParamLoop:
for _, templateVersionParameter := range templateVersionParameters {
if !args.BuildOptions && templateVersionParameter.Ephemeral {
continue
}
if !disclaimerPrinted {
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Paragraph.Render("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss).")+"\r\n")
disclaimerPrinted = true
}
// Param file is all or nothing
if !useParamFile {
if !useParamFile && !templateVersionParameter.Ephemeral {
for _, e := range args.ExistingRichParams {
if e.Name == templateVersionParameter.Name {
// If the param already exists, we do not need to prompt it again.
+60 -1
View File
@@ -195,9 +195,13 @@ func TestCreateWithRichParameters(t *testing.T) {
secondParameterDescription = "This is second parameter"
secondParameterValue = "2"
ephemeralParameterName = "ephemeral_parameter"
ephemeralParameterDescription = "This is ephemeral parameter"
ephemeralParameterValue = "3"
immutableParameterName = "third_parameter"
immutableParameterDescription = "This is not mutable parameter"
immutableParameterValue = "3"
immutableParameterValue = "4"
)
echoResponses := &echo.Responses{
@@ -209,6 +213,7 @@ func TestCreateWithRichParameters(t *testing.T) {
Parameters: []*proto.RichParameter{
{Name: firstParameterName, Description: firstParameterDescription, Mutable: true},
{Name: secondParameterName, DisplayName: secondParameterDisplayName, Description: secondParameterDescription, Mutable: true},
{Name: ephemeralParameterName, Description: ephemeralParameterDescription, Mutable: true, Ephemeral: true},
{Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false},
},
},
@@ -300,6 +305,60 @@ func TestCreateWithRichParameters(t *testing.T) {
}
<-doneChan
})
t.Run("BuildOptions", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
const workspaceName = "my-workspace"
inv, root := clitest.New(t, "create", workspaceName, "--template", template.Name, "--build-options")
clitest.SetupConfig(t, client, 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{
ephemeralParameterDescription, ephemeralParameterValue,
firstParameterDescription, firstParameterValue,
secondParameterDisplayName, "",
secondParameterDescription, secondParameterValue,
immutableParameterDescription, immutableParameterValue,
"Confirm create?", "yes",
}
for i := 0; i < len(matches); i += 2 {
match := matches[i]
value := matches[i+1]
pty.ExpectMatch(match)
if value != "" {
pty.WriteLine(value)
}
}
<-doneChan
// Verify if build option is set
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
workspace, err := client.WorkspaceByOwnerAndName(ctx, user.UserID.String(), workspaceName, codersdk.WorkspaceOptions{})
require.NoError(t, err)
actualParameters, err := client.WorkspaceBuildParameters(ctx, workspace.LatestBuild.ID)
require.NoError(t, err)
require.Contains(t, actualParameters, codersdk.WorkspaceBuildParameter{
Name: ephemeralParameterName,
Value: ephemeralParameterValue,
})
})
}
func TestCreateValidateRichParameters(t *testing.T) {
+22 -8
View File
@@ -10,6 +10,8 @@ import (
)
func (r *RootCmd) restart() *clibase.Cmd {
var parameterFlags workspaceParameterFlags
client := new(codersdk.Client)
cmd := &clibase.Cmd{
Annotations: workspaceCommand,
@@ -19,22 +21,33 @@ func (r *RootCmd) restart() *clibase.Cmd {
clibase.RequireNArgs(1),
r.InitClient(client),
),
Options: clibase.OptionSet{
cliui.SkipPromptOption(),
},
Options: append(parameterFlags.options(), cliui.SkipPromptOption()),
Handler: func(inv *clibase.Invocation) error {
ctx := inv.Context()
out := inv.Stdout
_, err := cliui.Prompt(inv, cliui.PromptOptions{
Text: "Confirm restart workspace?",
IsConfirm: true,
workspace, err := namedWorkspace(inv.Context(), client, inv.Args[0])
if err != nil {
return err
}
template, err := client.Template(inv.Context(), workspace.TemplateID)
if err != nil {
return err
}
buildParams, err := prepStartWorkspace(inv, client, prepStartWorkspaceArgs{
Template: template,
BuildOptions: parameterFlags.buildOptions,
})
if err != nil {
return err
}
workspace, err := namedWorkspace(inv.Context(), client, inv.Args[0])
_, err = cliui.Prompt(inv, cliui.PromptOptions{
Text: "Confirm restart workspace?",
IsConfirm: true,
})
if err != nil {
return err
}
@@ -51,7 +64,8 @@ func (r *RootCmd) restart() *clibase.Cmd {
}
build, err = client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
Transition: codersdk.WorkspaceTransitionStart,
Transition: codersdk.WorkspaceTransitionStart,
RichParameterValues: buildParams.richParameters,
})
if err != nil {
return err
+83
View File
@@ -1,12 +1,17 @@
package cli_test
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/provisioner/echo"
"github.com/coder/coder/provisionersdk/proto"
"github.com/coder/coder/pty/ptytest"
"github.com/coder/coder/testutil"
)
@@ -14,6 +19,31 @@ import (
func TestRestart(t *testing.T) {
t.Parallel()
echoResponses := &echo.Responses{
Parse: echo.ParseComplete,
ProvisionPlan: []*proto.Provision_Response{
{
Type: &proto.Provision_Response_Complete{
Complete: &proto.Provision_Complete{
Parameters: []*proto.RichParameter{
{
Name: ephemeralParameterName,
Description: ephemeralParameterDescription,
Mutable: true,
Ephemeral: true,
},
},
},
},
},
},
ProvisionApply: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
Complete: &proto.Provision_Complete{},
},
}},
}
t.Run("OK", func(t *testing.T) {
t.Parallel()
@@ -43,4 +73,57 @@ func TestRestart(t *testing.T) {
err := <-done
require.NoError(t, err, "execute failed")
})
t.Run("BuildOptions", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
inv, root := clitest.New(t, "restart", workspace.Name, "--build-options")
clitest.SetupConfig(t, client, 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{
ephemeralParameterDescription, ephemeralParameterValue,
"Confirm restart workspace?", "yes",
"Stopping workspace", "",
"Starting workspace", "",
"workspace has been restarted", "",
}
for i := 0; i < len(matches); i += 2 {
match := matches[i]
value := matches[i+1]
pty.ExpectMatch(match)
if value != "" {
pty.WriteLine(value)
}
}
<-doneChan
// Verify if build option is set
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
workspace, err := client.WorkspaceByOwnerAndName(ctx, user.UserID.String(), workspace.Name, codersdk.WorkspaceOptions{})
require.NoError(t, err)
actualParameters, err := client.WorkspaceBuildParameters(ctx, workspace.LatestBuild.ID)
require.NoError(t, err)
require.Contains(t, actualParameters, codersdk.WorkspaceBuildParameter{
Name: ephemeralParameterName,
Value: ephemeralParameterValue,
})
})
}
+82 -4
View File
@@ -4,12 +4,31 @@ import (
"fmt"
"time"
"golang.org/x/xerrors"
"github.com/coder/coder/cli/clibase"
"github.com/coder/coder/cli/cliui"
"github.com/coder/coder/codersdk"
)
// workspaceParameterFlags are used by "start", "restart", "create", and "update".
type workspaceParameterFlags struct {
buildOptions bool
}
func (wpf *workspaceParameterFlags) options() []clibase.Option {
return clibase.OptionSet{
{
Flag: "build-options",
Description: "Prompt for one-time build options defined with ephemeral parameters.",
Value: clibase.BoolOf(&wpf.buildOptions),
},
}
}
func (r *RootCmd) start() *clibase.Cmd {
var parameterFlags workspaceParameterFlags
client := new(codersdk.Client)
cmd := &clibase.Cmd{
Annotations: workspaceCommand,
@@ -19,16 +38,29 @@ func (r *RootCmd) start() *clibase.Cmd {
clibase.RequireNArgs(1),
r.InitClient(client),
),
Options: clibase.OptionSet{
cliui.SkipPromptOption(),
},
Options: append(parameterFlags.options(), cliui.SkipPromptOption()),
Handler: func(inv *clibase.Invocation) error {
workspace, err := namedWorkspace(inv.Context(), client, inv.Args[0])
if err != nil {
return err
}
template, err := client.Template(inv.Context(), workspace.TemplateID)
if err != nil {
return err
}
buildParams, err := prepStartWorkspace(inv, client, prepStartWorkspaceArgs{
Template: template,
BuildOptions: parameterFlags.buildOptions,
})
if err != nil {
return err
}
build, err := client.CreateWorkspaceBuild(inv.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
Transition: codersdk.WorkspaceTransitionStart,
Transition: codersdk.WorkspaceTransitionStart,
RichParameterValues: buildParams.richParameters,
})
if err != nil {
return err
@@ -45,3 +77,49 @@ func (r *RootCmd) start() *clibase.Cmd {
}
return cmd
}
type prepStartWorkspaceArgs struct {
Template codersdk.Template
BuildOptions bool
}
func prepStartWorkspace(inv *clibase.Invocation, client *codersdk.Client, args prepStartWorkspaceArgs) (*buildParameters, error) {
ctx := inv.Context()
templateVersion, err := client.TemplateVersion(ctx, args.Template.ActiveVersionID)
if err != nil {
return nil, err
}
templateVersionParameters, err := client.TemplateVersionRichParameters(inv.Context(), templateVersion.ID)
if err != nil {
return nil, xerrors.Errorf("get template version rich parameters: %w", err)
}
richParameters := make([]codersdk.WorkspaceBuildParameter, 0)
if !args.BuildOptions {
return &buildParameters{
richParameters: richParameters,
}, nil
}
for _, templateVersionParameter := range templateVersionParameters {
if !templateVersionParameter.Ephemeral {
continue
}
parameterValue, err := cliui.RichParameter(inv, templateVersionParameter)
if err != nil {
return nil, err
}
richParameters = append(richParameters, codersdk.WorkspaceBuildParameter{
Name: templateVersionParameter.Name,
Value: parameterValue,
})
}
return &buildParameters{
richParameters: richParameters,
}, nil
}
+102
View File
@@ -0,0 +1,102 @@
package cli_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/provisioner/echo"
"github.com/coder/coder/provisionersdk/proto"
"github.com/coder/coder/pty/ptytest"
"github.com/coder/coder/testutil"
)
const (
ephemeralParameterName = "ephemeral_parameter"
ephemeralParameterDescription = "This is ephemeral parameter"
ephemeralParameterValue = "3"
)
func TestStart(t *testing.T) {
t.Parallel()
echoResponses := &echo.Responses{
Parse: echo.ParseComplete,
ProvisionPlan: []*proto.Provision_Response{
{
Type: &proto.Provision_Response_Complete{
Complete: &proto.Provision_Complete{
Parameters: []*proto.RichParameter{
{
Name: ephemeralParameterName,
Description: ephemeralParameterDescription,
Mutable: true,
Ephemeral: true,
},
},
},
},
},
},
ProvisionApply: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
Complete: &proto.Provision_Complete{},
},
}},
}
t.Run("BuildOptions", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
inv, root := clitest.New(t, "start", workspace.Name, "--build-options")
clitest.SetupConfig(t, client, 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{
ephemeralParameterDescription, ephemeralParameterValue,
"workspace has been started", "",
}
for i := 0; i < len(matches); i += 2 {
match := matches[i]
value := matches[i+1]
pty.ExpectMatch(match)
if value != "" {
pty.WriteLine(value)
}
}
<-doneChan
// Verify if build option is set
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
workspace, err := client.WorkspaceByOwnerAndName(ctx, workspace.OwnerName, workspace.Name, codersdk.WorkspaceOptions{})
require.NoError(t, err)
actualParameters, err := client.WorkspaceBuildParameters(ctx, workspace.LatestBuild.ID)
require.NoError(t, err)
require.Contains(t, actualParameters, codersdk.WorkspaceBuildParameter{
Name: ephemeralParameterName,
Value: ephemeralParameterValue,
})
})
}
+3
View File
@@ -3,6 +3,9 @@ Usage: coder create [flags] [name]
Create a workspace
Options
--build-options bool
Prompt for one-time build options defined with ephemeral parameters.
--rich-parameter-file string, $CODER_RICH_PARAMETER_FILE
Specify a file path with values for rich parameters defined in the
template.
+3
View File
@@ -3,6 +3,9 @@ Usage: coder restart [flags] <workspace>
Restart a workspace
Options
--build-options bool
Prompt for one-time build options defined with ephemeral parameters.
-y, --yes bool
Bypass prompts.
+3
View File
@@ -3,6 +3,9 @@ Usage: coder start [flags] <workspace>
Start a workspace
Options
--build-options bool
Prompt for one-time build options defined with ephemeral parameters.
-y, --yes bool
Bypass prompts.
+3
View File
@@ -9,6 +9,9 @@ Use --always-prompt to change the parameter values of the workspace.
Always prompt all parameters. Does not pull parameter values from
existing workspace.
--build-options bool
Prompt for one-time build options defined with ephemeral parameters.
--rich-parameter-file string, $CODER_RICH_PARAMETER_FILE
Specify a file path with values for rich parameters defined in the
template.
+10 -6
View File
@@ -11,6 +11,8 @@ func (r *RootCmd) update() *clibase.Cmd {
var (
richParameterFile string
alwaysPrompt bool
parameterFlags workspaceParameterFlags
)
client := new(codersdk.Client)
@@ -28,20 +30,20 @@ func (r *RootCmd) update() *clibase.Cmd {
if err != nil {
return err
}
if !workspace.Outdated && !alwaysPrompt {
if !workspace.Outdated && !alwaysPrompt && !parameterFlags.buildOptions {
_, _ = fmt.Fprintf(inv.Stdout, "Workspace isn't outdated!\n")
return nil
}
template, err := client.Template(inv.Context(), workspace.TemplateID)
if err != nil {
return nil
return err
}
var existingRichParams []codersdk.WorkspaceBuildParameter
if !alwaysPrompt {
existingRichParams, err = client.WorkspaceBuildParameters(inv.Context(), workspace.LatestBuild.ID)
if err != nil {
return nil
return err
}
}
@@ -53,9 +55,11 @@ func (r *RootCmd) update() *clibase.Cmd {
UpdateWorkspace: true,
WorkspaceID: workspace.LatestBuild.ID,
BuildOptions: parameterFlags.buildOptions,
})
if err != nil {
return nil
return err
}
build, err := client.CreateWorkspaceBuild(inv.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
@@ -86,8 +90,7 @@ func (r *RootCmd) update() *clibase.Cmd {
{
Flag: "always-prompt",
Description: "Always prompt all parameters. Does not pull parameter values from existing workspace.",
Value: clibase.BoolOf(&alwaysPrompt),
Value: clibase.BoolOf(&alwaysPrompt),
},
{
Flag: "rich-parameter-file",
@@ -96,5 +99,6 @@ func (r *RootCmd) update() *clibase.Cmd {
Value: clibase.StringOf(&richParameterFile),
},
}
cmd.Options = append(cmd.Options, parameterFlags.options()...)
return cmd
}
+71 -1
View File
@@ -16,6 +16,7 @@ import (
"github.com/coder/coder/provisioner/echo"
"github.com/coder/coder/provisionersdk/proto"
"github.com/coder/coder/pty/ptytest"
"github.com/coder/coder/testutil"
)
func TestUpdate(t *testing.T) {
@@ -90,9 +91,13 @@ func TestUpdateWithRichParameters(t *testing.T) {
secondParameterDescription = "This is second parameter"
secondParameterValue = "2"
ephemeralParameterName = "ephemeral_parameter"
ephemeralParameterDescription = "This is ephemeral parameter"
ephemeralParameterValue = "3"
immutableParameterName = "immutable_parameter"
immutableParameterDescription = "This is not mutable parameter"
immutableParameterValue = "3"
immutableParameterValue = "4"
)
echoResponses := &echo.Responses{
@@ -105,6 +110,7 @@ func TestUpdateWithRichParameters(t *testing.T) {
{Name: firstParameterName, Description: firstParameterDescription, Mutable: true},
{Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false},
{Name: secondParameterName, Description: secondParameterDescription, Mutable: true},
{Name: ephemeralParameterName, Description: ephemeralParameterDescription, Mutable: true, Ephemeral: true},
},
},
},
@@ -166,6 +172,70 @@ func TestUpdateWithRichParameters(t *testing.T) {
}
<-doneChan
})
t.Run("BuildOptions", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
tempDir := t.TempDir()
removeTmpDirUntilSuccessAfterTest(t, tempDir)
parameterFile, _ := os.CreateTemp(tempDir, "testParameterFile*.yaml")
_, _ = parameterFile.WriteString(
firstParameterName + ": " + firstParameterValue + "\n" +
immutableParameterName + ": " + immutableParameterValue + "\n" +
secondParameterName + ": " + secondParameterValue)
const workspaceName = "my-workspace"
inv, root := clitest.New(t, "create", workspaceName, "--template", template.Name, "--rich-parameter-file", parameterFile.Name(), "-y")
clitest.SetupConfig(t, client, root)
err := inv.Run()
assert.NoError(t, err)
inv, root = clitest.New(t, "update", workspaceName, "--build-options")
clitest.SetupConfig(t, client, 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{
ephemeralParameterDescription, ephemeralParameterValue,
"Planning workspace", "",
}
for i := 0; i < len(matches); i += 2 {
match := matches[i]
value := matches[i+1]
pty.ExpectMatch(match)
if value != "" {
pty.WriteLine(value)
}
}
<-doneChan
// Verify if build option is set
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
workspace, err := client.WorkspaceByOwnerAndName(ctx, user.UserID.String(), workspaceName, codersdk.WorkspaceOptions{})
require.NoError(t, err)
actualParameters, err := client.WorkspaceBuildParameters(ctx, workspace.LatestBuild.ID)
require.NoError(t, err)
require.Contains(t, actualParameters, codersdk.WorkspaceBuildParameter{
Name: ephemeralParameterName,
Value: ephemeralParameterValue,
})
})
}
func TestUpdateValidateRichParameters(t *testing.T) {
+8
View File
@@ -12,6 +12,14 @@ coder create [flags] [name]
## Options
### --build-options
| | |
| ---- | ----------------- |
| Type | <code>bool</code> |
Prompt for one-time build options defined with ephemeral parameters.
### --rich-parameter-file
| | |
+8
View File
@@ -12,6 +12,14 @@ coder restart [flags] <workspace>
## Options
### --build-options
| | |
| ---- | ----------------- |
| Type | <code>bool</code> |
Prompt for one-time build options defined with ephemeral parameters.
### -y, --yes
| | |
+8
View File
@@ -12,6 +12,14 @@ coder start [flags] <workspace>
## Options
### --build-options
| | |
| ---- | ----------------- |
| Type | <code>bool</code> |
Prompt for one-time build options defined with ephemeral parameters.
### -y, --yes
| | |
+8
View File
@@ -26,6 +26,14 @@ Use --always-prompt to change the parameter values of the workspace.
Always prompt all parameters. Does not pull parameter values from existing workspace.
### --build-options
| | |
| ---- | ----------------- |
| Type | <code>bool</code> |
Prompt for one-time build options defined with ephemeral parameters.
### --rich-parameter-file
| | |
+18
View File
@@ -149,6 +149,24 @@ data "coder_parameter" "region" {
It is allowed to modify the mutability state anytime. In case of emergency, template authors can temporarily allow for changing immutable parameters to fix an operational issue, but it is not
advised to overuse this opportunity.
## Ephemeral parameters
Ephemeral parameters are introduced to users in the form of "build options." This functionality can be used to model
specific behaviors within a Coder workspace, such as reverting to a previous image, restoring from a volume snapshot, or
building a project without utilizing cache.
As these parameters are ephemeral in nature, subsequent builds will proceed in the standard manner.
```hcl
data "coder_parameter" "force_rebuild" {
name = "force_rebuild"
type = "bool"
description = "Rebuild the Docker image rather than use the cached one."
mutable = true
ephemeral = true
}
```
## Validation
Rich parameters support multiple validation modes - min, max, monotonic numbers, and regular expressions.