diff options
author | Pavlo Strokov <pstrokov@gitlab.com> | 2023-02-15 01:28:39 +0300 |
---|---|---|
committer | Pavlo Strokov <pstrokov@gitlab.com> | 2023-03-21 00:38:57 +0300 |
commit | e0b945da70367b68e9b1eb78386a1d2b6bfe9c95 (patch) | |
tree | d73132f0787daaaecf8bacc0046b889165228bf9 /internal/errors/cfgerror/validate.go | |
parent | 902f1f365fd2f0c8e190accdb092d533cc4692a9 (diff) |
gitaly: Validation of Git configuration
We want to make errors of configuration validation more verbose
and flexible to operate with. The idea is to produce a machine
friendly output that is why the ValidationError structure is defined.
The next steps are to refactor existing validation methods to return
errors as instances of the ValidationError combined into
ValidationErrors.
The first refactored validation is for the Git type. It now has a
new Validate method that returns all the validation errors found.
Diffstat (limited to 'internal/errors/cfgerror/validate.go')
-rw-r--r-- | internal/errors/cfgerror/validate.go | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/internal/errors/cfgerror/validate.go b/internal/errors/cfgerror/validate.go new file mode 100644 index 000000000..54a31123b --- /dev/null +++ b/internal/errors/cfgerror/validate.go @@ -0,0 +1,98 @@ +package cfgerror + +import ( + "errors" + "fmt" + "strings" +) + +// ErrNotSet should be used when the value is not set, but it is required. +var ErrNotSet = errors.New("not set") + +// ValidationError represents an issue with provided configuration. +type ValidationError struct { + // Key represents a path to the field. + Key []string + // Cause contains a reason why validation failed. + Cause error +} + +// Error to implement an error standard interface. +// The string representation can have 3 different formats: +// - when Key and Cause is set: "outer.inner: failure cause" +// - when only Key is set: "outer.inner" +// - when only Cause is set: "failure cause" +func (ve ValidationError) Error() string { + if len(ve.Key) != 0 && ve.Cause != nil { + return fmt.Sprintf("%s: %v", strings.Join(ve.Key, "."), ve.Cause) + } + if len(ve.Key) != 0 { + return strings.Join(ve.Key, ".") + } + if ve.Cause != nil { + return fmt.Sprintf("%v", ve.Cause) + } + return "" +} + +// NewValidationError creates a new ValidationError with provided parameters. +func NewValidationError(err error, keys ...string) ValidationError { + return ValidationError{Key: keys, Cause: err} +} + +// ValidationErrors is a list of ValidationError-s. +type ValidationErrors []ValidationError + +// Append adds provided error into current list by enriching each ValidationError with the +// provided keys or if provided err is not an instance of the ValidationError it will be wrapped +// into it. In case the nil is provided nothing happens. +func (vs ValidationErrors) Append(err error, keys ...string) ValidationErrors { + switch terr := err.(type) { + case nil: + return vs + case ValidationErrors: + for _, err := range terr { + vs = append(vs, ValidationError{ + Key: append(keys, err.Key...), + Cause: err.Cause, + }) + } + case ValidationError: + vs = append(vs, ValidationError{ + Key: append(keys, terr.Key...), + Cause: terr.Cause, + }) + default: + vs = append(vs, ValidationError{ + Key: keys, + Cause: err, + }) + } + + return vs +} + +// AsError returns nil if there are no elements and itself if there is at least one. +func (vs ValidationErrors) AsError() error { + if len(vs) != 0 { + return vs + } + return nil +} + +// Error transforms all validation errors into a single string joined by newline. +func (vs ValidationErrors) Error() string { + var buf strings.Builder + for i, ve := range vs { + if i != 0 { + buf.WriteString("\n") + } + buf.WriteString(ve.Error()) + } + return buf.String() +} + +// New returns uninitialized ValidationErrors object. +func New() ValidationErrors { + return nil +} |