Propagate lint report write errors

This commit is contained in:
Snider 2026-04-16 06:34:41 +01:00
parent 49bf3c36f4
commit be103daed9
3 changed files with 46 additions and 15 deletions

View file

@ -323,7 +323,9 @@ func newCheckCommand() *cli.Command {
}
return lintpkg.WriteReportSARIF(command.OutOrStdout(), report)
default:
lintpkg.WriteText(command.OutOrStdout(), findings)
if err := lintpkg.WriteText(command.OutOrStdout(), findings); err != nil {
return err
}
if format == "text" && len(findings) > 0 {
writeCatalogSummary(command.OutOrStdout(), findings)
}
@ -405,11 +407,9 @@ func writeReport(writer io.Writer, output string, report lintpkg.Report) error {
case "json":
return lintpkg.WriteReportJSON(writer, report)
case "text":
lintpkg.WriteReportText(writer, report)
return nil
return lintpkg.WriteReportText(writer, report)
case "github":
lintpkg.WriteReportGitHub(writer, report)
return nil
return lintpkg.WriteReportGitHub(writer, report)
case "sarif":
return lintpkg.WriteReportSARIF(writer, report)
default:

View file

@ -75,7 +75,7 @@ func WriteJSONL(w io.Writer, findings []Finding) error {
// WriteText writes findings in a human-readable format.
//
// lint.WriteText(os.Stdout, findings)
func WriteText(w io.Writer, findings []Finding) {
func WriteText(w io.Writer, findings []Finding) error {
for _, finding := range findings {
message := finding.Message
if message == "" {
@ -85,8 +85,11 @@ func WriteText(w io.Writer, findings []Finding) {
if code == "" {
code = finding.RuleID
}
fmt.Fprintf(w, "%s:%d [%s] %s (%s)\n", finding.File, finding.Line, finding.Severity, message, code)
if _, err := fmt.Fprintf(w, "%s:%d [%s] %s (%s)\n", finding.File, finding.Line, finding.Severity, message, code); err != nil {
return err
}
}
return nil
}
// WriteReportJSON writes the RFC report document as pretty-printed JSON.
@ -101,15 +104,18 @@ func WriteReportJSON(w io.Writer, report Report) error {
// WriteReportText writes report findings followed by a short summary.
//
// lint.WriteReportText(os.Stdout, report)
func WriteReportText(w io.Writer, report Report) {
WriteText(w, report.Findings)
fmt.Fprintf(w, "\n%d finding(s): %d error(s), %d warning(s), %d info\n", report.Summary.Total, report.Summary.Errors, report.Summary.Warnings, report.Summary.Info)
func WriteReportText(w io.Writer, report Report) error {
if err := WriteText(w, report.Findings); err != nil {
return err
}
_, err := fmt.Fprintf(w, "\n%d finding(s): %d error(s), %d warning(s), %d info\n", report.Summary.Total, report.Summary.Errors, report.Summary.Warnings, report.Summary.Info)
return err
}
// WriteReportGitHub writes GitHub Actions annotation lines.
//
// lint.WriteReportGitHub(os.Stdout, report)
func WriteReportGitHub(w io.Writer, report Report) {
func WriteReportGitHub(w io.Writer, report Report) error {
for _, finding := range report.Findings {
level := githubAnnotationLevel(finding.Severity)
@ -132,8 +138,11 @@ func WriteReportGitHub(w io.Writer, report Report) {
if code == "" {
code = finding.RuleID
}
fmt.Fprintf(w, "::%s%s::[%s] %s (%s)\n", level, location, finding.Tool, message, code)
if _, err := fmt.Fprintf(w, "::%s%s::[%s] %s (%s)\n", level, location, finding.Tool, message, code); err != nil {
return err
}
}
return nil
}
// WriteReportSARIF writes a minimal SARIF document for code scanning tools.

View file

@ -3,6 +3,7 @@ package lint
import (
"bytes"
"encoding/json"
"errors"
"strings"
"testing"
@ -118,7 +119,8 @@ func TestWriteJSONL_Good_Empty(t *testing.T) {
func TestWriteText_Good(t *testing.T) {
findings := sampleFindings()
var buf bytes.Buffer
WriteText(&buf, findings)
err := WriteText(&buf, findings)
require.NoError(t, err)
output := buf.String()
assert.Contains(t, output, "store/query.go:42")
@ -131,14 +133,15 @@ func TestWriteText_Good(t *testing.T) {
func TestWriteText_Good_Empty(t *testing.T) {
var buf bytes.Buffer
WriteText(&buf, nil)
err := WriteText(&buf, nil)
require.NoError(t, err)
assert.Empty(t, buf.String())
}
func TestWriteReportGitHub_Good_MapsInfoToNotice(t *testing.T) {
var buf bytes.Buffer
WriteReportGitHub(&buf, Report{
err := WriteReportGitHub(&buf, Report{
Findings: []Finding{{
Tool: "demo",
File: "example.go",
@ -149,10 +152,23 @@ func TestWriteReportGitHub_Good_MapsInfoToNotice(t *testing.T) {
Message: "explanation",
}},
})
require.NoError(t, err)
assert.Contains(t, buf.String(), "::notice file=example.go,line=7,col=3::[demo] explanation (demo-rule)")
}
func TestWriteText_Bad_PropagatesWriterErrors(t *testing.T) {
err := WriteText(failingWriter{}, sampleFindings())
require.Error(t, err)
}
func TestWriteReportGitHub_Bad_PropagatesWriterErrors(t *testing.T) {
err := WriteReportGitHub(failingWriter{}, Report{
Findings: sampleFindings(),
})
require.Error(t, err)
}
func TestWriteReportSARIF_Good_MapsInfoToNote(t *testing.T) {
var buf bytes.Buffer
@ -176,3 +192,9 @@ func TestWriteReportSARIF_Good_MapsInfoToNote(t *testing.T) {
results := runs[0].(map[string]any)["results"].([]any)
assert.Equal(t, "note", results[0].(map[string]any)["level"])
}
type failingWriter struct{}
func (failingWriter) Write([]byte) (int, error) {
return 0, errors.New("write failed")
}