github.com/vanstinator/golangci-lint@v0.0.0-20240223191551-cc572f00d9d1/pkg/printers/checkstyle.go (about) 1 package printers 2 3 import ( 4 "encoding/xml" 5 "fmt" 6 "io" 7 "sort" 8 9 "github.com/go-xmlfmt/xmlfmt" 10 "golang.org/x/exp/maps" 11 12 "github.com/vanstinator/golangci-lint/pkg/result" 13 ) 14 15 const defaultCheckstyleSeverity = "error" 16 17 type checkstyleOutput struct { 18 XMLName xml.Name `xml:"checkstyle"` 19 Version string `xml:"version,attr"` 20 Files []*checkstyleFile `xml:"file"` 21 } 22 23 type checkstyleFile struct { 24 Name string `xml:"name,attr"` 25 Errors []*checkstyleError `xml:"error"` 26 } 27 28 type checkstyleError struct { 29 Column int `xml:"column,attr"` 30 Line int `xml:"line,attr"` 31 Message string `xml:"message,attr"` 32 Severity string `xml:"severity,attr"` 33 Source string `xml:"source,attr"` 34 } 35 36 type Checkstyle struct { 37 w io.Writer 38 } 39 40 func NewCheckstyle(w io.Writer) *Checkstyle { 41 return &Checkstyle{w: w} 42 } 43 44 func (p Checkstyle) Print(issues []result.Issue) error { 45 out := checkstyleOutput{ 46 Version: "5.0", 47 } 48 49 files := map[string]*checkstyleFile{} 50 51 for i := range issues { 52 issue := &issues[i] 53 file, ok := files[issue.FilePath()] 54 if !ok { 55 file = &checkstyleFile{ 56 Name: issue.FilePath(), 57 } 58 59 files[issue.FilePath()] = file 60 } 61 62 severity := defaultCheckstyleSeverity 63 if issue.Severity != "" { 64 severity = issue.Severity 65 } 66 67 newError := &checkstyleError{ 68 Column: issue.Column(), 69 Line: issue.Line(), 70 Message: issue.Text, 71 Source: issue.FromLinter, 72 Severity: severity, 73 } 74 75 file.Errors = append(file.Errors, newError) 76 } 77 78 out.Files = maps.Values(files) 79 80 sort.Slice(out.Files, func(i, j int) bool { 81 return out.Files[i].Name < out.Files[j].Name 82 }) 83 84 data, err := xml.Marshal(&out) 85 if err != nil { 86 return err 87 } 88 89 _, err = fmt.Fprintf(p.w, "%s%s\n", xml.Header, xmlfmt.FormatXML(string(data), "", " ")) 90 if err != nil { 91 return err 92 } 93 94 return nil 95 }