diff --git a/cli/parameterresolver.go b/cli/parameterresolver.go index 8cae66527d503..486188d52a27a 100644 --- a/cli/parameterresolver.go +++ b/cli/parameterresolver.go @@ -141,6 +141,10 @@ next: continue // immutables should not be passed to consecutive builds } + if len(tvp.Options) > 0 && !isValidTemplateParameterOption(buildParameter, tvp.Options) { + continue // do not propagate invalid options + } + for i, r := range resolved { if r.Name == buildParameter.Name { resolved[i].Value = buildParameter.Value @@ -180,10 +184,12 @@ func (pr *ParameterResolver) resolveWithInput(resolved []codersdk.WorkspaceBuild // Parameter has not been resolved yet, so CLI needs to determine if user should input it. firstTimeUse := pr.isFirstTimeUse(tvp.Name) + promptParameterOption := pr.isLastBuildParameterInvalidOption(tvp) if (tvp.Ephemeral && pr.promptBuildOptions) || (action == WorkspaceCreate && tvp.Required) || (action == WorkspaceCreate && !tvp.Ephemeral) || + (action == WorkspaceUpdate && promptParameterOption) || (action == WorkspaceUpdate && tvp.Mutable && tvp.Required) || (action == WorkspaceUpdate && !tvp.Mutable && firstTimeUse) || (action == WorkspaceUpdate && tvp.Mutable && !tvp.Ephemeral && pr.promptRichParameters) { @@ -207,6 +213,19 @@ func (pr *ParameterResolver) isFirstTimeUse(parameterName string) bool { return findWorkspaceBuildParameter(parameterName, pr.lastBuildParameters) == nil } +func (pr *ParameterResolver) isLastBuildParameterInvalidOption(templateVersionParameter codersdk.TemplateVersionParameter) bool { + if len(templateVersionParameter.Options) == 0 { + return false + } + + for _, buildParameter := range pr.lastBuildParameters { + if buildParameter.Name == templateVersionParameter.Name { + return !isValidTemplateParameterOption(buildParameter, templateVersionParameter.Options) + } + } + return false +} + func findTemplateVersionParameter(workspaceBuildParameter codersdk.WorkspaceBuildParameter, templateVersionParameters []codersdk.TemplateVersionParameter) *codersdk.TemplateVersionParameter { for _, tvp := range templateVersionParameters { if tvp.Name == workspaceBuildParameter.Name { @@ -224,3 +243,12 @@ func findWorkspaceBuildParameter(parameterName string, params []codersdk.Workspa } return nil } + +func isValidTemplateParameterOption(buildParameter codersdk.WorkspaceBuildParameter, options []codersdk.TemplateVersionParameterOption) bool { + for _, opt := range options { + if opt.Value == buildParameter.Value { + return true + } + } + return false +} diff --git a/cli/root.go b/cli/root.go index 2b4db5eb8b221..fad5625d909c0 100644 --- a/cli/root.go +++ b/cli/root.go @@ -981,6 +981,8 @@ func (p *prettyErrorFormatter) format(err error) { msg = sdkError.Message if sdkError.Helper != "" { msg = msg + "\n" + sdkError.Helper + } else if sdkError.Detail != "" { + msg = msg + "\n" + sdkError.Detail } // The SDK error is usually good enough, and we don't want to overwhelm // the user with output. diff --git a/cli/update_test.go b/cli/update_test.go index a066eaef7278c..57e49d0db3766 100644 --- a/cli/update_test.go +++ b/cli/update_test.go @@ -593,12 +593,138 @@ func TestUpdateValidateRichParameters(t *testing.T) { assert.NoError(t, err) }() + pty.ExpectMatch("Planning workspace...") + <-doneChan + }) + + t.Run("ParameterOptionChanged", func(t *testing.T) { + t.Parallel() + + // Create template and workspace + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + + templateParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true, Required: true, Options: []*proto.RichParameterOption{ + {Name: "First option", Description: "This is first option", Value: "1st"}, + {Name: "Second option", Description: "This is second option", Value: "2nd"}, + {Name: "Third option", Description: "This is third option", Value: "3rd"}, + }}, + } + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(templateParameters)) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + + inv, root := clitest.New(t, "create", "my-workspace", "--yes", "--template", template.Name, "--parameter", fmt.Sprintf("%s=%s", stringParameterName, "2nd")) + clitest.SetupConfig(t, client, root) + err := inv.Run() + require.NoError(t, err) + + // Update template + updatedTemplateParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true, Required: true, Options: []*proto.RichParameterOption{ + {Name: "first_option", Description: "This is first option", Value: "1"}, + {Name: "second_option", Description: "This is second option", Value: "2"}, + {Name: "third_option", Description: "This is third option", Value: "3"}, + }}, + } + + updatedVersion := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(updatedTemplateParameters), template.ID) + coderdtest.AwaitTemplateVersionJob(t, client, updatedVersion.ID) + err = client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{ + ID: updatedVersion.ID, + }) + require.NoError(t, err) + + // Update the workspace + inv, root = clitest.New(t, "update", "my-workspace") + 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{ + stringParameterName, "second_option", "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 + }) + + t.Run("ParameterOptionDisappeared", func(t *testing.T) { + t.Parallel() + + // Create template and workspace + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + + templateParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true, Required: true, Options: []*proto.RichParameterOption{ + {Name: "First option", Description: "This is first option", Value: "1st"}, + {Name: "Second option", Description: "This is second option", Value: "2nd"}, + {Name: "Third option", Description: "This is third option", Value: "3rd"}, + }}, + } + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(templateParameters)) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + + inv, root := clitest.New(t, "create", "my-workspace", "--yes", "--template", template.Name, "--parameter", fmt.Sprintf("%s=%s", stringParameterName, "2nd")) + clitest.SetupConfig(t, client, root) + err := inv.Run() + require.NoError(t, err) + + // Update template - 2nd option disappeared, 4th option added + updatedTemplateParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true, Required: true, Options: []*proto.RichParameterOption{ + {Name: "First option", Description: "This is first option", Value: "1st"}, + {Name: "Third option", Description: "This is third option", Value: "3rd"}, + {Name: "Fourth option", Description: "This is fourth option", Value: "4th"}, + }}, + } + + updatedVersion := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(updatedTemplateParameters), template.ID) + coderdtest.AwaitTemplateVersionJob(t, client, updatedVersion.ID) + err = client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{ + ID: updatedVersion.ID, + }) + require.NoError(t, err) + + // Update the workspace + inv, root = clitest.New(t, "update", "my-workspace") + 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{ + stringParameterName, "Third option", + "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 }) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 561848ba4a1bb..58f6d3267376e 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -8440,11 +8440,9 @@ const docTemplate = `{ "codersdk.JobErrorCode": { "type": "string", "enum": [ - "MISSING_TEMPLATE_PARAMETER", "REQUIRED_TEMPLATE_VARIABLES" ], "x-enum-varnames": [ - "MissingTemplateParameter", "RequiredTemplateVariables" ] }, @@ -8978,7 +8976,6 @@ const docTemplate = `{ }, "error_code": { "enum": [ - "MISSING_TEMPLATE_PARAMETER", "REQUIRED_TEMPLATE_VARIABLES" ], "allOf": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index ee7c78c369698..5d88d599e3039 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -7572,11 +7572,8 @@ }, "codersdk.JobErrorCode": { "type": "string", - "enum": ["MISSING_TEMPLATE_PARAMETER", "REQUIRED_TEMPLATE_VARIABLES"], - "x-enum-varnames": [ - "MissingTemplateParameter", - "RequiredTemplateVariables" - ] + "enum": ["REQUIRED_TEMPLATE_VARIABLES"], + "x-enum-varnames": ["RequiredTemplateVariables"] }, "codersdk.License": { "type": "object", @@ -8070,7 +8067,7 @@ "type": "string" }, "error_code": { - "enum": ["MISSING_TEMPLATE_PARAMETER", "REQUIRED_TEMPLATE_VARIABLES"], + "enum": ["REQUIRED_TEMPLATE_VARIABLES"], "allOf": [ { "$ref": "#/definitions/codersdk.JobErrorCode" diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index 3b6bcf1ae832b..26090a4f1be99 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -525,7 +525,7 @@ func (b *Builder) getParameters() (names, values []string, err error) { // At this point, we've queried all the data we need from the database, // so the only errors are problems with the request (missing data, failed // validation, immutable parameters, etc.) - return nil, nil, BuildError{http.StatusBadRequest, err.Error(), err} + return nil, nil, BuildError{http.StatusBadRequest, fmt.Sprintf("Unable to validate parameter %q", templateVersionParameter.Name), err} } names = append(names, templateVersionParameter.Name) values = append(values, value) diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go index 30e0896707d56..4a3e280697f74 100644 --- a/codersdk/provisionerdaemons.go +++ b/codersdk/provisionerdaemons.go @@ -69,7 +69,6 @@ const ( type JobErrorCode string const ( - MissingTemplateParameter JobErrorCode = "MISSING_TEMPLATE_PARAMETER" RequiredTemplateVariables JobErrorCode = "REQUIRED_TEMPLATE_VARIABLES" ) @@ -81,7 +80,7 @@ type ProvisionerJob struct { CompletedAt *time.Time `json:"completed_at,omitempty" format:"date-time"` CanceledAt *time.Time `json:"canceled_at,omitempty" format:"date-time"` Error string `json:"error,omitempty"` - ErrorCode JobErrorCode `json:"error_code,omitempty" enums:"MISSING_TEMPLATE_PARAMETER,REQUIRED_TEMPLATE_VARIABLES"` + ErrorCode JobErrorCode `json:"error_code,omitempty" enums:"REQUIRED_TEMPLATE_VARIABLES"` Status ProvisionerJobStatus `json:"status" enums:"pending,running,succeeded,canceling,canceled,failed"` WorkerID *uuid.UUID `json:"worker_id,omitempty" format:"uuid"` FileID uuid.UUID `json:"file_id" format:"uuid"` diff --git a/docs/api/builds.md b/docs/api/builds.md index 782e41a6f61aa..f6aa71be7a555 100644 --- a/docs/api/builds.md +++ b/docs/api/builds.md @@ -39,7 +39,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -201,7 +201,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \ "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -759,7 +759,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/sta "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -926,7 +926,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -1163,7 +1163,6 @@ Status Code **200** | Property | Value | | ------------------------- | ----------------------------- | -| `error_code` | `MISSING_TEMPLATE_PARAMETER` | | `error_code` | `REQUIRED_TEMPLATE_VARIABLES` | | `status` | `pending` | | `status` | `running` | @@ -1273,7 +1272,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 019043cfda687..b9b55dc7fbe26 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -3090,7 +3090,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ## codersdk.JobErrorCode ```json -"MISSING_TEMPLATE_PARAMETER" +"REQUIRED_TEMPLATE_VARIABLES" ``` ### Properties @@ -3099,7 +3099,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | Value | | ----------------------------- | -| `MISSING_TEMPLATE_PARAMETER` | | `REQUIRED_TEMPLATE_VARIABLES` | ## codersdk.License @@ -3628,7 +3627,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -3666,7 +3665,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | Property | Value | | ------------ | ----------------------------- | -| `error_code` | `MISSING_TEMPLATE_PARAMETER` | | `error_code` | `REQUIRED_TEMPLATE_VARIABLES` | | `status` | `pending` | | `status` | `running` | @@ -4658,7 +4656,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -5371,7 +5369,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -5978,7 +5976,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -6505,7 +6503,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, diff --git a/docs/api/templates.md b/docs/api/templates.md index 14ce5dec7d29f..407ab84eba439 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -385,7 +385,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -455,7 +455,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -549,7 +549,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -850,7 +850,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions \ "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -920,7 +920,6 @@ Status Code **200** | Property | Value | | ------------ | ----------------------------- | -| `error_code` | `MISSING_TEMPLATE_PARAMETER` | | `error_code` | `REQUIRED_TEMPLATE_VARIABLES` | | `status` | `pending` | | `status` | `running` | @@ -1024,7 +1023,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions/{templ "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -1094,7 +1093,6 @@ Status Code **200** | Property | Value | | ------------ | ----------------------------- | -| `error_code` | `MISSING_TEMPLATE_PARAMETER` | | `error_code` | `REQUIRED_TEMPLATE_VARIABLES` | | `status` | `pending` | | `status` | `running` | @@ -1142,7 +1140,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion} \ "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -1221,7 +1219,7 @@ curl -X PATCH http://coder-server:8080/api/v2/templateversions/{templateversion} "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -1347,7 +1345,7 @@ curl -X POST http://coder-server:8080/api/v2/templateversions/{templateversion}/ "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -1400,7 +1398,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, diff --git a/docs/api/workspaces.md b/docs/api/workspaces.md index f5c4aadd729c5..01b85e21b3527 100644 --- a/docs/api/workspaces.md +++ b/docs/api/workspaces.md @@ -67,7 +67,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/member "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -255,7 +255,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -446,7 +446,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \ "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -631,7 +631,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \ "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, @@ -953,7 +953,7 @@ curl -X PUT http://coder-server:8080/api/v2/workspaces/{workspace}/lock \ "completed_at": "2019-08-24T14:15:22Z", "created_at": "2019-08-24T14:15:22Z", "error": "string", - "error_code": "MISSING_TEMPLATE_PARAMETER", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "queue_position": 0, diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 7625368589e31..eefbcfba275e7 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1225,7 +1225,6 @@ const getMissingParameters = ( if (isMutableAndRequired || isImmutable) { requiredParameters.push(p) - return } }) @@ -1248,6 +1247,35 @@ const getMissingParameters = ( missingParameters.push(parameter) } + // Check if parameter "options" changed and we can't use old build parameters. + templateParameters.forEach((templateParameter) => { + if (templateParameter.options.length === 0) { + return + } + + // Check if there is a new value + let buildParameter = newBuildParameters.find( + (p) => p.name === templateParameter.name, + ) + + // If not, get the old one + if (!buildParameter) { + buildParameter = oldBuildParameters.find( + (p) => p.name === templateParameter.name, + ) + } + + if (!buildParameter) { + return + } + + const matchingOption = templateParameter.options.find( + (option) => option.value === buildParameter?.value, + ) + if (!matchingOption) { + missingParameters.push(templateParameter) + } + }) return missingParameters } diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 7d93591344fb8..ebe8fb61218e2 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1663,13 +1663,8 @@ export type InsightsReportInterval = "day" export const InsightsReportIntervals: InsightsReportInterval[] = ["day"] // From codersdk/provisionerdaemons.go -export type JobErrorCode = - | "MISSING_TEMPLATE_PARAMETER" - | "REQUIRED_TEMPLATE_VARIABLES" -export const JobErrorCodes: JobErrorCode[] = [ - "MISSING_TEMPLATE_PARAMETER", - "REQUIRED_TEMPLATE_VARIABLES", -] +export type JobErrorCode = "REQUIRED_TEMPLATE_VARIABLES" +export const JobErrorCodes: JobErrorCode[] = ["REQUIRED_TEMPLATE_VARIABLES"] // From codersdk/provisionerdaemons.go export type LogLevel = "debug" | "error" | "info" | "trace" | "warn" diff --git a/site/src/pages/WorkspacePage/UpdateBuildParametersDialog.tsx b/site/src/pages/WorkspacePage/UpdateBuildParametersDialog.tsx index 33d42b6bc5ae2..860969267fb7e 100644 --- a/site/src/pages/WorkspacePage/UpdateBuildParametersDialog.tsx +++ b/site/src/pages/WorkspacePage/UpdateBuildParametersDialog.tsx @@ -48,6 +48,7 @@ export const UpdateBuildParametersDialog: FC< onSubmit: (values) => { onUpdate(values.rich_parameter_values) }, + enableReinitialize: true, }) const getFieldHelpers = getFormHelpers(form) const { t } = useTranslation("workspacePage") diff --git a/site/src/xServices/createTemplate/createTemplateXService.ts b/site/src/xServices/createTemplate/createTemplateXService.ts index 3d4205fc23f05..bfff04549fe17 100644 --- a/site/src/xServices/createTemplate/createTemplateXService.ts +++ b/site/src/xServices/createTemplate/createTemplateXService.ts @@ -517,11 +517,7 @@ export const createTemplateMachine = isNotUsingExample: ({ exampleId }) => !exampleId, hasFile: ({ file }) => Boolean(file), hasFailed: (_, { data }) => - Boolean( - data.job.status === "failed" && - !isMissingParameter(data) && - !isMissingVariables(data), - ), + Boolean(data.job.status === "failed" && !isMissingVariables(data)), hasNoParametersOrVariables: (_, { data }) => data.variables === undefined, hasParametersOrVariables: (_, { data }) => { @@ -531,13 +527,6 @@ export const createTemplateMachine = }, ) -const isMissingParameter = (version: TemplateVersion) => { - return Boolean( - version.job.error_code && - version.job.error_code === "MISSING_TEMPLATE_PARAMETER", - ) -} - const isMissingVariables = (version: TemplateVersion) => { return Boolean( version.job.error_code &&