Files
ReleaseKit/validation_error.go

122 lines
3.5 KiB
Go

package releasekit
import (
"errors"
"fmt"
"strings"
"gitea.maximumdirect.net/eric/ReleaseKit/internal/validation"
)
// ValidationCheck identifies a shared validation check that failed.
// Current checks include "go-test".
type ValidationCheck string
// ValidationFinding describes a failed check observation at an optional
// repository-relative source location.
type ValidationFinding struct {
Path string // repository-relative path when available
Line int // one-based source line, or zero when unavailable
Column int // one-based source column, or zero when unavailable
Message string // useful detail that is not promised to have exact wording
Target string // applicable target for a file check
Directive string // applicable directive for a file check
}
// FileSizeMeasurement reports a measured file size and its selected limit.
type FileSizeMeasurement struct {
Bytes int64
LimitBytes int64
}
// ValidationError describes a failed shared validation check returned by
// [Check] or [Publish]. Cause preserves the contextual and underlying error chain.
type ValidationError struct {
Check ValidationCheck // failed shared check
Findings []ValidationFinding // actionable observations, when available
Measurement *FileSizeMeasurement // measured file size, when applicable
Cause error // original contextual and underlying error chain
}
// Error returns the contextual validation error summary.
func (failure *ValidationError) Error() string {
if failure == nil {
return "<nil>"
}
if failure.Cause != nil {
return failure.Cause.Error()
}
return formatPublicValidationError(failure)
}
// Unwrap returns the original validation error chain.
func (failure *ValidationError) Unwrap() error {
if failure == nil {
return nil
}
return failure.Cause
}
func convertValidationError(err error) error {
if err == nil {
return nil
}
var failure *validation.Failure
if !errors.As(err, &failure) {
return err
}
result := &ValidationError{
Check: ValidationCheck(failure.Check),
Cause: err,
}
if len(failure.Findings) != 0 {
result.Findings = make([]ValidationFinding, len(failure.Findings))
for index, finding := range failure.Findings {
result.Findings[index] = ValidationFinding{
Path: finding.Path,
Line: finding.Line,
Column: finding.Column,
Message: finding.Message,
Target: finding.Target,
Directive: finding.Directive,
}
}
}
if failure.Measurement != nil {
result.Measurement = &FileSizeMeasurement{
Bytes: failure.Measurement.Bytes,
LimitBytes: failure.Measurement.LimitBytes,
}
}
return result
}
func formatPublicValidationError(failure *ValidationError) string {
var summary strings.Builder
if failure.Check == "" {
summary.WriteString("validation failed")
} else {
fmt.Fprintf(&summary, "%s validation failed", failure.Check)
}
for _, finding := range failure.Findings {
summary.WriteString(": ")
if finding.Path != "" {
summary.WriteString(finding.Path)
if finding.Line > 0 {
fmt.Fprintf(&summary, ":%d", finding.Line)
if finding.Column > 0 {
fmt.Fprintf(&summary, ":%d", finding.Column)
}
}
summary.WriteString(": ")
}
summary.WriteString(finding.Message)
}
if failure.Measurement != nil {
fmt.Fprintf(&summary, ": measured %d bytes against a %d byte limit", failure.Measurement.Bytes, failure.Measurement.LimitBytes)
}
return summary.String()
}
var _ error = (*ValidationError)(nil)