From af7f27f2cc02a5630893cd8facedc2c9390d4197 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 16 Feb 2024 15:09:38 +0100 Subject: [PATCH 1/8] First steps --- provider/parameter.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/provider/parameter.go b/provider/parameter.go index 339bb017..b6480020 100644 --- a/provider/parameter.go +++ b/provider/parameter.go @@ -314,10 +314,9 @@ func parameterDataSource() *schema.Resource { Optional: true, }, "error": { - Type: schema.TypeString, - Optional: true, - RequiredWith: []string{"validation.0.regex"}, - Description: "An error message to display if the value doesn't match the provided regex.", + Type: schema.TypeString, + Optional: true, + Description: "An error message to display if the value breaks the validation rules.", }, }, }, @@ -438,16 +437,16 @@ func (v *Validation) Valid(typ, value string) error { case "number": num, err := strconv.Atoi(value) if err != nil { - return fmt.Errorf("value %q is not a number", value) + return validationError(v.Error, "value %q is not a number", value) } if !v.MinDisabled && num < v.Min { - return fmt.Errorf("value %d is less than the minimum %d", num, v.Min) + return validationError(v.Error, "value %d is less than the minimum %d", num, v.Min) } if !v.MaxDisabled && num > v.Max { - return fmt.Errorf("value %d is more than the maximum %d", num, v.Max) + return validationError(v.Error, "value %d is more than the maximum %d", num, v.Max) } if v.Monotonic != "" && v.Monotonic != ValidationMonotonicIncreasing && v.Monotonic != ValidationMonotonicDecreasing { - return fmt.Errorf("number monotonicity can be either %q or %q", ValidationMonotonicIncreasing, ValidationMonotonicDecreasing) + return validationError(v.Error, "number monotonicity can be either %q or %q", ValidationMonotonicIncreasing, ValidationMonotonicDecreasing) } case "list(string)": var listOfStrings []string @@ -466,3 +465,10 @@ func ParameterEnvironmentVariable(name string) string { sum := sha256.Sum256([]byte(name)) return "CODER_PARAMETER_" + hex.EncodeToString(sum[:]) } + +func validationError(customMessage, defaultMessage string, a ...any) error { + if customMessage != "" { + return fmt.Errorf(customMessage) + } + return fmt.Errorf(defaultMessage, a...) +} From 02af5eaa74418b7e216a7fd96d028062e22473aa Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 16 Feb 2024 15:18:47 +0100 Subject: [PATCH 2/8] md --- docs/data-sources/parameter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-sources/parameter.md b/docs/data-sources/parameter.md index fc8100e7..0ad2d6e5 100644 --- a/docs/data-sources/parameter.md +++ b/docs/data-sources/parameter.md @@ -57,7 +57,7 @@ Optional: Optional: -- `error` (String) An error message to display if the value doesn't match the provided regex. +- `error` (String) An error message to display if the value breaks the validation rules. - `max` (Number) The maximum of a number parameter. - `min` (Number) The minimum of a number parameter. - `monotonic` (String) Number monotonicity, either increasing or decreasing. From 6cdb775c7a3cf6759867f5aadc1e91d4c1deb0fb Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 19 Feb 2024 14:08:28 +0100 Subject: [PATCH 3/8] unit test --- provider/parameter_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/provider/parameter_test.go b/provider/parameter_test.go index 48cf4829..e60c96f7 100644 --- a/provider/parameter_test.go +++ b/provider/parameter_test.go @@ -527,6 +527,20 @@ data "coder_parameter" "region" { } `, ExpectError: regexp.MustCompile("is more than the maximum"), + }, { + Name: "NumberValidation_CustomError", + Config: ` + data "coder_parameter" "region" { + name = "Region" + type = "number" + default = 5 + validation { + max = 3 + error = "foobar" + } + } + `, + ExpectError: regexp.MustCompile("foobar"), }, { Name: "NumberValidation_NotInRange", Config: ` From 50eec53c7a76cee14e8f3f5381ff6d62c74010b8 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 19 Feb 2024 14:35:36 +0100 Subject: [PATCH 4/8] must be region --- provider/parameter_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/provider/parameter_test.go b/provider/parameter_test.go index e60c96f7..3ce3f5ef 100644 --- a/provider/parameter_test.go +++ b/provider/parameter_test.go @@ -149,6 +149,19 @@ func TestParameter(t *testing.T) { } `, ExpectError: regexp.MustCompile("is not a bool"), + }, { + Name: "Bool_CustomError", + Config: ` + data "coder_parameter" "region" { + name = "region" + type = "bool" + default = true + validation { + error = "foobar" + } + } + `, + ExpectError: regexp.MustCompile("is not a bool"), }, { Name: "OptionNotBool", Config: ` From ad8d249d2106e4ecaa5f998fbee36aba00bca580 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 19 Feb 2024 14:46:44 +0100 Subject: [PATCH 5/8] revert --- provider/parameter_test.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/provider/parameter_test.go b/provider/parameter_test.go index 3ce3f5ef..e60c96f7 100644 --- a/provider/parameter_test.go +++ b/provider/parameter_test.go @@ -149,19 +149,6 @@ func TestParameter(t *testing.T) { } `, ExpectError: regexp.MustCompile("is not a bool"), - }, { - Name: "Bool_CustomError", - Config: ` - data "coder_parameter" "region" { - name = "region" - type = "bool" - default = true - validation { - error = "foobar" - } - } - `, - ExpectError: regexp.MustCompile("is not a bool"), }, { Name: "OptionNotBool", Config: ` From e831d0e118a183ec33b514313592fb3366130427 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 19 Feb 2024 15:10:09 +0100 Subject: [PATCH 6/8] Fix --- provider/parameter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider/parameter.go b/provider/parameter.go index b6480020..59088827 100644 --- a/provider/parameter.go +++ b/provider/parameter.go @@ -446,7 +446,7 @@ func (v *Validation) Valid(typ, value string) error { return validationError(v.Error, "value %d is more than the maximum %d", num, v.Max) } if v.Monotonic != "" && v.Monotonic != ValidationMonotonicIncreasing && v.Monotonic != ValidationMonotonicDecreasing { - return validationError(v.Error, "number monotonicity can be either %q or %q", ValidationMonotonicIncreasing, ValidationMonotonicDecreasing) + return fmt.Errorf("number monotonicity can be either %q or %q", ValidationMonotonicIncreasing, ValidationMonotonicDecreasing) } case "list(string)": var listOfStrings []string From 6d2385333fbcc7fd5df0996efe068ebf6a0588ce Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 19 Feb 2024 16:19:47 +0100 Subject: [PATCH 7/8] render error --- provider/parameter.go | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/provider/parameter.go b/provider/parameter.go index 59088827..4aca4334 100644 --- a/provider/parameter.go +++ b/provider/parameter.go @@ -10,6 +10,7 @@ import ( "os" "regexp" "strconv" + "strings" "github.com/google/uuid" "github.com/hashicorp/go-cty/cty" @@ -437,13 +438,13 @@ func (v *Validation) Valid(typ, value string) error { case "number": num, err := strconv.Atoi(value) if err != nil { - return validationError(v.Error, "value %q is not a number", value) + return takeFirstError(v.errorRendered(value), fmt.Errorf("value %q is not a number", value)) } if !v.MinDisabled && num < v.Min { - return validationError(v.Error, "value %d is less than the minimum %d", num, v.Min) + return takeFirstError(v.errorRendered(value), fmt.Errorf("value %d is less than the minimum %d", num, v.Min)) } if !v.MaxDisabled && num > v.Max { - return validationError(v.Error, "value %d is more than the maximum %d", num, v.Max) + return takeFirstError(v.errorRendered(value), fmt.Errorf("value %d is more than the maximum %d", num, v.Max)) } if v.Monotonic != "" && v.Monotonic != ValidationMonotonicIncreasing && v.Monotonic != ValidationMonotonicDecreasing { return fmt.Errorf("number monotonicity can be either %q or %q", ValidationMonotonicIncreasing, ValidationMonotonicDecreasing) @@ -466,9 +467,22 @@ func ParameterEnvironmentVariable(name string) string { return "CODER_PARAMETER_" + hex.EncodeToString(sum[:]) } -func validationError(customMessage, defaultMessage string, a ...any) error { - if customMessage != "" { - return fmt.Errorf(customMessage) +func takeFirstError(errs ...error) error { + for _, err := range errs { + if err != nil { + return err + } + } + return xerrors.Errorf("developer error: error message is not provided") +} + +func (v *Validation) errorRendered(value string) error { + if v.Error == "" { + return nil } - return fmt.Errorf(defaultMessage, a...) + r := strings.NewReplacer( + "{min}", fmt.Sprintf("%d", v.Min), + "{max}", fmt.Sprintf("%d", v.Max), + "{value}", value) + return xerrors.Errorf(r.Replace(v.Error)) } From 2f26b39d7e5b9a6a38ff489ed2923f15683b380e Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 19 Feb 2024 16:29:20 +0100 Subject: [PATCH 8/8] docs --- docs/data-sources/parameter.md | 2 +- provider/parameter.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-sources/parameter.md b/docs/data-sources/parameter.md index 0ad2d6e5..4bded2d3 100644 --- a/docs/data-sources/parameter.md +++ b/docs/data-sources/parameter.md @@ -57,7 +57,7 @@ Optional: Optional: -- `error` (String) An error message to display if the value breaks the validation rules. +- `error` (String) An error message to display if the value breaks the validation rules. The following placeholders are supported: {max}, {min}, and {value}. - `max` (Number) The maximum of a number parameter. - `min` (Number) The minimum of a number parameter. - `monotonic` (String) Number monotonicity, either increasing or decreasing. diff --git a/provider/parameter.go b/provider/parameter.go index 4aca4334..f4a31b7f 100644 --- a/provider/parameter.go +++ b/provider/parameter.go @@ -317,7 +317,7 @@ func parameterDataSource() *schema.Resource { "error": { Type: schema.TypeString, Optional: true, - Description: "An error message to display if the value breaks the validation rules.", + Description: "An error message to display if the value breaks the validation rules. The following placeholders are supported: {max}, {min}, and {value}.", }, }, },