package cli import ( "errors" "fmt" "io" "gitea.maximumdirect.net/eric/notarius/internal/core/debugbundle" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" ) type DebugTerminalWriter interface { WriteRunReport(debugbundle.RunReport) error WriteError(string) error } type pipelineCommandState struct { report debugbundle.RunReport terminalized bool } func newPipelineCommandState(runID, pipelineID, outputPath string) *pipelineCommandState { return &pipelineCommandState{report: debugbundle.RunReport{ RunID: runID, PipelineID: pipelineID, OutputPath: outputPath, }} } func (s *pipelineCommandState) setDebugPath(debugPath string) { if s != nil { s.report.DebugPath = debugPath } } func (s *pipelineCommandState) observeOutput(output pipeline.RunOutput) { if s == nil { return } s.report.OutputCount = len(output.NormalizeOutputs) s.report.RejectedCount = len(output.Rejected) s.report.WarningCount = len(output.Warnings) s.report.ValidationStatus = output.Manifest.ValidationStatus } func (s *pipelineCommandState) terminalize(writer DebugTerminalWriter, primaryErr error) (error, error) { if s == nil || s.terminalized { return primaryErr, nil } s.terminalized = true if writer == nil { return primaryErr, nil } report := s.report report.Succeeded = primaryErr == nil reportErr := writer.WriteRunReport(report) if reportErr != nil { reportErr = fmt.Errorf("write debug run report: %w", reportErr) if primaryErr == nil { primaryErr = reportErr reportErr = nil } } var errorLogErr error if primaryErr != nil { if err := writer.WriteError(primaryErr.Error()); err != nil { errorLogErr = fmt.Errorf("write debug error log: %w", err) } } return primaryErr, errors.Join(reportErr, errorLogErr) } func failPipelineCommand(stderr io.Writer, state *pipelineCommandState, writer DebugTerminalWriter, primaryErr error, persistenceErrs ...error) int { primaryErr, terminalErr := state.terminalize(writer, primaryErr) persistenceErrs = append(persistenceErrs, terminalErr) return writePipelineCommandFailure(stderr, state, primaryErr, errors.Join(persistenceErrs...)) } func writePipelineCommandFailure(stderr io.Writer, state *pipelineCommandState, primaryErr, persistenceErr error) int { fmt.Fprintf(stderr, "notarius: %v\n", primaryErr) if persistenceErr != nil { fmt.Fprintf(stderr, "notarius: %v\n", persistenceErr) } if state != nil && state.report.DebugPath != "" { fmt.Fprintf(stderr, "notarius: debug=%s\n", state.report.DebugPath) } return 1 }