From 08b86b1e22b11b8dc89c7875e4004a19e5e0c6ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=20Kl=C3=A4rner?= Date: Thu, 15 Aug 2024 17:32:55 +0200 Subject: [PATCH] feat(output)!: consolidate errors in the human output format (closes #359) This changes the human output format to collect multiple identical error messages on consecutive lines into one error message that list both the starting and ending line. This is still missing a properly written testcase, I so far only tested locally. --- pkg/error/error.go | 51 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/pkg/error/error.go b/pkg/error/error.go index 294edf0f..0d97a972 100644 --- a/pkg/error/error.go +++ b/pkg/error/error.go @@ -10,8 +10,9 @@ import ( // ValidationError represents one validation error type ValidationError struct { - LineNumber int - Message error + LineNumber int + Message error + ConsecuitiveCount int } // ValidationErrors represents which errors occurred in a file @@ -31,6 +32,44 @@ func GetErrorCount(errors []ValidationErrors) int { return errorCount } +func ConsolidateErrors(errors []ValidationError, config config.Config) []ValidationError { + var lineLessErrors []ValidationError + var errorsWithLines []ValidationError + + // filter the errors, so we do not need to care about LineNumber == -1 in the loop below + for _, singleError := range errors { + if singleError.LineNumber == -1 { + lineLessErrors = append(lineLessErrors, singleError) + } else { + errorsWithLines = append(errorsWithLines, singleError) + } + } + + config.Logger.Debug("sorted errors: %d with line number -1, %d with a line number", len(lineLessErrors), len(errorsWithLines)) + + var consolidatedErrors []ValidationError + + // scan through the errors + for i := 0; i < len(errorsWithLines); i++ { + thisError := errorsWithLines[i] + config.Logger.Debug("investigating error %d(%s)", i, thisError.Message) + // scan through the errors after the current one + for j, nextError := range errorsWithLines[i+1:] { + config.Logger.Debug("comparing against error %d(%s)", j, nextError.Message) + if nextError.Message.Error() == thisError.Message.Error() { + thisError.ConsecuitiveCount++ // keep track of how many consecutive lines we've seen + i = i + j + 1 // make sure the outer loop jumps over the consecutive errors we just found + } else { + break // if they are different errors we can stop comparing messages + } + } + + consolidatedErrors = append(consolidatedErrors, thisError) + } + + return append(lineLessErrors, consolidatedErrors...) +} + // PrintErrors prints the errors to the console func PrintErrors(errors []ValidationErrors, config config.Config) { for _, fileErrors := range errors { @@ -54,9 +93,13 @@ func PrintErrors(errors []ValidationErrors, config config.Config) { } else { // default: A human readable text format. config.Logger.Warning(fmt.Sprintf("%s:", relativeFilePath)) - for _, singleError := range fileErrors.Errors { + for _, singleError := range ConsolidateErrors(fileErrors.Errors, config) { if singleError.LineNumber != -1 { - config.Logger.Error(fmt.Sprintf("\t%d: %s", singleError.LineNumber, singleError.Message)) + if singleError.ConsecuitiveCount != 0 { + config.Logger.Error(fmt.Sprintf("\t%d-%d: %s", singleError.LineNumber, singleError.LineNumber+singleError.ConsecuitiveCount, singleError.Message)) + } else { + config.Logger.Error(fmt.Sprintf("\t%d: %s", singleError.LineNumber, singleError.Message)) + } } else { config.Logger.Error(fmt.Sprintf("\t%s", singleError.Message)) }