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