package pipeline import ( "fmt" "gitea.maximumdirect.net/eric/notarius/internal/core/source" "gitea.maximumdirect.net/eric/notarius/internal/framework/contracts" frameworkdiagnostics "gitea.maximumdirect.net/eric/notarius/internal/framework/diagnostics" ) func terminalDiagnosticGroups(terminal producerAttemptTerminal, origin contracts.DiagnosticOrigin, chunk *source.Chunk) ([]contracts.DiagnosticGroup, error) { groups, err := promoteProducerDiagnostics(terminal.Diagnostics, origin, chunk) if err != nil { return nil, err } for _, record := range terminal.Validation.Diagnostics() { validatorOrigin := origin validatorOrigin.ValidatorKey = record.validatorName promoted, err := promoteProducerDiagnostics([]contracts.ProducerDiagnostic{record.diagnostic}, validatorOrigin, chunk) if err != nil { return nil, fmt.Errorf("validator %q diagnostic: %w", record.validatorName, err) } groups = append(groups, promoted...) } if terminal.Action == producerTerminalIncompleteAccepted { for _, record := range incompleteValidationDiagnostics(terminal.Validation) { validatorOrigin := origin validatorOrigin.ValidatorKey = record.validatorName promoted, err := promoteProducerDiagnostics([]contracts.ProducerDiagnostic{record.diagnostic}, validatorOrigin, chunk) if err != nil { return nil, fmt.Errorf("validator %q incomplete diagnostic: %w", record.validatorName, err) } groups = append(groups, promoted...) } } return groups, nil } func promoteProducerDiagnostics(diagnostics []contracts.ProducerDiagnostic, origin contracts.DiagnosticOrigin, chunk *source.Chunk) ([]contracts.DiagnosticGroup, error) { if err := contracts.ValidateProducerDiagnostics(diagnostics); err != nil { return nil, err } if len(diagnostics) == 0 { return nil, nil } groups := make([]contracts.DiagnosticGroup, len(diagnostics)) for index, diagnostic := range diagnostics { group := contracts.DiagnosticGroup{ Disposition: diagnostic.Disposition, Category: diagnostic.Category, ReasonCode: diagnostic.ReasonCode, Origin: origin, OccurrenceCount: diagnostic.OccurrenceCount, Samples: cloneDiagnosticSamples(diagnostic.Samples, chunk), OmittedSampleCount: diagnostic.OmittedSampleCount, } if err := group.Validate(); err != nil { return nil, err } groups[index] = group } return groups, nil } func cloneDiagnosticSamples(samples []contracts.DiagnosticSample, chunk *source.Chunk) []contracts.DiagnosticSample { if len(samples) == 0 { return nil } cloned := make([]contracts.DiagnosticSample, len(samples)) for index, sample := range samples { if chunk != nil { chunkIndex := chunk.Index sample.ChunkID = chunk.ID sample.ChunkIndex = &chunkIndex } else if sample.ChunkIndex != nil { chunkIndex := *sample.ChunkIndex sample.ChunkIndex = &chunkIndex } cloned[index] = sample } return cloned } func appendDiagnosticGroups(output *RunOutput, groups []contracts.DiagnosticGroup) { if output == nil || len(groups) == 0 { return } cloned := contracts.CloneDiagnosticCollection(contracts.DiagnosticCollection{Groups: groups}).Groups output.diagnosticGroups = append(output.diagnosticGroups, cloned...) seen := make(map[contracts.Warning]struct{}, len(output.Warnings)) for _, warning := range output.Warnings { seen[warning] = struct{}{} } for _, group := range cloned { for _, sample := range group.Samples { warning := contracts.Warning{Scope: sample.Scope, ReasonCode: group.ReasonCode, Message: sample.Message} if _, exists := seen[warning]; exists { continue } output.Warnings = append(output.Warnings, warning) seen[warning] = struct{}{} } } } func finalizeDiagnostics(output *RunOutput) error { if output == nil { return nil } aggregator := frameworkdiagnostics.Aggregator{} for _, group := range output.diagnosticGroups { if err := aggregator.Add(group); err != nil { return err } } output.Diagnostics = aggregator.Collection() return nil }