118 lines
3.1 KiB
Go
118 lines
3.1 KiB
Go
package failure
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const SchemaVersionV1 = "ariadne.execution-failure.v1"
|
|
|
|
var codePattern = regexp.MustCompile(`^[A-Z][A-Z0-9_]{2,99}$`)
|
|
|
|
type Stage string
|
|
|
|
const (
|
|
StageIngestion Stage = "ingestion"
|
|
StageCorrelation Stage = "correlation"
|
|
StageTargetSelection Stage = "target_selection"
|
|
StageRepositoryAnalysis Stage = "repository_analysis"
|
|
StageRuntimeAnalysis Stage = "runtime_analysis"
|
|
StageTranslation Stage = "translation"
|
|
StageIOPSubmission Stage = "iop_submission"
|
|
StageIOPExecution Stage = "iop_execution"
|
|
StageChange Stage = "change"
|
|
StageValidation Stage = "validation"
|
|
StageMergeRequest Stage = "merge_request"
|
|
)
|
|
|
|
type Failure struct {
|
|
SchemaVersion string
|
|
Code string
|
|
Stage Stage
|
|
Message string
|
|
UserMessage string
|
|
Retryable bool
|
|
OccurredAt time.Time
|
|
DetailsReference string
|
|
Causes []Cause
|
|
}
|
|
|
|
type Cause struct {
|
|
Code string
|
|
Stage Stage
|
|
Message string
|
|
Retryable bool
|
|
}
|
|
|
|
func (failure Failure) Validate() error {
|
|
var validationErrors []error
|
|
if failure.SchemaVersion != SchemaVersionV1 {
|
|
validationErrors = append(
|
|
validationErrors,
|
|
fmt.Errorf("unsupported failure schema %q", failure.SchemaVersion),
|
|
)
|
|
}
|
|
if !codePattern.MatchString(failure.Code) {
|
|
validationErrors = append(validationErrors, errors.New("failure code is invalid"))
|
|
}
|
|
if !failure.Stage.Valid() {
|
|
validationErrors = append(validationErrors, errors.New("failure stage is invalid"))
|
|
}
|
|
if strings.TrimSpace(failure.Message) == "" {
|
|
validationErrors = append(validationErrors, errors.New("failure message is required"))
|
|
}
|
|
if strings.TrimSpace(failure.UserMessage) == "" {
|
|
validationErrors = append(validationErrors, errors.New("failure user message is required"))
|
|
}
|
|
if failure.OccurredAt.IsZero() {
|
|
validationErrors = append(validationErrors, errors.New("failure occurrence time is required"))
|
|
}
|
|
if len(failure.Causes) > 32 {
|
|
validationErrors = append(validationErrors, errors.New("failure cause stack exceeds 32 entries"))
|
|
}
|
|
for index, cause := range failure.Causes {
|
|
if err := cause.Validate(); err != nil {
|
|
validationErrors = append(
|
|
validationErrors,
|
|
fmt.Errorf("failure cause %d: %w", index, err),
|
|
)
|
|
}
|
|
}
|
|
return errors.Join(validationErrors...)
|
|
}
|
|
|
|
func (cause Cause) Validate() error {
|
|
var validationErrors []error
|
|
if !codePattern.MatchString(cause.Code) {
|
|
validationErrors = append(validationErrors, errors.New("cause code is invalid"))
|
|
}
|
|
if !cause.Stage.Valid() {
|
|
validationErrors = append(validationErrors, errors.New("cause stage is invalid"))
|
|
}
|
|
if strings.TrimSpace(cause.Message) == "" {
|
|
validationErrors = append(validationErrors, errors.New("cause message is required"))
|
|
}
|
|
return errors.Join(validationErrors...)
|
|
}
|
|
|
|
func (stage Stage) Valid() bool {
|
|
switch stage {
|
|
case StageIngestion,
|
|
StageCorrelation,
|
|
StageTargetSelection,
|
|
StageRepositoryAnalysis,
|
|
StageRuntimeAnalysis,
|
|
StageTranslation,
|
|
StageIOPSubmission,
|
|
StageIOPExecution,
|
|
StageChange,
|
|
StageValidation,
|
|
StageMergeRequest:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|