@@ -2,6 +2,7 @@ package main
22
33import (
44 "bytes"
5+ _ "embed"
56 "encoding/csv"
67 "flag"
78 "fmt"
@@ -29,6 +30,7 @@ ORDER BY created DESC`
2930
3031func main () {
3132 p := params {}
33+ flag .StringVar (& p .htmlOutput , "html-output" , "" , "Generate HTML report (use dash [-] for stdout)" )
3234 flag .StringVar (& p .csvOutput , "csv-output" , "" , "Convert XML to a CSV file (use dash [-] for stdout)" )
3335 flag .StringVar (& p .jiraUrl , "jira-url" , "https://issues.redhat.com/" , "Url of JIRA instance" )
3436 flag .StringVar (& p .junitReportsDir , "junit-reports-dir" , os .Getenv ("ARTIFACT_DIR" ), "Dir that contains jUnit reports XML files" )
@@ -88,10 +90,49 @@ func run(p params) error {
8890 return errors .Wrap (err , "could not find failed tests" )
8991 }
9092
91- err = j .createIssuesOrComments (failedTests )
93+ issues , err : = j .createIssuesOrComments (failedTests )
9294 if err != nil {
9395 return errors .Wrap (err , "could not create issues or comments" )
9496 }
97+ return j .createHtml (issues )
98+ }
99+
100+ //go:embed htmlOutput.tpl
101+ var htmlOutputTemplate string
102+
103+ func (j junit2jira ) createHtml (issues []* jira.Issue ) error {
104+ if j .htmlOutput == "" || len (issues ) == 0 {
105+ return nil
106+ }
107+ out := os .Stdout
108+ if j .htmlOutput != "-" {
109+ file , err := os .Create (j .htmlOutput )
110+ if err != nil {
111+ return fmt .Errorf ("could not create file %s: %w" , j .htmlOutput , err )
112+ }
113+ out = file
114+ defer file .Close ()
115+ }
116+ return j .renderHtml (issues , out )
117+ }
118+
119+ type htmlData struct {
120+ Issues []* jira.Issue
121+ JiraUrl string
122+ }
123+
124+ func (j junit2jira ) renderHtml (issues []* jira.Issue , out io.Writer ) error {
125+ t , err := template .New (j .htmlOutput ).Parse (htmlOutputTemplate )
126+ if err != nil {
127+ return fmt .Errorf ("could parse template: %w" , err )
128+ }
129+ err = t .Execute (out , htmlData {
130+ Issues : issues ,
131+ JiraUrl : j .jiraUrl ,
132+ })
133+ if err != nil {
134+ return fmt .Errorf ("could not render template %s: %w" , j .htmlOutput , err )
135+ }
95136 return nil
96137}
97138
@@ -111,31 +152,35 @@ func (j junit2jira) createCsv(testSuites []junit.Suite) error {
111152 return junit2csv (testSuites , j .params , out )
112153}
113154
114- func (j junit2jira ) createIssuesOrComments (failedTests []testCase ) error {
155+ func (j junit2jira ) createIssuesOrComments (failedTests []testCase ) ([] * jira. Issue , error ) {
115156 var result error
157+ issues := make ([]* jira.Issue , 0 , len (failedTests ))
116158 for _ , tc := range failedTests {
117- err := j .createIssueOrComment (tc )
159+ issue , err := j .createIssueOrComment (tc )
118160 if err != nil {
119161 result = multierror .Append (result , err )
120162 }
163+ if issue != nil {
164+ issues = append (issues , issue )
165+ }
121166 }
122- return result
167+ return issues , result
123168}
124169
125- func (j junit2jira ) createIssueOrComment (tc testCase ) error {
170+ func (j junit2jira ) createIssueOrComment (tc testCase ) ( * jira. Issue , error ) {
126171 summary , err := tc .summary ()
127172 if err != nil {
128- return fmt .Errorf ("could not get summary: %w" , err )
173+ return nil , fmt .Errorf ("could not get summary: %w" , err )
129174 }
130175 description , err := tc .description ()
131176 if err != nil {
132- return fmt .Errorf ("could not get description: %w" , err )
177+ return nil , fmt .Errorf ("could not get description: %w" , err )
133178 }
134179 log .Println ("Searching for " , summary )
135180 search , response , err := j .jiraClient .Issue .Search (fmt .Sprintf (jql , summary ), nil )
136181 if err != nil {
137182 logError (err , response )
138- return fmt .Errorf ("could not search: %w" , err )
183+ return nil , fmt .Errorf ("could not search: %w" , err )
139184 }
140185
141186 issue := findMatchingIssue (search , summary )
@@ -148,15 +193,15 @@ func (j junit2jira) createIssueOrComment(tc testCase) error {
148193 log .Println ("Dry run: will just print issue content" )
149194 log .Println (summary )
150195 log .Println (description )
151- return nil
196+ return nil , nil
152197 }
153198 create , response , err := j .jiraClient .Issue .Create (newIssue (summary , description ))
154199 if response != nil && err != nil {
155200 logError (err , response )
156- return fmt .Errorf ("could not create issue %s: %w" , summary , err )
201+ return nil , fmt .Errorf ("could not create issue %s: %w" , summary , err )
157202 }
158203 log .Printf ("Created new issues: %s:%s" , create .Key , summary )
159- return nil
204+ return create , nil
160205 }
161206
162207 comment := jira.Comment {
@@ -168,16 +213,16 @@ func (j junit2jira) createIssueOrComment(tc testCase) error {
168213 if j .dryRun {
169214 log .Println ("Dry run: will just print comment" )
170215 log .Println (description )
171- return nil
216+ return issue , nil
172217 }
173218
174219 addComment , response , err := j .jiraClient .Issue .AddComment (issue .ID , & comment )
175220 if response != nil && err != nil {
176221 logError (err , response )
177- return fmt .Errorf ("could not create issue %s: %w" , summary , err )
222+ return nil , fmt .Errorf ("could not create issue %s: %w" , summary , err )
178223 }
179224 log .Printf ("Created comment %s for %s:%s " , addComment .ID , issue .Key , summary )
180- return nil
225+ return issue , nil
181226}
182227
183228func newIssue (summary string , description string ) * jira.Issue {
@@ -391,6 +436,7 @@ type params struct {
391436 junitReportsDir string
392437 timestamp string
393438 csvOutput string
439+ htmlOutput string
394440}
395441
396442func NewTestCase (tc junit.Test , p params ) testCase {
0 commit comments