From c70d6a48d001952c1beb882ec68da5f7b1151f56 Mon Sep 17 00:00:00 2001 From: kylecarbs Date: Thu, 19 May 2022 13:04:33 +0000 Subject: [PATCH 1/4] feat: Expose the values contained in an HCL validation string to the API This allows the frontend to render inputs displaying these values! --- cli/cliui/parameter.go | 2 +- cli/templatecreate.go | 2 +- coderd/parameters.go | 33 +++++++++++++++++ coderd/templateversions.go | 15 ++++++-- coderd/templateversions_test.go | 30 +++++++++++++++ codersdk/parameters.go | 39 ++++++++++++++++---- codersdk/templateversions.go | 8 +--- site/src/api/typesGenerated.ts | 65 +++++++++++++++++---------------- 8 files changed, 142 insertions(+), 52 deletions(-) diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index 6918cd4357b68..895e3716678df 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -10,7 +10,7 @@ import ( "github.com/coder/coder/codersdk" ) -func ParameterSchema(cmd *cobra.Command, parameterSchema codersdk.TemplateVersionParameterSchema) (string, error) { +func ParameterSchema(cmd *cobra.Command, parameterSchema codersdk.ParameterSchema) (string, error) { _, _ = fmt.Fprintln(cmd.OutOrStdout(), Styles.Bold.Render("var."+parameterSchema.Name)) if parameterSchema.Description != "" { _, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+strings.TrimSpace(strings.Join(strings.Split(parameterSchema.Description, "\n"), "\n "))+"\n") diff --git a/cli/templatecreate.go b/cli/templatecreate.go index 92d0c29465e71..08c3ebba0a288 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -175,7 +175,7 @@ func createValidTemplateVersion(cmd *cobra.Command, client *codersdk.Client, org sort.Slice(parameterSchemas, func(i, j int) bool { return parameterSchemas[i].Name < parameterSchemas[j].Name }) - missingSchemas := make([]codersdk.TemplateVersionParameterSchema, 0) + missingSchemas := make([]codersdk.ParameterSchema, 0) for _, parameterSchema := range parameterSchemas { _, ok := valuesBySchemaID[parameterSchema.ID.String()] if ok { diff --git a/coderd/parameters.go b/coderd/parameters.go index 8f5ce04c83bfe..2930c3f909c37 100644 --- a/coderd/parameters.go +++ b/coderd/parameters.go @@ -8,9 +8,11 @@ import ( "github.com/go-chi/chi/v5" "github.com/google/uuid" + "golang.org/x/xerrors" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/httpapi" + "github.com/coder/coder/coderd/parameter" "github.com/coder/coder/codersdk" ) @@ -122,6 +124,37 @@ func (api *api) deleteParameter(rw http.ResponseWriter, r *http.Request) { }) } +func convertParameterSchema(parameterSchema database.ParameterSchema) (codersdk.ParameterSchema, error) { + contains := []string{} + if parameterSchema.ValidationCondition != "" { + var err error + contains, _, err = parameter.Contains(parameterSchema.ValidationCondition) + if err != nil { + return codersdk.ParameterSchema{}, xerrors.Errorf("parse validation condition for %q: %w", parameterSchema.Name, err) + } + } + + return codersdk.ParameterSchema{ + ID: parameterSchema.ID, + CreatedAt: parameterSchema.CreatedAt, + JobID: parameterSchema.JobID, + Name: parameterSchema.Name, + Description: parameterSchema.Description, + DefaultSourceScheme: parameterSchema.DefaultSourceScheme, + DefaultSourceValue: parameterSchema.DefaultSourceValue, + AllowOverrideSource: parameterSchema.AllowOverrideSource, + DefaultDestinationScheme: parameterSchema.DefaultDestinationScheme, + AllowOverrideDestination: parameterSchema.AllowOverrideDestination, + DefaultRefresh: parameterSchema.DefaultRefresh, + RedisplayValue: parameterSchema.RedisplayValue, + ValidationError: parameterSchema.ValidationError, + ValidationCondition: parameterSchema.ValidationCondition, + ValidationTypeSystem: parameterSchema.ValidationTypeSystem, + ValidationValueType: parameterSchema.ValidationValueType, + ValidationContains: contains, + }, nil +} + func convertParameterValue(parameterValue database.ParameterValue) codersdk.Parameter { return codersdk.Parameter{ ID: parameterValue.ID, diff --git a/coderd/templateversions.go b/coderd/templateversions.go index f1d70cb4c9b97..35e362527e4b6 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -95,11 +95,18 @@ func (api *api) templateVersionSchema(rw http.ResponseWriter, r *http.Request) { }) return } - if schemas == nil { - schemas = []database.ParameterSchema{} + apiSchemas := make([]codersdk.ParameterSchema, 0) + for _, schema := range schemas { + apiSchema, err := convertParameterSchema(schema) + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: fmt.Sprintf("convert: %s", err), + }) + return + } + apiSchemas = append(apiSchemas, apiSchema) } - - httpapi.Write(rw, http.StatusOK, schemas) + httpapi.Write(rw, http.StatusOK, apiSchemas) } func (api *api) templateVersionParameters(rw http.ResponseWriter, r *http.Request) { diff --git a/coderd/templateversions_test.go b/coderd/templateversions_test.go index 6512e482a1527..edf0efb9d315a 100644 --- a/coderd/templateversions_test.go +++ b/coderd/templateversions_test.go @@ -198,6 +198,36 @@ func TestTemplateVersionSchema(t *testing.T) { require.NotNil(t, schemas) require.Len(t, schemas, 1) }) + t.Run("ListContains", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, nil) + user := coderdtest.CreateFirstUser(t, client) + coderdtest.NewProvisionerDaemon(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ + Parse: []*proto.Parse_Response{{ + Type: &proto.Parse_Response_Complete{ + Complete: &proto.Parse_Complete{ + ParameterSchemas: []*proto.ParameterSchema{{ + Name: "example", + ValidationTypeSystem: proto.ParameterSchema_HCL, + ValidationValueType: "string", + ValidationCondition: `contains(["first", "second"], var.example)`, + DefaultDestination: &proto.ParameterDestination{ + Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE, + }, + }}, + }, + }, + }}, + Provision: echo.ProvisionComplete, + }) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + schemas, err := client.TemplateVersionSchema(context.Background(), version.ID) + require.NoError(t, err) + require.NotNil(t, schemas) + require.Len(t, schemas, 1) + require.Equal(t, []string{"first", "second"}, schemas[0].ValidationContains) + }) } func TestTemplateVersionParameters(t *testing.T) { diff --git a/codersdk/parameters.go b/codersdk/parameters.go index 9fd9d5d9cad8d..866b3cf00d33c 100644 --- a/codersdk/parameters.go +++ b/codersdk/parameters.go @@ -24,14 +24,37 @@ const ( // Parameter represents a set value for the scope. type Parameter struct { - ID uuid.UUID `db:"id" json:"id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - Scope ParameterScope `db:"scope" json:"scope"` - ScopeID uuid.UUID `db:"scope_id" json:"scope_id"` - Name string `db:"name" json:"name"` - SourceScheme database.ParameterSourceScheme `db:"source_scheme" json:"source_scheme"` - DestinationScheme database.ParameterDestinationScheme `db:"destination_scheme" json:"destination_scheme"` + ID uuid.UUID `json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Scope ParameterScope `json:"scope"` + ScopeID uuid.UUID `json:"scope_id"` + Name string `json:"name"` + SourceScheme database.ParameterSourceScheme `json:"source_scheme"` + DestinationScheme database.ParameterDestinationScheme `json:"destination_scheme"` +} + +type ParameterSchema struct { + ID uuid.UUID `json:"id"` + CreatedAt time.Time `json:"created_at"` + JobID uuid.UUID ` json:"job_id"` + Name string `json:"name"` + Description string `json:"description"` + DefaultSourceScheme database.ParameterSourceScheme `json:"default_source_scheme"` + DefaultSourceValue string `json:"default_source_value"` + AllowOverrideSource bool `json:"allow_override_source"` + DefaultDestinationScheme database.ParameterDestinationScheme `json:"default_destination_scheme"` + AllowOverrideDestination bool `json:"allow_override_destination"` + DefaultRefresh string `json:"default_refresh"` + RedisplayValue bool `json:"redisplay_value"` + ValidationError string `json:"validation_error"` + ValidationCondition string `json:"validation_condition"` + ValidationTypeSystem database.ParameterTypeSystem `json:"validation_type_system"` + ValidationValueType string `json:"validation_value_type"` + + // This is a special array of items provided if the validation condition + // explicitly states the value must be one of a set. + ValidationContains []string `json:"validation_contains"` } // CreateParameterRequest is used to create a new parameter value for a scope. diff --git a/codersdk/templateversions.go b/codersdk/templateversions.go index 64e3934c8732a..1c0e831779f2d 100644 --- a/codersdk/templateversions.go +++ b/codersdk/templateversions.go @@ -9,7 +9,6 @@ import ( "github.com/google/uuid" - "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/parameter" ) @@ -24,9 +23,6 @@ type TemplateVersion struct { Readme string `json:"readme"` } -// TemplateVersionParameterSchema represents a parameter parsed from template version source. -type TemplateVersionParameterSchema database.ParameterSchema - // TemplateVersionParameter represents a computed parameter value. type TemplateVersionParameter parameter.ComputedValue @@ -58,7 +54,7 @@ func (c *Client) CancelTemplateVersion(ctx context.Context, version uuid.UUID) e } // TemplateVersionSchema returns schemas for a template version by ID. -func (c *Client) TemplateVersionSchema(ctx context.Context, version uuid.UUID) ([]TemplateVersionParameterSchema, error) { +func (c *Client) TemplateVersionSchema(ctx context.Context, version uuid.UUID) ([]ParameterSchema, error) { res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/schema", version), nil) if err != nil { return nil, err @@ -67,7 +63,7 @@ func (c *Client) TemplateVersionSchema(ctx context.Context, version uuid.UUID) ( if res.StatusCode != http.StatusOK { return nil, readBodyAsError(res) } - var params []TemplateVersionParameterSchema + var params []ParameterSchema return params, json.NewDecoder(res.Body).Decode(¶ms) } diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 792ef3961313c..f5dc8b8cf3e62 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -49,7 +49,7 @@ export interface CreateOrganizationRequest { readonly name: string } -// From codersdk/parameters.go:38:6 +// From codersdk/parameters.go:61:6 export interface CreateParameterRequest { readonly name: string readonly source_value: string @@ -86,7 +86,7 @@ export interface CreateUserRequest { readonly organization_id: string } -// From codersdk/workspaces.go:34:6 +// From codersdk/workspaces.go:36:6 export interface CreateWorkspaceBuildRequest { readonly template_version_id?: string // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.WorkspaceTransition") @@ -169,6 +169,30 @@ export interface Parameter { readonly destination_scheme: string } +// From codersdk/parameters.go:37:6 +export interface ParameterSchema { + readonly id: string + readonly created_at: string + readonly job_id: string + readonly name: string + readonly description: string + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterSourceScheme") + readonly default_source_scheme: string + readonly default_source_value: string + readonly allow_override_source: boolean + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterDestinationScheme") + readonly default_destination_scheme: string + readonly allow_override_destination: boolean + readonly default_refresh: string + readonly redisplay_value: boolean + readonly validation_error: string + readonly validation_condition: string + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterTypeSystem") + readonly validation_type_system: string + readonly validation_value_type: string + readonly validation_contains: string[] +} + // From codersdk/provisionerdaemons.go:23:6 export interface ProvisionerDaemon { readonly id: string @@ -223,7 +247,7 @@ export interface Template { readonly description: string } -// From codersdk/templateversions.go:17:6 +// From codersdk/templateversions.go:16:6 export interface TemplateVersion { readonly id: string readonly template_id?: string @@ -234,7 +258,7 @@ export interface TemplateVersion { readonly readme: string } -// From codersdk/templateversions.go:31:6 +// From codersdk/templateversions.go:27:6 export interface TemplateVersionParameter { // Named type "github.com/coder/coder/coderd/database.ParameterValue" unknown, using "any" // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -243,29 +267,6 @@ export interface TemplateVersionParameter { readonly default_source_value: boolean } -// From codersdk/templateversions.go:28:6 -export interface TemplateVersionParameterSchema { - readonly id: string - readonly created_at: string - readonly job_id: string - readonly name: string - readonly description: string - // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterSourceScheme") - readonly default_source_scheme: string - readonly default_source_value: string - readonly allow_override_source: boolean - // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterDestinationScheme") - readonly default_destination_scheme: string - readonly allow_override_destination: boolean - readonly default_refresh: string - readonly redisplay_value: boolean - readonly validation_error: string - readonly validation_condition: string - // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterTypeSystem") - readonly validation_type_system: string - readonly validation_value_type: string -} - // From codersdk/templates.go:75:6 export interface TemplateVersionsByTemplateRequest extends Pagination { readonly template_id: string @@ -292,12 +293,12 @@ export interface UpdateUserProfileRequest { readonly username: string } -// From codersdk/workspaces.go:102:6 +// From codersdk/workspaces.go:134:6 export interface UpdateWorkspaceAutostartRequest { readonly schedule: string } -// From codersdk/workspaces.go:122:6 +// From codersdk/workspaces.go:154:6 export interface UpdateWorkspaceAutostopRequest { readonly schedule: string } @@ -352,7 +353,7 @@ export interface UsersRequest extends Pagination { readonly status?: string } -// From codersdk/workspaces.go:18:6 +// From codersdk/workspaces.go:20:6 export interface Workspace { readonly id: string readonly created_at: string @@ -429,12 +430,12 @@ export interface WorkspaceBuild { readonly job: ProvisionerJob } -// From codersdk/workspaces.go:55:6 +// From codersdk/workspaces.go:57:6 export interface WorkspaceBuildsRequest extends Pagination { readonly WorkspaceID: string } -// From codersdk/workspaces.go:141:6 +// From codersdk/workspaces.go:173:6 export interface WorkspaceFilter { readonly OrganizationID: string readonly Owner: string From c4a07a131da284ea3c0ddfe4026c0c603fe9a732 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 19 May 2022 08:10:16 -0500 Subject: [PATCH 2/4] Update codersdk/parameters.go Co-authored-by: Cian Johnston --- codersdk/parameters.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codersdk/parameters.go b/codersdk/parameters.go index 866b3cf00d33c..a2235d22136f5 100644 --- a/codersdk/parameters.go +++ b/codersdk/parameters.go @@ -37,7 +37,7 @@ type Parameter struct { type ParameterSchema struct { ID uuid.UUID `json:"id"` CreatedAt time.Time `json:"created_at"` - JobID uuid.UUID ` json:"job_id"` + JobID uuid.UUID `json:"job_id"` Name string `json:"name"` Description string `json:"description"` DefaultSourceScheme database.ParameterSourceScheme `json:"default_source_scheme"` From d3e33c81ed532d02e70e1f76538d859e9c9084f5 Mon Sep 17 00:00:00 2001 From: kylecarbs Date: Thu, 19 May 2022 13:11:41 +0000 Subject: [PATCH 3/4] Call a spade a space --- coderd/parameters.go | 6 +++--- codersdk/parameters.go | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/coderd/parameters.go b/coderd/parameters.go index 2930c3f909c37..7a13172ec448e 100644 --- a/coderd/parameters.go +++ b/coderd/parameters.go @@ -140,16 +140,16 @@ func convertParameterSchema(parameterSchema database.ParameterSchema) (codersdk. JobID: parameterSchema.JobID, Name: parameterSchema.Name, Description: parameterSchema.Description, - DefaultSourceScheme: parameterSchema.DefaultSourceScheme, + DefaultSourceScheme: string(parameterSchema.DefaultSourceScheme), DefaultSourceValue: parameterSchema.DefaultSourceValue, AllowOverrideSource: parameterSchema.AllowOverrideSource, - DefaultDestinationScheme: parameterSchema.DefaultDestinationScheme, + DefaultDestinationScheme: string(parameterSchema.DefaultDestinationScheme), AllowOverrideDestination: parameterSchema.AllowOverrideDestination, DefaultRefresh: parameterSchema.DefaultRefresh, RedisplayValue: parameterSchema.RedisplayValue, ValidationError: parameterSchema.ValidationError, ValidationCondition: parameterSchema.ValidationCondition, - ValidationTypeSystem: parameterSchema.ValidationTypeSystem, + ValidationTypeSystem: string(parameterSchema.ValidationTypeSystem), ValidationValueType: parameterSchema.ValidationValueType, ValidationContains: contains, }, nil diff --git a/codersdk/parameters.go b/codersdk/parameters.go index a2235d22136f5..78b0d84588e59 100644 --- a/codersdk/parameters.go +++ b/codersdk/parameters.go @@ -35,22 +35,22 @@ type Parameter struct { } type ParameterSchema struct { - ID uuid.UUID `json:"id"` - CreatedAt time.Time `json:"created_at"` - JobID uuid.UUID `json:"job_id"` - Name string `json:"name"` - Description string `json:"description"` - DefaultSourceScheme database.ParameterSourceScheme `json:"default_source_scheme"` - DefaultSourceValue string `json:"default_source_value"` - AllowOverrideSource bool `json:"allow_override_source"` - DefaultDestinationScheme database.ParameterDestinationScheme `json:"default_destination_scheme"` - AllowOverrideDestination bool `json:"allow_override_destination"` - DefaultRefresh string `json:"default_refresh"` - RedisplayValue bool `json:"redisplay_value"` - ValidationError string `json:"validation_error"` - ValidationCondition string `json:"validation_condition"` - ValidationTypeSystem database.ParameterTypeSystem `json:"validation_type_system"` - ValidationValueType string `json:"validation_value_type"` + ID uuid.UUID `json:"id"` + CreatedAt time.Time `json:"created_at"` + JobID uuid.UUID `json:"job_id"` + Name string `json:"name"` + Description string `json:"description"` + DefaultSourceScheme string `json:"default_source_scheme"` + DefaultSourceValue string `json:"default_source_value"` + AllowOverrideSource bool `json:"allow_override_source"` + DefaultDestinationScheme string `json:"default_destination_scheme"` + AllowOverrideDestination bool `json:"allow_override_destination"` + DefaultRefresh string `json:"default_refresh"` + RedisplayValue bool `json:"redisplay_value"` + ValidationError string `json:"validation_error"` + ValidationCondition string `json:"validation_condition"` + ValidationTypeSystem string `json:"validation_type_system"` + ValidationValueType string `json:"validation_value_type"` // This is a special array of items provided if the validation condition // explicitly states the value must be one of a set. From f422e7b4281e8a21987054bfba7fffe9da4f240e Mon Sep 17 00:00:00 2001 From: kylecarbs Date: Thu, 19 May 2022 13:17:53 +0000 Subject: [PATCH 4/4] Fix linting errors with type conversion --- cli/create.go | 2 +- cli/templatecreate.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/create.go b/cli/create.go index 6a274afa4f353..aa6930e8151f6 100644 --- a/cli/create.go +++ b/cli/create.go @@ -135,7 +135,7 @@ func create() *cobra.Command { Name: parameterSchema.Name, SourceValue: value, SourceScheme: database.ParameterSourceSchemeData, - DestinationScheme: parameterSchema.DefaultDestinationScheme, + DestinationScheme: database.ParameterDestinationScheme(parameterSchema.DefaultDestinationScheme), }) } _, _ = fmt.Fprintln(cmd.OutOrStdout()) diff --git a/cli/templatecreate.go b/cli/templatecreate.go index 08c3ebba0a288..0f6977a674a8e 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -193,7 +193,7 @@ func createValidTemplateVersion(cmd *cobra.Command, client *codersdk.Client, org Name: parameterSchema.Name, SourceValue: value, SourceScheme: database.ParameterSourceSchemeData, - DestinationScheme: parameterSchema.DefaultDestinationScheme, + DestinationScheme: database.ParameterDestinationScheme(parameterSchema.DefaultDestinationScheme), }) _, _ = fmt.Fprintln(cmd.OutOrStdout()) }