@@ -17,12 +17,18 @@ job_pattern = '-(.*).xml' if !job_pattern || job_pattern.empty?
17
17
failure_format = ENV [ 'BUILDKITE_PLUGIN_JUNIT_ANNOTATE_FAILURE_FORMAT' ]
18
18
failure_format = 'classname' if !failure_format || failure_format . empty?
19
19
20
- class Failure < Struct . new ( :name , :failed_test , :body , :job , :type , :message )
20
+ report_slowest = ENV [ 'BUILDKITE_PLUGIN_JUNIT_ANNOTATE_REPORT_SLOWEST' ] . to_i
21
+
22
+ class Failure < Struct . new ( :name , :unit_name , :body , :job , :type , :message )
23
+ end
24
+
25
+ class Timing < Struct . new ( :name , :unit_name , :time )
21
26
end
22
27
23
28
junit_report_files = Dir . glob ( File . join ( junits_dir , "**" , "*" ) )
24
29
testcases = 0
25
30
failures = [ ]
31
+ timings = [ ]
26
32
27
33
def text_content ( element )
28
34
# Handle mulptiple CDATA/text children elements
@@ -55,48 +61,65 @@ junit_report_files.sort.each do |file|
55
61
REXML ::XPath . each ( doc , '//testsuite/testcase' ) do |testcase |
56
62
testcases += 1
57
63
name = testcase . attributes [ 'name' ] . to_s
58
- failed_test = testcase . attributes [ failure_format ] . to_s
64
+ unit_name = testcase . attributes [ failure_format ] . to_s
65
+ time = testcase . attributes [ 'time' ] . to_f
66
+ timings << Timing . new ( name , unit_name , time )
59
67
testcase . elements . each ( "failure" ) do |failure |
60
- failures << Failure . new ( name , failed_test , text_content ( failure ) , job , :failure , message_content ( failure ) )
68
+ failures << Failure . new ( name , unit_name , text_content ( failure ) , job , :failure , message_content ( failure ) )
61
69
end
62
70
testcase . elements . each ( "error" ) do |error |
63
- failures << Failure . new ( name , failed_test , text_content ( error ) , job , :error , message_content ( error ) )
71
+ failures << Failure . new ( name , unit_name , text_content ( error ) , job , :error , message_content ( error ) )
64
72
end
65
73
end
66
74
end
67
75
68
- STDERR . puts "--- ❓ Checking failures "
76
+ STDERR . puts "--- ✍️ Preparing annotation "
69
77
STDERR . puts "#{ testcases } testcases found"
70
78
71
- if failures . empty?
72
- STDERR . puts "There were no failures/errors 🙌"
73
- exit 0
74
- else
79
+ if failures . any?
75
80
STDERR . puts "There #{ failures . length == 1 ? "is 1 failure/error" : "are #{ failures . length } failures/errors" } 😭"
76
- end
77
81
78
- STDERR . puts "--- ✍️ Preparing annotation"
82
+ failures_count = failures . select { |f | f . type == :failure } . length
83
+ errors_count = failures . select { |f | f . type == :error } . length
84
+ puts [
85
+ failures_count == 0 ? nil : ( failures_count == 1 ? "1 failure" : "#{ failures_count } failures" ) ,
86
+ errors_count === 0 ? nil : ( errors_count == 1 ? "1 error" : "#{ errors_count } errors" ) ,
87
+ ] . compact . join ( " and " ) + ":\n \n "
88
+
89
+ failures . each do |failure |
90
+ puts "<details>"
91
+ puts "<summary><code>#{ failure . name } in #{ failure . unit_name } </code></summary>\n \n "
92
+ if failure . message
93
+ puts "<p>#{ failure . message . chomp . strip } </p>\n \n "
94
+ end
95
+ if failure . body
96
+ puts "<pre><code>#{ CGI . escapeHTML ( failure . body . chomp . strip ) } </code></pre>\n \n "
97
+ end
98
+ if failure . job
99
+ puts "in <a href=\" ##{ failure . job } \" >Job ##{ failure . job } </a>"
100
+ end
101
+ puts "</details>"
102
+ puts "" unless failure == failures . last
103
+ end
79
104
80
- failures_count = failures . select { |f | f . type == :failure } . length
81
- errors_count = failures . select { |f | f . type == :error } . length
105
+ else
106
+ STDERR . puts "There were no failures/errors 🙌"
107
+ end
82
108
83
- puts [
84
- failures_count == 0 ? nil : ( failures_count == 1 ? "1 failure" : "#{ failures_count } failures" ) ,
85
- errors_count === 0 ? nil : ( errors_count == 1 ? "1 error" : "#{ errors_count } errors" ) ,
86
- ] . compact . join ( " and " ) + ":\n \n "
109
+ if report_slowest > 0
110
+ STDERR . puts "Reporting slowest tests ⏱"
87
111
88
- failures . each do |failure |
89
112
puts "<details>"
90
- puts "<summary><code>#{ failure . name } in #{ failure . failed_test } </code></summary>\n \n "
91
- if failure . message
92
- puts "<p>#{ failure . message . chomp . strip } </p>\n \n "
93
- end
94
- if failure . body
95
- puts "<pre><code>#{ CGI . escapeHTML ( failure . body . chomp . strip ) } </code></pre>\n \n "
96
- end
97
- if failure . job
98
- puts "in <a href=\" ##{ failure . job } \" >Job ##{ failure . job } </a>"
113
+ puts "<summary>#{ report_slowest } slowest tests</summary>\n \n "
114
+ puts "<table>"
115
+ puts "<thead><tr><th>Unit</th><th>Test</th><th>Time</th></tr></thead>"
116
+ puts "<tbody>"
117
+ timings . sort_by ( &:time ) . reverse . take ( report_slowest ) . each do |timing |
118
+ puts "<tr><td>#{ timing . unit_name } </td><td>#{ timing . name } </td><td>#{ timing . time } </td></tr>"
99
119
end
120
+ puts "</tbody>"
121
+ puts "</table>"
100
122
puts "</details>"
101
- puts "" unless failure == failures . last
102
123
end
124
+
125
+ exit 64 if failures . any? # special exit code to signal test failures
0 commit comments