Skip to content

Commit f58b7dc

Browse files
committed
Support glob expressions for xml reports files
1 parent b7f6c23 commit f58b7dc

File tree

3 files changed

+85
-23
lines changed

3 files changed

+85
-23
lines changed

README.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ Here is an example that uses trap to always created the test report:
1919
go install github.com/jstemmer/go-junit-report@latest
2020
go install github.com/alexec/junit2html@latest
2121

22-
trap 'go-junit-report < test.out > junit.xml && junit2html < junit.xml > test-report.html' EXIT
22+
trap 'go-junit-report < test.out > junit.xml && junit2html --xmlReports junit.xml > test-report.html' EXIT
2323

2424
go test -v -cover ./... 2>&1 > test.out
2525
```
2626

27-
💡 Don't use pipes (i.e. `|`) in shell, pipes swallow exit codes. Use `<` and `>` which is POSIX compliant.
27+
💡 Don't use pipes (i.e. `|`) in shell, pipes swallow exit codes. Use `>` which is POSIX compliant.
2828

2929
## Test
3030

@@ -33,5 +33,24 @@ How to test this locally:
3333
```bash
3434
go test -v -cover ./... 2>&1 > test.out
3535
go-junit-report < test.out > junit.xml
36-
go run . < junit.xml > test-report.html
36+
go run . --xmlReports junit.xml > test-report.html
3737
```
38+
39+
## Using glob patterns:
40+
41+
Sometimes there is a need to parse multiple xml files and generate single html report.
42+
`junit2html` supports that by using standard [`glob` expression](https://pkg.go.dev/path/filepath#Glob).
43+
44+
```bash
45+
# Explicit single file
46+
junit2html --xmlReports "reports/junit.xml" > report.html
47+
48+
# Multiple files
49+
junit2html --xmlReports "reports/junit.xml,reports/coverage.xml" > report.html
50+
51+
# Single glob pattern
52+
junit2html --xmlReports "reports/*.xml" > report.html
53+
54+
# Multiple glob patterns
55+
junit2html --xmlReports "reports/junit*.xml,reports/coverage*.xml" > report.html
56+
```

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module github.com/alexec/junit2html
1+
module github.com/or-shachar/junit2html
22

33
go 1.18
44

main.go

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package main
22

33
import (
4+
"bytes"
45
_ "embed"
56
"encoding/xml"
7+
"flag"
68
"fmt"
9+
"io/ioutil"
710
"os"
11+
"path/filepath"
812
"strconv"
913
"strings"
1014
"time"
@@ -40,12 +44,44 @@ func printTest(s formatter.JUnitTestSuite, c formatter.JUnitTestCase) {
4044
fmt.Printf("</div>\n")
4145
}
4246

43-
func main() {
44-
suites := &formatter.JUnitTestSuites{}
47+
// arguments
48+
var (
49+
xmlReports *string
50+
)
4551

46-
err := xml.NewDecoder(os.Stdin).Decode(suites)
47-
if err != nil {
48-
panic(err)
52+
func init() {
53+
xmlReports = flag.String("xmlReports", "", "Comma delimited glob expressions describing the files to scan")
54+
}
55+
56+
func main() {
57+
flag.Parse()
58+
if (*xmlReports) == "" {
59+
panic("xmlReports cannot be empty")
60+
}
61+
patterns := strings.Split((*xmlReports), ",")
62+
files := []string{}
63+
for _, p := range patterns {
64+
fmt.Fprintf(os.Stderr, "Given xmlReports '%s'\n", p)
65+
matches, err := filepath.Glob(p)
66+
if err != nil {
67+
panic(err)
68+
}
69+
files = append(files, matches...)
70+
}
71+
allSuites := make([]formatter.JUnitTestSuites, 0, len(files))
72+
for _, f := range files {
73+
fmt.Fprintf(os.Stderr, "Parsing file '%s'\n", f)
74+
res, err := ioutil.ReadFile(f)
75+
if err != nil {
76+
panic(err)
77+
}
78+
testResult := bytes.NewReader(res)
79+
suites := &formatter.JUnitTestSuites{}
80+
err = xml.NewDecoder(testResult).Decode(suites)
81+
if err != nil {
82+
panic(err)
83+
}
84+
allSuites = append(allSuites, *suites)
4985
}
5086

5187
fmt.Println("<html>")
@@ -56,27 +92,34 @@ func main() {
5692
fmt.Println("</style>")
5793
fmt.Println("</head>")
5894
fmt.Println("<body>")
95+
5996
failures, total := 0, 0
60-
for _, s := range suites.Suites {
61-
failures += s.Failures
62-
total += len(s.TestCases)
97+
for _, suites := range allSuites {
98+
for _, s := range suites.Suites {
99+
failures += s.Failures
100+
total += len(s.TestCases)
101+
}
63102
}
64103
fmt.Printf("<p>%d of %d tests failed</p>\n", failures, total)
65-
for _, s := range suites.Suites {
66-
if s.Failures > 0 {
67-
printSuiteHeader(s)
68-
for _, c := range s.TestCases {
69-
if f := c.Failure; f != nil {
70-
printTest(s, c)
104+
for _, suites := range allSuites {
105+
for _, s := range suites.Suites {
106+
if s.Failures > 0 {
107+
printSuiteHeader(s)
108+
for _, c := range s.TestCases {
109+
if f := c.Failure; f != nil {
110+
printTest(s, c)
111+
}
71112
}
72113
}
73114
}
74115
}
75-
for _, s := range suites.Suites {
76-
printSuiteHeader(s)
77-
for _, c := range s.TestCases {
78-
if c.Failure == nil {
79-
printTest(s, c)
116+
for _, suites := range allSuites {
117+
for _, s := range suites.Suites {
118+
printSuiteHeader(s)
119+
for _, c := range s.TestCases {
120+
if c.Failure == nil {
121+
printTest(s, c)
122+
}
80123
}
81124
}
82125
}

0 commit comments

Comments
 (0)