From 89d9ca8a41a42d0ea7a1f85b53891e457256010a Mon Sep 17 00:00:00 2001 From: or-shachar Date: Thu, 5 Jan 2023 13:59:26 +0200 Subject: [PATCH] Support glob expressions for xml reports files --- README.md | 25 ++++++++++++++--- main.go | 81 ++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 84 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 5b81475..1b2fe7c 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,12 @@ Here is an example that uses trap to always created the test report: go install github.com/jstemmer/go-junit-report@latest go install github.com/alexec/junit2html@latest -trap 'go-junit-report < test.out > junit.xml && junit2html < junit.xml > test-report.html' EXIT +trap 'go-junit-report < test.out > junit.xml && junit2html --xmlReports junit.xml > test-report.html' EXIT go test -v -cover ./... 2>&1 > test.out ``` -💡 Don't use pipes (i.e. `|`) in shell, pipes swallow exit codes. Use `<` and `>` which is POSIX compliant. +💡 Don't use pipes (i.e. `|`) in shell, pipes swallow exit codes. Use `>` which is POSIX compliant. ## Test @@ -33,5 +33,24 @@ How to test this locally: ```bash go test -v -cover ./... 2>&1 > test.out go-junit-report < test.out > junit.xml -go run . < junit.xml > test-report.html +go run . --xmlReports junit.xml > test-report.html ``` + +## Using glob patterns: + +Sometimes there is a need to parse multiple xml files and generate single html report. +`junit2html` supports that by using standard [`glob` expression](https://pkg.go.dev/path/filepath#Glob). + +```bash +# Explicit single file +junit2html --xmlReports "reports/junit.xml" > report.html + +# Multiple files +junit2html --xmlReports "reports/junit.xml,reports/coverage.xml" > report.html + +# Single glob pattern +junit2html --xmlReports "reports/*.xml" > report.html + +# Multiple glob patterns +junit2html --xmlReports "reports/junit*.xml,reports/coverage*.xml" > report.html +``` diff --git a/main.go b/main.go index 31b7f7d..2f9cb75 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,14 @@ package main import ( + "bytes" _ "embed" "encoding/xml" + "flag" "fmt" + "io/ioutil" "os" + "path/filepath" "strconv" "strings" "time" @@ -40,12 +44,44 @@ func printTest(s formatter.JUnitTestSuite, c formatter.JUnitTestCase) { fmt.Printf("\n") } -func main() { - suites := &formatter.JUnitTestSuites{} +// arguments +var ( + xmlReports *string +) - err := xml.NewDecoder(os.Stdin).Decode(suites) - if err != nil { - panic(err) +func init() { + xmlReports = flag.String("xmlReports", "", "Comma delimited glob expressions describing the files to scan") +} + +func main() { + flag.Parse() + if (*xmlReports) == "" { + panic("xmlReports cannot be empty") + } + patterns := strings.Split((*xmlReports), ",") + files := []string{} + for _, p := range patterns { + fmt.Fprintf(os.Stderr, "Given xmlReports '%s'\n", p) + matches, err := filepath.Glob(p) + if err != nil { + panic(err) + } + files = append(files, matches...) + } + allSuites := make([]formatter.JUnitTestSuites, 0, len(files)) + for _, f := range files { + fmt.Fprintf(os.Stderr, "Parsing file '%s'\n", f) + res, err := ioutil.ReadFile(f) + if err != nil { + panic(err) + } + testResult := bytes.NewReader(res) + suites := &formatter.JUnitTestSuites{} + err = xml.NewDecoder(testResult).Decode(suites) + if err != nil { + panic(err) + } + allSuites = append(allSuites, *suites) } fmt.Println("") @@ -56,27 +92,34 @@ func main() { fmt.Println("") fmt.Println("") fmt.Println("") + failures, total := 0, 0 - for _, s := range suites.Suites { - failures += s.Failures - total += len(s.TestCases) + for _, suites := range allSuites { + for _, s := range suites.Suites { + failures += s.Failures + total += len(s.TestCases) + } } fmt.Printf("

%d of %d tests failed

\n", failures, total) - for _, s := range suites.Suites { - if s.Failures > 0 { - printSuiteHeader(s) - for _, c := range s.TestCases { - if f := c.Failure; f != nil { - printTest(s, c) + for _, suites := range allSuites { + for _, s := range suites.Suites { + if s.Failures > 0 { + printSuiteHeader(s) + for _, c := range s.TestCases { + if f := c.Failure; f != nil { + printTest(s, c) + } } } } } - for _, s := range suites.Suites { - printSuiteHeader(s) - for _, c := range s.TestCases { - if c.Failure == nil { - printTest(s, c) + for _, suites := range allSuites { + for _, s := range suites.Suites { + printSuiteHeader(s) + for _, c := range s.TestCases { + if c.Failure == nil { + printTest(s, c) + } } } }