diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index 6918cd4357..895e371667 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/create.go b/cli/create.go index 6a274afa4f..aa6930e815 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 92d0c29465..0f6977a674 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 { @@ -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()) } diff --git a/coderd/parameters.go b/coderd/parameters.go index 8f5ce04c83..7a13172ec4 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: string(parameterSchema.DefaultSourceScheme), + DefaultSourceValue: parameterSchema.DefaultSourceValue, + AllowOverrideSource: parameterSchema.AllowOverrideSource, + DefaultDestinationScheme: string(parameterSchema.DefaultDestinationScheme), + AllowOverrideDestination: parameterSchema.AllowOverrideDestination, + DefaultRefresh: parameterSchema.DefaultRefresh, + RedisplayValue: parameterSchema.RedisplayValue, + ValidationError: parameterSchema.ValidationError, + ValidationCondition: parameterSchema.ValidationCondition, + ValidationTypeSystem: string(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 f1d70cb4c9..35e362527e 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 6512e482a1..edf0efb9d3 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 9fd9d5d9ca..78b0d84588 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 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. + 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 64e3934c87..1c0e831779 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 792ef39613..f5dc8b8cf3 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