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  }