package app import ( "errors" "fmt" "strings" ) type runFailure struct { pipelineID string destinationID string backend string bundlePath string err error } type runFailures struct { items []runFailure } func (f *runFailures) add(pipelineID, destinationID, backend, bundlePath string, err error) { f.items = append(f.items, runFailure{ pipelineID: pipelineID, destinationID: destinationID, backend: backend, bundlePath: bundlePath, err: err, }) } func (f runFailures) Error() string { if len(f.items) == 0 { return "" } parts := make([]string, 0, len(f.items)) for _, item := range f.items { parts = append(parts, fmt.Sprintf("pipeline %s destination %s backend %s bundle %s: %v", item.pipelineID, item.destinationID, item.backend, item.bundlePath, item.err)) } return "run failed: " + strings.Join(parts, "; ") } func (f runFailures) outputErrors() []OutputError { if len(f.items) == 0 { return nil } errors := make([]OutputError, 0, len(f.items)) for _, item := range f.items { errors = append(errors, OutputError{ PipelineID: item.pipelineID, DestinationID: item.destinationID, Backend: item.backend, BundlePath: item.bundlePath, Message: item.err.Error(), }) } return errors } func IsPartialResultError(err error) bool { var failures runFailures return errors.As(err, &failures) } func (f runFailures) Unwrap() error { errs := make([]error, 0, len(f.items)) for _, item := range f.items { errs = append(errs, item.err) } return errors.Join(errs...) }