github.com/vanstinator/golangci-lint@v0.0.0-20240223191551-cc572f00d9d1/pkg/printers/junitxml.go (about) 1 package printers 2 3 import ( 4 "encoding/xml" 5 "fmt" 6 "io" 7 "sort" 8 "strings" 9 10 "golang.org/x/exp/maps" 11 12 "github.com/vanstinator/golangci-lint/pkg/result" 13 ) 14 15 type testSuitesXML struct { 16 XMLName xml.Name `xml:"testsuites"` 17 TestSuites []testSuiteXML 18 } 19 20 type testSuiteXML struct { 21 XMLName xml.Name `xml:"testsuite"` 22 Suite string `xml:"name,attr"` 23 Tests int `xml:"tests,attr"` 24 Errors int `xml:"errors,attr"` 25 Failures int `xml:"failures,attr"` 26 TestCases []testCaseXML `xml:"testcase"` 27 } 28 29 type testCaseXML struct { 30 Name string `xml:"name,attr"` 31 ClassName string `xml:"classname,attr"` 32 Failure failureXML `xml:"failure"` 33 } 34 35 type failureXML struct { 36 Message string `xml:"message,attr"` 37 Type string `xml:"type,attr"` 38 Content string `xml:",cdata"` 39 } 40 41 type JunitXML struct { 42 w io.Writer 43 } 44 45 func NewJunitXML(w io.Writer) *JunitXML { 46 return &JunitXML{w: w} 47 } 48 49 func (p JunitXML) Print(issues []result.Issue) error { 50 suites := make(map[string]testSuiteXML) // use a map to group by file 51 52 for ind := range issues { 53 i := &issues[ind] 54 suiteName := i.FilePath() 55 testSuite := suites[suiteName] 56 testSuite.Suite = i.FilePath() 57 testSuite.Tests++ 58 testSuite.Failures++ 59 60 tc := testCaseXML{ 61 Name: i.FromLinter, 62 ClassName: i.Pos.String(), 63 Failure: failureXML{ 64 Type: i.Severity, 65 Message: i.Pos.String() + ": " + i.Text, 66 Content: fmt.Sprintf("%s: %s\nCategory: %s\nFile: %s\nLine: %d\nDetails: %s", 67 i.Severity, i.Text, i.FromLinter, i.Pos.Filename, i.Pos.Line, strings.Join(i.SourceLines, "\n")), 68 }, 69 } 70 71 testSuite.TestCases = append(testSuite.TestCases, tc) 72 suites[suiteName] = testSuite 73 } 74 75 var res testSuitesXML 76 res.TestSuites = maps.Values(suites) 77 78 sort.Slice(res.TestSuites, func(i, j int) bool { 79 return res.TestSuites[i].Suite < res.TestSuites[j].Suite 80 }) 81 82 enc := xml.NewEncoder(p.w) 83 enc.Indent("", " ") 84 if err := enc.Encode(res); err != nil { 85 return err 86 } 87 return nil 88 }