index: add fold-out failure summary
[fateserver.git] / index.cgi
1 #! /usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use FATE;
7
8 opendir D, $fatedir or fail 'Server error: $fatedir not found';
9 my @slots = grep /^[^.]/, readdir D;
10 closedir D;
11
12 my @reps;
13 my $allpass = 0;
14 my $allfail = 0;
15
16 for my $slot (@slots) {
17     my $rep = load_summary $slot, 'latest' or next;
18     push @reps, $rep;
19     if ($$rep{npass} == 0) {
20         $allfail++;
21     } elsif ($$rep{npass} == $$rep{ntests}) {
22         $allpass++;
23     }
24
25     if (my $prev = load_summary $slot, 'previous') {
26         my $nfail = $$rep{ntests}  - $$rep{npass};
27         my $pfail = $$prev{ntests} - $$prev{npass};
28         $$rep{alert} = $$rep{ntests} && $nfail <=> $pfail;
29     }
30 }
31
32 $allpass = int 100 * $allpass / @reps;
33 $allfail = int 100 * $allfail / @reps;
34 my $warn = int 100 - $allpass - $allfail;
35
36 print "Content-type: text/html\r\n\r\n";
37
38 doctype;
39 start 'html', xmlns => "http://www.w3.org/1999/xhtml";
40 start 'head';
41 tag 'meta', 'http-equiv' => "Content-Type",
42             'content'    => "text/html; charset=utf-8";
43 tag 'link', rel  => 'stylesheet',
44             type => 'text/css',
45             href => 'fate.css';
46 print "<title>FATE</title>\n";
47 print <<EOF;
48 <script type="text/javascript">
49   function toggle(id, arr) {
50       var e = document.getElementById(id);
51       if (e.style.display == 'table-row') {
52           e.style.display = 'none';
53           arr.textContent = '\\u25ba'
54       } else {
55           e.style.display = 'table-row';
56           arr.textContent = '\\u25bc'
57       }
58   }
59 </script>
60 EOF
61 end 'head';
62
63 start 'body';
64 h1 'FATE';
65
66 start 'table', id => 'index', class => 'replist';
67 start 'thead';
68 start 'tr';
69 start 'td', colspan => 7, id => 'failometer';
70 span '&nbsp;', class => 'pass', style => "width: ${allpass}%";
71 span '&nbsp;', class => 'warn', style => "width: ${warn}%";
72 span '&nbsp;', class => 'fail', style => "width: ${allfail}%";
73 end 'td';
74 end 'tr';
75 start 'tr';
76 th 'Time';
77 th 'Arch';
78 th 'OS';
79 th 'Compiler';
80 th 'Rev';
81 th 'Result', colspan => 2;
82 end 'tr';
83 end 'thead';
84 start 'tbody';
85 for my $rep (sort { $$a{slot} cmp $$b{slot} } @reps) {
86     my $ntest = $$rep{ntests};
87     my $npass = $$rep{npass};
88     my $time = parse_date $$rep{date};
89     my $age  = time - $time;
90     my $agestr = agestr $age, $time;
91     my $ageclass = '';
92     my $rtext;
93     my $rclass;
94     my $alert = ('rejoice', '', 'alert')[$$rep{alert} + 1];
95     (my $slotid = $$rep{slot}) =~ s/[^a-z0-9_-]/_/ig;
96
97     if ($age < $recent_age) {
98         $ageclass = 'recent';
99     } elsif ($age > $ancient_age) {
100         $ageclass = 'ancient';
101     }
102
103     start 'tr', class => "$ageclass $alert alt hilight";
104     start 'td';
105     anchor $agestr, href => "history.cgi?slot=$$rep{slot}";
106     end 'td';
107     td $$rep{subarch} || $$rep{arch};
108     td $$rep{os};
109     td $$rep{cc};
110     td $$rep{rev};
111     if ($npass) {
112         $rtext  = "$npass / $ntest";
113         $rclass = $npass==$ntest? 'pass' : $npass? 'warn' : 'fail';
114     } else {
115         $rtext  = $$rep{errstr};
116         $rclass = 'fail'
117     }
118     start 'td', class => $rclass;
119     anchor $rtext, href => "report.cgi?slot=$$rep{slot}&amp;time=$$rep{date}";
120     end 'td';
121     start 'td', class => $rclass;
122     if ($npass < $ntest) {
123         span '&#9658;', class => 'toggle', onclick => "toggle('$slotid', this)";
124     }
125     end 'td';
126     end 'tr';
127     print "\n";
128     if ($npass < $ntest) {
129         my $report = load_report $$rep{slot}, $$rep{date};
130         my @fail = grep $$_{status} ne '0', @{$$report{recs}};
131         my $nfail = @fail;
132         start 'tr', id => $slotid, class => 'slotfail';
133         start 'td', colspan => 7;
134         start 'table', class => 'minirep';
135         start 'thead';
136         start 'tr';
137         th "$nfail failed tests";
138         th 'Status', class => 'errcode';
139         end 'tr';
140         end 'thead';
141         start 'tbody';
142         for (sort { $$a{name} cmp $$b{name} } @fail) {
143             start 'tr', class => 'alt hilight';
144             td $$_{name};
145             td $$_{status}, class => 'errcode';
146             end 'tr';
147         }
148         end 'tbody';
149         end 'table';
150         end 'td';
151         end 'tr';
152         print "\n";
153         trowa { style => 'display: none' }, '';
154     }
155 }
156 end 'tbody';
157 end 'table';
158 end 'body';
159 end 'html';