diff --git a/cli/create_test.go b/cli/create_test.go index 75f29046ac163..be05656117c97 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -15,6 +15,7 @@ import ( "github.com/coder/coder/cli/clitest" "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/coderd/gitauth" + "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" "github.com/coder/coder/provisioner/echo" "github.com/coder/coder/provisionersdk/proto" @@ -494,7 +495,7 @@ func TestCreateValidateRichParameters(t *testing.T) { ) numberRichParameters := []*proto.RichParameter{ - {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10}, + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: ptr.Ref(int32(3)), ValidationMax: ptr.Ref(int32(10))}, } stringRichParameters := []*proto.RichParameter{ diff --git a/cli/update_test.go b/cli/update_test.go index 38526aefb4d76..81b0a05804a5d 100644 --- a/cli/update_test.go +++ b/cli/update_test.go @@ -11,6 +11,7 @@ import ( "github.com/coder/coder/cli/clitest" "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" "github.com/coder/coder/provisioner/echo" "github.com/coder/coder/provisionersdk/proto" @@ -245,7 +246,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { ) numberRichParameters := []*proto.RichParameter{ - {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10}, + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: ptr.Ref(int32(3)), ValidationMax: ptr.Ref(int32(10))}, } stringRichParameters := []*proto.RichParameter{ diff --git a/coderd/database/db2sdk/db2sdk.go b/coderd/database/db2sdk/db2sdk.go index 079b0689c40b2..dde447ffafc96 100644 --- a/coderd/database/db2sdk/db2sdk.go +++ b/coderd/database/db2sdk/db2sdk.go @@ -46,6 +46,17 @@ func TemplateVersionParameter(param database.TemplateVersionParameter) (codersdk if err != nil { return codersdk.TemplateVersionParameter{}, err } + + var validationMin *int32 + if param.ValidationMin.Valid { + validationMin = ¶m.ValidationMin.Int32 + } + + var validationMax *int32 + if param.ValidationMax.Valid { + validationMax = ¶m.ValidationMax.Int32 + } + return codersdk.TemplateVersionParameter{ Name: param.Name, DisplayName: param.DisplayName, @@ -57,8 +68,8 @@ func TemplateVersionParameter(param database.TemplateVersionParameter) (codersdk Icon: param.Icon, Options: options, ValidationRegex: param.ValidationRegex, - ValidationMin: param.ValidationMin, - ValidationMax: param.ValidationMax, + ValidationMin: validationMin, + ValidationMax: validationMax, ValidationError: param.ValidationError, ValidationMonotonic: codersdk.ValidationMonotonicOrder(param.ValidationMonotonic), Required: param.Required, diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 3520008680968..0c5846749a5c8 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -385,8 +385,8 @@ CREATE TABLE template_version_parameters ( icon text NOT NULL, options jsonb DEFAULT '[]'::jsonb NOT NULL, validation_regex text NOT NULL, - validation_min integer NOT NULL, - validation_max integer NOT NULL, + validation_min integer, + validation_max integer, validation_error text DEFAULT ''::text NOT NULL, validation_monotonic text DEFAULT ''::text NOT NULL, required boolean DEFAULT true NOT NULL, diff --git a/coderd/database/migrations/000124_validation_min_max_nullable.down.sql b/coderd/database/migrations/000124_validation_min_max_nullable.down.sql new file mode 100644 index 0000000000000..39a8eb69a33a5 --- /dev/null +++ b/coderd/database/migrations/000124_validation_min_max_nullable.down.sql @@ -0,0 +1,6 @@ +BEGIN; +UPDATE template_version_parameters SET validation_min = 0 WHERE validation_min = NULL; +UPDATE template_version_parameters SET validation_max = 0 WHERE validation_max = NULL; +ALTER TABLE template_version_parameters ALTER COLUMN validation_min SET NOT NULL; +ALTER TABLE template_version_parameters ALTER COLUMN validation_max SET NOT NULL; +COMMIT; diff --git a/coderd/database/migrations/000124_validation_min_max_nullable.up.sql b/coderd/database/migrations/000124_validation_min_max_nullable.up.sql new file mode 100644 index 0000000000000..ea3160747e55e --- /dev/null +++ b/coderd/database/migrations/000124_validation_min_max_nullable.up.sql @@ -0,0 +1,6 @@ +BEGIN; +ALTER TABLE template_version_parameters ALTER COLUMN validation_min DROP NOT NULL; +ALTER TABLE template_version_parameters ALTER COLUMN validation_max DROP NOT NULL; +UPDATE template_version_parameters SET validation_min = NULL WHERE validation_min = 0; +UPDATE template_version_parameters SET validation_max = NULL WHERE validation_max = 0; +COMMIT; diff --git a/coderd/database/models.go b/coderd/database/models.go index 4cef35e644a4c..33b51451333b7 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1535,9 +1535,9 @@ type TemplateVersionParameter struct { // Validation: regex pattern ValidationRegex string `db:"validation_regex" json:"validation_regex"` // Validation: minimum length of value - ValidationMin int32 `db:"validation_min" json:"validation_min"` + ValidationMin sql.NullInt32 `db:"validation_min" json:"validation_min"` // Validation: maximum length of value - ValidationMax int32 `db:"validation_max" json:"validation_max"` + ValidationMax sql.NullInt32 `db:"validation_max" json:"validation_max"` // Validation: error displayed when the regex does not match. ValidationError string `db:"validation_error" json:"validation_error"` // Validation: consecutive values preserve the monotonic order diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index de1a7231c3a8a..842dbd87ba75a 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -4164,8 +4164,8 @@ type InsertTemplateVersionParameterParams struct { Icon string `db:"icon" json:"icon"` Options json.RawMessage `db:"options" json:"options"` ValidationRegex string `db:"validation_regex" json:"validation_regex"` - ValidationMin int32 `db:"validation_min" json:"validation_min"` - ValidationMax int32 `db:"validation_max" json:"validation_max"` + ValidationMin sql.NullInt32 `db:"validation_min" json:"validation_min"` + ValidationMax sql.NullInt32 `db:"validation_max" json:"validation_max"` ValidationError string `db:"validation_error" json:"validation_error"` ValidationMonotonic string `db:"validation_monotonic" json:"validation_monotonic"` Required bool `db:"required" json:"required"` diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index d760a9e269fe4..f3a13e70bb574 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -919,6 +919,21 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete if err != nil { return nil, xerrors.Errorf("marshal parameter options: %w", err) } + + var validationMin, validationMax sql.NullInt32 + if richParameter.ValidationMin != nil { + validationMin = sql.NullInt32{ + Int32: *richParameter.ValidationMin, + Valid: true, + } + } + if richParameter.ValidationMax != nil { + validationMax = sql.NullInt32{ + Int32: *richParameter.ValidationMax, + Valid: true, + } + } + _, err = server.Database.InsertTemplateVersionParameter(ctx, database.InsertTemplateVersionParameterParams{ TemplateVersionID: input.TemplateVersionID, Name: richParameter.Name, @@ -931,8 +946,8 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete Options: options, ValidationRegex: richParameter.ValidationRegex, ValidationError: richParameter.ValidationError, - ValidationMin: richParameter.ValidationMin, - ValidationMax: richParameter.ValidationMax, + ValidationMin: validationMin, + ValidationMax: validationMax, ValidationMonotonic: richParameter.ValidationMonotonic, Required: richParameter.Required, LegacyVariableName: richParameter.LegacyVariableName, diff --git a/coderd/templateversions.go b/coderd/templateversions.go index 39d803049ba3d..25348e3a92683 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -1706,6 +1706,15 @@ func convertTemplateVersionParameter(param database.TemplateVersionParameter) (c if err != nil { return codersdk.TemplateVersionParameter{}, err } + + var validationMin, validationMax *int32 + if param.ValidationMin.Valid { + validationMin = ¶m.ValidationMin.Int32 + } + if param.ValidationMax.Valid { + validationMax = ¶m.ValidationMax.Int32 + } + return codersdk.TemplateVersionParameter{ Name: param.Name, DisplayName: param.DisplayName, @@ -1717,8 +1726,8 @@ func convertTemplateVersionParameter(param database.TemplateVersionParameter) (c Icon: param.Icon, Options: options, ValidationRegex: param.ValidationRegex, - ValidationMin: param.ValidationMin, - ValidationMax: param.ValidationMax, + ValidationMin: validationMin, + ValidationMax: validationMax, ValidationError: param.ValidationError, ValidationMonotonic: codersdk.ValidationMonotonicOrder(param.ValidationMonotonic), Required: param.Required, diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 7218792ac837b..36227d411acc4 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -1973,8 +1973,8 @@ func TestWorkspaceWithRichParameters(t *testing.T) { DisplayName: secondParameterDisplayName, Type: secondParameterType, Description: secondParameterDescription, - ValidationMin: 1, - ValidationMax: 3, + ValidationMin: ptr.Ref(int32(1)), + ValidationMax: ptr.Ref(int32(3)), ValidationMonotonic: string(secondParameterValidationMonotonic), }, }, diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go index 4bf3d24edca6c..3810eb3cb5871 100644 --- a/codersdk/richparameters.go +++ b/codersdk/richparameters.go @@ -79,8 +79,8 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui } validation := &provider.Validation{ - Min: int(richParameter.ValidationMin), - Max: int(richParameter.ValidationMax), + Min: ptrInt(richParameter.ValidationMin), + Max: ptrInt(richParameter.ValidationMax), Regex: richParameter.ValidationRegex, Error: richParameter.ValidationError, Monotonic: string(richParameter.ValidationMonotonic), @@ -88,6 +88,14 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui return validation.Valid(richParameter.Type, value) } +func ptrInt(number *int32) *int { + if number == nil { + return nil + } + n := int(*number) + return &n +} + func findBuildParameter(params []WorkspaceBuildParameter, parameterName string) (*WorkspaceBuildParameter, bool) { if params == nil { return nil, false @@ -111,7 +119,8 @@ func parameterValuesAsArray(options []TemplateVersionParameterOption) []string { func validationEnabled(param TemplateVersionParameter) bool { return len(param.ValidationRegex) > 0 || - (param.ValidationMin != 0 && param.ValidationMax != 0) || + param.ValidationMin != nil || + param.ValidationMax != nil || len(param.ValidationMonotonic) > 0 || param.Type == "bool" || // boolean type doesn't have any custom validation rules, but the value must be checked (true/false). param.Type == "list(string)" // list(string) type doesn't have special validation, but we need to check if this is a correct list. diff --git a/codersdk/richparameters_test.go b/codersdk/richparameters_test.go index fbc7d47748b11..70e933b01dfe3 100644 --- a/codersdk/richparameters_test.go +++ b/codersdk/richparameters_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" ) @@ -72,8 +73,8 @@ func TestParameterResolver_ValidateResolve_PrevInvalid(t *testing.T) { p := codersdk.TemplateVersionParameter{ Name: "n", Type: "number", - ValidationMax: 10, - ValidationMin: 1, + ValidationMax: ptr.Ref(int32(10)), + ValidationMin: ptr.Ref(int32(1)), } v, err := uut.ValidateResolve(p, nil) require.Error(t, err) @@ -89,8 +90,8 @@ func TestParameterResolver_ValidateResolve_DefaultInvalid(t *testing.T) { p := codersdk.TemplateVersionParameter{ Name: "n", Type: "number", - ValidationMax: 10, - ValidationMin: 1, + ValidationMax: ptr.Ref(int32(10)), + ValidationMin: ptr.Ref(int32(1)), DefaultValue: "11", } v, err := uut.ValidateResolve(p, nil) @@ -221,19 +222,19 @@ func TestRichParameterValidation(t *testing.T) { numberRichParameters := []codersdk.TemplateVersionParameter{ {Name: stringParameterName, Type: "string", Mutable: true}, - {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10}, + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: ptr.Ref(int32(3)), ValidationMax: ptr.Ref(int32(10))}, {Name: boolParameterName, Type: "bool", Mutable: true}, } monotonicIncreasingNumberRichParameters := []codersdk.TemplateVersionParameter{ {Name: stringParameterName, Type: "string", Mutable: true}, - {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10, ValidationMonotonic: "increasing"}, + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: ptr.Ref(int32(3)), ValidationMax: ptr.Ref(int32(10)), ValidationMonotonic: "increasing"}, {Name: boolParameterName, Type: "bool", Mutable: true}, } monotonicDecreasingNumberRichParameters := []codersdk.TemplateVersionParameter{ {Name: stringParameterName, Type: "string", Mutable: true}, - {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10, ValidationMonotonic: "decreasing"}, + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: ptr.Ref(int32(3)), ValidationMax: ptr.Ref(int32(10)), ValidationMonotonic: "decreasing"}, {Name: boolParameterName, Type: "bool", Mutable: true}, } diff --git a/codersdk/templateversions.go b/codersdk/templateversions.go index cfc9af54443ae..1597be7f9282b 100644 --- a/codersdk/templateversions.go +++ b/codersdk/templateversions.go @@ -59,8 +59,8 @@ type TemplateVersionParameter struct { Options []TemplateVersionParameterOption `json:"options"` ValidationError string `json:"validation_error,omitempty"` ValidationRegex string `json:"validation_regex,omitempty"` - ValidationMin int32 `json:"validation_min,omitempty"` - ValidationMax int32 `json:"validation_max,omitempty"` + ValidationMin *int32 `json:"validation_min,omitempty"` + ValidationMax *int32 `json:"validation_max,omitempty"` ValidationMonotonic ValidationMonotonicOrder `json:"validation_monotonic,omitempty" enums:"increasing,decreasing"` Required bool `json:"required"` LegacyVariableName string `json:"legacy_variable_name,omitempty"` diff --git a/go.mod b/go.mod index f1b1e58f75831..4d7182c361ef2 100644 --- a/go.mod +++ b/go.mod @@ -75,7 +75,7 @@ require ( github.com/codeclysm/extract v2.2.0+incompatible github.com/coder/flog v1.1.0 github.com/coder/retry v1.3.1-0.20230210155434-e90a2e1e091d - github.com/coder/terraform-provider-coder v0.6.23 + github.com/coder/terraform-provider-coder v0.8.1 github.com/coder/wgtunnel v0.1.5 github.com/coreos/go-oidc/v3 v3.6.0 github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf diff --git a/go.sum b/go.sum index b39045d6fd8a7..3c2d9c6c3c00c 100644 --- a/go.sum +++ b/go.sum @@ -336,8 +336,8 @@ github.com/coder/ssh v0.0.0-20230421140225-04bb837133e1 h1:LBw76rEDuhNJyohve11mb github.com/coder/ssh v0.0.0-20230421140225-04bb837133e1/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= github.com/coder/tailscale v0.0.0-20230522123520-74712221d00f h1:F0Xr1d8h8dAHn7tab1HXuzYFkcjmCydnEfdMbkOhlVk= github.com/coder/tailscale v0.0.0-20230522123520-74712221d00f/go.mod h1:jpg+77g19FpXL43U1VoIqoSg1K/Vh5CVxycGldQ8KhA= -github.com/coder/terraform-provider-coder v0.6.23 h1:O2Rcj0umez4DfVdGnKZi63z1Xzxd0IQOn9VQDB8YU8g= -github.com/coder/terraform-provider-coder v0.6.23/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= +github.com/coder/terraform-provider-coder v0.8.1 h1:i/LhvFi+Ei0gL+h4GItJfwtxjcITTlQhS+R8J+0vRo8= +github.com/coder/terraform-provider-coder v0.8.1/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= github.com/coder/wgtunnel v0.1.5 h1:WP3sCj/3iJ34eKvpMQEp1oJHvm24RYh0NHbj1kfUKfs= github.com/coder/wgtunnel v0.1.5/go.mod h1:bokoUrHnUFY4lu9KOeSYiIcHTI2MO1KwqumU4DPDyJI= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index 2f497a1ae79f1..28faadfa54aa5 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -483,8 +483,8 @@ func ConvertState(modules []*tfjson.StateModule, rawGraph string, rawParameterNa if len(param.Validation) == 1 { protoParam.ValidationRegex = param.Validation[0].Regex protoParam.ValidationError = param.Validation[0].Error - protoParam.ValidationMax = int32(param.Validation[0].Max) - protoParam.ValidationMin = int32(param.Validation[0].Min) + protoParam.ValidationMax = ptrInt32(param.Validation[0].Max) + protoParam.ValidationMin = ptrInt32(param.Validation[0].Min) protoParam.ValidationMonotonic = param.Validation[0].Monotonic } if len(param.Option) > 0 { @@ -527,6 +527,15 @@ func ConvertState(modules []*tfjson.StateModule, rawGraph string, rawParameterNa }, nil } +func ptrInt32(number *int) *int32 { + var n int32 + if number == nil { + return &n + } + n = int32(*number) + return &n +} + // convertAddressToLabel returns the Terraform address without the count // specifier. // eg. "module.ec2_dev.ec2_instance.dev[0]" becomes "module.ec2_dev.ec2_instance.dev" diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index 5e4a301e39f59..2c7d8be5592d9 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -819,8 +819,8 @@ type RichParameter struct { Options []*RichParameterOption `protobuf:"bytes,7,rep,name=options,proto3" json:"options,omitempty"` ValidationRegex string `protobuf:"bytes,8,opt,name=validation_regex,json=validationRegex,proto3" json:"validation_regex,omitempty"` ValidationError string `protobuf:"bytes,9,opt,name=validation_error,json=validationError,proto3" json:"validation_error,omitempty"` - ValidationMin int32 `protobuf:"varint,10,opt,name=validation_min,json=validationMin,proto3" json:"validation_min,omitempty"` - ValidationMax int32 `protobuf:"varint,11,opt,name=validation_max,json=validationMax,proto3" json:"validation_max,omitempty"` + ValidationMin *int32 `protobuf:"varint,10,opt,name=validation_min,json=validationMin,proto3,oneof" json:"validation_min,omitempty"` + ValidationMax *int32 `protobuf:"varint,11,opt,name=validation_max,json=validationMax,proto3,oneof" json:"validation_max,omitempty"` ValidationMonotonic string `protobuf:"bytes,12,opt,name=validation_monotonic,json=validationMonotonic,proto3" json:"validation_monotonic,omitempty"` Required bool `protobuf:"varint,13,opt,name=required,proto3" json:"required,omitempty"` LegacyVariableName string `protobuf:"bytes,14,opt,name=legacy_variable_name,json=legacyVariableName,proto3" json:"legacy_variable_name,omitempty"` @@ -923,15 +923,15 @@ func (x *RichParameter) GetValidationError() string { } func (x *RichParameter) GetValidationMin() int32 { - if x != nil { - return x.ValidationMin + if x != nil && x.ValidationMin != nil { + return *x.ValidationMin } return 0 } func (x *RichParameter) GetValidationMax() int32 { - if x != nil { - return x.ValidationMax + if x != nil && x.ValidationMax != nil { + return *x.ValidationMax } return 0 } @@ -2874,7 +2874,7 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x22, 0xb0, 0x04, 0x0a, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x22, 0xe0, 0x04, 0x0a, 0x0d, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, @@ -2894,22 +2894,25 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x09, 0x52, 0x0f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x29, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x25, 0x0a, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x0e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x69, 0x6e, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x4d, 0x69, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x12, 0x31, 0x0a, 0x14, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x6f, 0x6e, 0x6f, 0x74, 0x6f, - 0x6e, 0x69, 0x63, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x76, 0x61, 0x6c, 0x69, 0x64, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x6e, 0x6f, 0x74, 0x6f, 0x6e, 0x69, 0x63, 0x12, 0x1a, - 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x6c, 0x65, - 0x67, 0x61, 0x63, 0x79, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, - 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, - 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0f, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, + 0x0a, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x0d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x05, 0x48, 0x01, 0x52, 0x0d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x61, 0x78, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x14, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x6f, 0x6e, 0x6f, 0x74, 0x6f, 0x6e, 0x69, 0x63, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x13, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x6f, 0x6e, 0x6f, 0x74, 0x6f, 0x6e, 0x69, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x5f, 0x76, + 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x12, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, + 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x69, 0x6e, 0x42, 0x11, 0x0a, 0x0f, + 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x22, 0x3e, 0x0a, 0x12, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, @@ -3691,6 +3694,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } } + file_provisionersdk_proto_provisioner_proto_msgTypes[7].OneofWrappers = []interface{}{} file_provisionersdk_proto_provisioner_proto_msgTypes[13].OneofWrappers = []interface{}{ (*Agent_Token)(nil), (*Agent_InstanceId)(nil), diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 6cb29a3a015fd..27ee7d904a489 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -81,8 +81,8 @@ message RichParameter { repeated RichParameterOption options = 7; string validation_regex = 8; string validation_error = 9; - int32 validation_min = 10; - int32 validation_max = 11; + optional int32 validation_min = 10; + optional int32 validation_max = 11; string validation_monotonic = 12; bool required = 13; string legacy_variable_name = 14; diff --git a/site/src/i18n/en/createWorkspacePage.json b/site/src/i18n/en/createWorkspacePage.json index 44ecb110791e3..83a50fe97adf5 100644 --- a/site/src/i18n/en/createWorkspacePage.json +++ b/site/src/i18n/en/createWorkspacePage.json @@ -3,6 +3,8 @@ "nameLabel": "Workspace Name", "ownerLabel": "Owner", "createWorkspace": "Create workspace", + "validationNumberLesserThan": "Value must be greater than {{min}}.", + "validationNumberGreaterThan": "Value must be lesser than {{max}}.", "validationNumberNotInRange": "Value must be between {{min}} and {{max}}.", "validationPatternNotMatched": "{{error}} (value does not match the pattern {{pattern}})." } diff --git a/site/src/utils/richParameters.ts b/site/src/utils/richParameters.ts index 764dc1d0896f9..db2bd522518ea 100644 --- a/site/src/utils/richParameters.ts +++ b/site/src/utils/richParameters.ts @@ -69,6 +69,30 @@ export const useValidationSchemaForRichParameters = ( switch (templateParameter.type) { case "number": if ( + templateParameter.validation_min && + !templateParameter.validation_max + ) { + if (Number(val) < templateParameter.validation_min) { + return ctx.createError({ + path: ctx.path, + message: t("validationNumberLesserThan", { + min: templateParameter.validation_min, + }), + }) + } + } else if ( + !templateParameter.validation_min && + templateParameter.validation_max + ) { + if (templateParameter.validation_max < Number(val)) { + return ctx.createError({ + path: ctx.path, + message: t("validationNumberGreaterThan", { + max: templateParameter.validation_max, + }), + }) + } + } else if ( templateParameter.validation_min && templateParameter.validation_max ) {