Index: trunk/tools/bugzilla/bugzilla-4.0/extensions/WeeklyReport/Config.pm |
— | — | @@ -0,0 +1,27 @@ |
| 2 | +# -*- Mode: perl; indent-tabs-mode: nil -*- |
| 3 | +# |
| 4 | +# The contents of this file are subject to the Mozilla Public |
| 5 | +# License Version 1.1 (the "License"); you may not use this file |
| 6 | +# except in compliance with the License. You may obtain a copy of |
| 7 | +# the License at http://www.mozilla.org/MPL/ |
| 8 | +# |
| 9 | +# Software distributed under the License is distributed on an "AS |
| 10 | +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
| 11 | +# implied. See the License for the specific language governing |
| 12 | +# rights and limitations under the License. |
| 13 | +# |
| 14 | +# See: https://bugzilla.wikimedia.org/show_bug.cgi?id=25637#c3 |
| 15 | +# Original Source code from http://websvn.kde.org/trunk/www/sites/bugs/ |
| 16 | + |
| 17 | +package Bugzilla::Extension::WeeklyReport; |
| 18 | +use strict; |
| 19 | + |
| 20 | +use constant NAME => 'WeeklyReport'; |
| 21 | + |
| 22 | +use constant REQUIRED_MODULES => [ |
| 23 | +]; |
| 24 | + |
| 25 | +use constant OPTIONAL_MODULES => [ |
| 26 | +]; |
| 27 | + |
| 28 | +__PACKAGE__->NAME; |
Index: trunk/tools/bugzilla/bugzilla-4.0/extensions/WeeklyReport/Extension.pm |
— | — | @@ -0,0 +1,30 @@ |
| 2 | +# -*- Mode: perl; indent-tabs-mode: nil -*- |
| 3 | +# |
| 4 | +# The contents of this file are subject to the Mozilla Public |
| 5 | +# License Version 1.1 (the "License"); you may not use this file |
| 6 | +# except in compliance with the License. You may obtain a copy of |
| 7 | +# the License at http://www.mozilla.org/MPL/ |
| 8 | +# |
| 9 | +# Software distributed under the License is distributed on an "AS |
| 10 | +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
| 11 | +# implied. See the License for the specific language governing |
| 12 | +# rights and limitations under the License. |
| 13 | +# |
| 14 | +# See: https://bugzilla.wikimedia.org/show_bug.cgi?id=25637#c3 |
| 15 | +# Original Source code from http://websvn.kde.org/trunk/www/sites/bugs/ |
| 16 | + |
| 17 | + |
| 18 | +package Bugzilla::Extension::WeeklyReport; |
| 19 | +use strict; |
| 20 | +use base qw(Bugzilla::Extension); |
| 21 | + |
| 22 | +our $VERSION = '0.01'; |
| 23 | + |
| 24 | +# See the documentation of Bugzilla::Hook ("perldoc Bugzilla::Hook" |
| 25 | +# in the bugzilla directory) for a list of all available hooks. |
| 26 | +sub install_update_db { |
| 27 | + my ($self, $args) = @_; |
| 28 | + |
| 29 | +} |
| 30 | + |
| 31 | +__PACKAGE__->NAME; |
Index: trunk/tools/bugzilla/bugzilla-4.0/extensions/WeeklyReport/weekly-bug-summary.cgi |
— | — | @@ -0,0 +1,386 @@ |
| 2 | +#!/usr/bin/perl -wT |
| 3 | + |
| 4 | +# its stolen from somewhere but was mostly re-written by Dirk Mueller <mueller@kde.org>, 08/2006 |
| 5 | +# templatized by Matt Rogers <mattr@kde.org>, 12/2007 |
| 6 | +use strict; |
| 7 | +use lib "."; |
| 8 | + |
| 9 | +use Bugzilla; |
| 10 | +use Bugzilla::Constants; |
| 11 | +use Bugzilla::Util; |
| 12 | +use Bugzilla::Error; |
| 13 | +use Bugzilla::Field; |
| 14 | + |
| 15 | +sub total_bugs_in_bugzilla() |
| 16 | +{ |
| 17 | + my $dbh = Bugzilla->dbh; |
| 18 | + |
| 19 | + # figure out total bugs |
| 20 | + my (@totalbugs) = $dbh->selectrow_array( |
| 21 | + "SELECT count(bugs.bug_id) FROM bugs WHERE bugs.bug_severity != 'enhancement' AND |
| 22 | + ( bugs.bug_status = 'NEW' or bugs.bug_status = 'ASSIGNED' or |
| 23 | + bugs.bug_status = 'REOPENED' or bugs.bug_status = 'UNCONFIRMED')" |
| 24 | + ); |
| 25 | + |
| 26 | + # figure out total number of wishes |
| 27 | + my (@totalwishes) = $dbh->selectrow_array ( |
| 28 | + "SELECT count(bugs.bug_id) FROM bugs WHERE bugs.bug_severity = 'enhancement' AND |
| 29 | + ( bugs.bug_status = 'NEW' or bugs.bug_status = 'ASSIGNED' or |
| 30 | + bugs.bug_status = 'REOPENED' or bugs.bug_status = 'UNCONFIRMED')" |
| 31 | + ); |
| 32 | + |
| 33 | + return ($totalbugs[0], $totalwishes[0]); |
| 34 | +} |
| 35 | + |
| 36 | +sub bugs_opened() |
| 37 | +{ |
| 38 | + my($product, $days) = @_; |
| 39 | + |
| 40 | + my $sqlproduct = ""; |
| 41 | + $sqlproduct = "AND bugs.product_id=$product" |
| 42 | + if(defined $product and $product ne "%"); |
| 43 | + |
| 44 | + my ($count) = Bugzilla->dbh->selectrow_array( |
| 45 | + "SELECT count(bugs.bug_id) FROM bugs |
| 46 | + WHERE creation_ts >= from_days(to_days(NOW())-?) |
| 47 | + $sqlproduct AND bugs.bug_severity != 'enhancement'", undef, ($days) |
| 48 | + ); |
| 49 | + |
| 50 | + return $count; |
| 51 | +} |
| 52 | + |
| 53 | +sub wishes_opened() |
| 54 | +{ |
| 55 | + my($product, $days) = @_; |
| 56 | + |
| 57 | + my $sqlproduct = ""; |
| 58 | + $sqlproduct = "AND bugs.product_id=" . Bugzilla->dbh->quote($product) |
| 59 | + if(defined $product and $product ne "%"); |
| 60 | + |
| 61 | + my ($count) = Bugzilla->dbh->selectrow_array( |
| 62 | + "SELECT count(bugs.bug_id) FROM bugs |
| 63 | + WHERE creation_ts >= from_days(to_days(NOW())-?) |
| 64 | + $sqlproduct AND bugs.bug_severity = 'enhancement'", undef, ($days) |
| 65 | + ); |
| 66 | + |
| 67 | + return $count; |
| 68 | +} |
| 69 | + |
| 70 | +sub bugs_closed() |
| 71 | +{ |
| 72 | + my($product, $days) = @_; |
| 73 | + my $query = ""; |
| 74 | + my $sqlproduct = ""; |
| 75 | + $sqlproduct = "AND bugs.product_id=" . Bugzilla->dbh->quote($product) |
| 76 | + if(defined $product and $product ne "%"); |
| 77 | + |
| 78 | + my ($count) = Bugzilla->dbh->selectrow_array(" |
| 79 | +select |
| 80 | + count(distinct bugs.bug_id) |
| 81 | +from |
| 82 | + bugs, bugs_activity |
| 83 | +where |
| 84 | + bugs.bug_severity != 'enhancement' AND |
| 85 | + (bugs_activity.added='RESOLVED' or bugs_activity.added='CLOSED' or |
| 86 | + bugs_activity.added='NEEDSINFO') |
| 87 | +and |
| 88 | + bugs_activity.bug_when >= FROM_DAYS(TO_DAYS(NOW())-?) |
| 89 | +and |
| 90 | + bugs.bug_id = bugs_activity.bug_id |
| 91 | + $sqlproduct |
| 92 | + ", undef, ($days)); |
| 93 | + |
| 94 | + return($count); |
| 95 | +} |
| 96 | + |
| 97 | +sub wishes_closed() |
| 98 | +{ |
| 99 | + my($product, $days) = @_; |
| 100 | + my $query = ""; |
| 101 | + my $sqlproduct = ""; |
| 102 | + $sqlproduct = "AND bugs.product_id=" . Bugzilla->dbh->quote($product) |
| 103 | + if(defined $product and $product ne "%"); |
| 104 | + |
| 105 | + # We are going to build a long SQL query. |
| 106 | + my ($count) = Bugzilla->dbh->selectrow_array(" |
| 107 | +select |
| 108 | + count(distinct bugs.bug_id) |
| 109 | +from |
| 110 | + bugs, bugs_activity |
| 111 | +where |
| 112 | + bugs.bug_severity = 'enhancement' AND |
| 113 | + (bugs_activity.added='RESOLVED' or bugs_activity.added='CLOSED' or |
| 114 | + bugs_activity.added='NEEDSINFO') |
| 115 | +and |
| 116 | + bugs_activity.bug_when >= FROM_DAYS(TO_DAYS(NOW())-?) |
| 117 | +and |
| 118 | + bugs.bug_id = bugs_activity.bug_id |
| 119 | + $sqlproduct |
| 120 | + ", undef, ($days)); |
| 121 | + |
| 122 | + return($count); |
| 123 | +} |
| 124 | + |
| 125 | +sub open_wishes() |
| 126 | +{ |
| 127 | + my($product) = @_; |
| 128 | + |
| 129 | + my $sqlproduct = ""; |
| 130 | + $sqlproduct = "AND bugs.product_id=" . Bugzilla->dbh->quote($product) |
| 131 | + if(defined $product and $product ne "%"); |
| 132 | + |
| 133 | + # We are going to build a long SQL query. |
| 134 | + my ($count) = Bugzilla->dbh->selectrow_array(" |
| 135 | +SELECT |
| 136 | + count(bugs.bug_id) |
| 137 | +FROM bugs |
| 138 | +WHERE bugs.bug_severity = 'enhancement' AND |
| 139 | + (bugs.bug_status = 'NEW' or bugs.bug_status = 'ASSIGNED' or |
| 140 | + bugs.bug_status = 'REOPENED' or bugs.bug_status = 'UNCONFIRMED') |
| 141 | +$sqlproduct"); |
| 142 | + |
| 143 | + return $count; |
| 144 | +} |
| 145 | + |
| 146 | + |
| 147 | +# $format can be HTML or XML |
| 148 | +sub print_product_bug_lists() { |
| 149 | + my($number, $days, $format, $fh) = @_; |
| 150 | + |
| 151 | + my $query; |
| 152 | + |
| 153 | + my @results; |
| 154 | + |
| 155 | + # We are going to build a long SQL query. |
| 156 | + my $sth = Bugzilla->dbh->prepare(" |
| 157 | +select |
| 158 | + products.name, bugs.product_id, count(bugs.product_id) as n |
| 159 | +from |
| 160 | + bugs, products |
| 161 | +where |
| 162 | + (bugs.bug_status = 'NEW' or bugs.bug_status = 'ASSIGNED' or |
| 163 | + bugs.bug_status = 'REOPENED' or bugs.bug_status = 'UNCONFIRMED') |
| 164 | +and |
| 165 | + bugs.bug_severity != 'enhancement' |
| 166 | +and |
| 167 | + products.id = bugs.product_id |
| 168 | + |
| 169 | +group by product_id |
| 170 | +order by n desc |
| 171 | +limit $number |
| 172 | + "); |
| 173 | + $sth->execute; |
| 174 | + |
| 175 | + # For each product we want to show the difference in the last period. |
| 176 | + # But this will involve two sql connections at once, which the bugzilla |
| 177 | + # functions don't handle too nicely. |
| 178 | + # So lets collect the data first and then print the table. |
| 179 | + my %product_count; |
| 180 | + my %product_id; |
| 181 | + |
| 182 | + while (my ($product, $p_id, $count) = $sth->fetchrow_array) { |
| 183 | + $product_count{$product} = $count; |
| 184 | + $product_id{$product} = $p_id; |
| 185 | + } |
| 186 | + |
| 187 | + |
| 188 | + foreach my $product (reverse sort |
| 189 | + {$product_count{$a} <=> $product_count{$b}} |
| 190 | + keys (%product_count)) { |
| 191 | + my %product_results; |
| 192 | + my $bopened = &bugs_opened($product_id{$product}, $days); |
| 193 | + my $bclosed = &bugs_closed($product_id{$product}, $days); |
| 194 | + $product_results{'id'} = $product_id{$product}; |
| 195 | + $product_results{'name'} = $product; |
| 196 | + $product_results{'count'} = $product_count{$product}; |
| 197 | + $product_results{'bugs_opened'} = $bopened; |
| 198 | + $product_results{'bugs_closed'} = $bclosed; |
| 199 | + $product_results{'bugs_change'} = $bopened - $bclosed; |
| 200 | + if( $product_results{'bugs_change'} > 0 ) { |
| 201 | + $product_results{'bugs_change_color'} = "#FF9999"; |
| 202 | + } elsif( $product_results{'bugs_change'} < 0 ) { |
| 203 | + $product_results{'bugs_change_color'} = "#99FF99"; |
| 204 | + } |
| 205 | + $product_results{'total_wishes'} = &open_wishes($product_id{$product}); |
| 206 | + $product_results{'open_wishes'} = &wishes_opened($product_id{$product}, $days); |
| 207 | + $product_results{'closed_wishes'} = &wishes_closed($product_id{$product}, $days); |
| 208 | + $product_results{'wishes_change'} = $product_results{'open_wishes'} - |
| 209 | + $product_results{'closed_wishes'}; |
| 210 | + if( $product_results{'wishes_change'} > 0 ) { |
| 211 | + $product_results{'wish_change_color'} = "#FF9999"; |
| 212 | + } elsif( $product_results{'wishes_change'} < 0 ) { |
| 213 | + $product_results{'wish_change_color'} = "#99FF99"; |
| 214 | + } |
| 215 | + push @results, \%product_results; |
| 216 | + } |
| 217 | + |
| 218 | + return \@results; |
| 219 | +} |
| 220 | + |
| 221 | +sub print_bug_hunters_list() { |
| 222 | + my($number, $days) = @_; |
| 223 | + my @results; |
| 224 | + my $query; |
| 225 | + |
| 226 | + my $sth = Bugzilla->dbh->prepare(" |
| 227 | +select |
| 228 | + assign.login_name, count(assign.login_name), count(assign.login_name) as n |
| 229 | +from |
| 230 | + bugs, bugs_activity, profiles assign |
| 231 | +where |
| 232 | + (bugs_activity.added='RESOLVED' or bugs_activity.added = 'CLOSED' or |
| 233 | + bugs_activity.added='NEEDSINFO') |
| 234 | +and |
| 235 | + bugs_activity.bug_when >= from_days(TO_DAYS(NOW()) - ?) |
| 236 | +and |
| 237 | + bugs_activity.who = assign.userid |
| 238 | +and |
| 239 | + bugs.bug_id = bugs_activity.bug_id |
| 240 | +and |
| 241 | + (bugs.bug_status = 'RESOLVED' or bugs.bug_status = 'CLOSED') |
| 242 | +group by assign.login_name |
| 243 | +order by n desc |
| 244 | +limit ? |
| 245 | + "); |
| 246 | + |
| 247 | + $sth->execute($days, $number); |
| 248 | + while (my ($user, $count, $n) = $sth->fetchrow_array()) { |
| 249 | + |
| 250 | + my %bh_results; |
| 251 | + |
| 252 | + # defang the email address |
| 253 | + $user =~ y/\@\./ / if (Bugzilla->user->id == 0); |
| 254 | + $bh_results{'user'} = $user; |
| 255 | + $bh_results{'count'} = $count; |
| 256 | + |
| 257 | + push @results, \%bh_results; |
| 258 | + } |
| 259 | + |
| 260 | + return \@results; |
| 261 | +} |
| 262 | + |
| 263 | +sub print_bug_fixers_list() { |
| 264 | + my($number, $days) = @_; |
| 265 | + my @results; |
| 266 | + |
| 267 | + my $sth = Bugzilla->dbh->prepare(" |
| 268 | +SELECT |
| 269 | + profiles.login_name, bugs.bug_id, |
| 270 | + MIN(UNIX_TIMESTAMP(bugs_activity.bug_when)-UNIX_TIMESTAMP(bugs.creation_ts)) |
| 271 | + AS open_time |
| 272 | +FROM |
| 273 | + bugs, bugs_activity, profiles, longdescs |
| 274 | +WHERE |
| 275 | + bugs.resolution='FIXED' |
| 276 | +AND |
| 277 | + bugs.bug_status='RESOLVED' |
| 278 | +AND |
| 279 | + bugs_activity.bug_when >= FROM_DAYS(TO_DAYS(NOW())-?) |
| 280 | +AND |
| 281 | + bugs.bug_id=bugs_activity.bug_id |
| 282 | +AND |
| 283 | + bugs_activity.added='FIXED' |
| 284 | +AND |
| 285 | + bugs_activity.who=profiles.userid |
| 286 | +AND |
| 287 | + bugs.reporter != bugs_activity.who |
| 288 | +AND |
| 289 | + longdescs.bug_id = bugs.bug_id |
| 290 | +AND |
| 291 | + longdescs.who = bugs_activity.who |
| 292 | +AND |
| 293 | + longdescs.thetext like \"SVN commit%\" |
| 294 | +GROUP BY |
| 295 | + profiles.login_name, bugs.bug_id |
| 296 | +ORDER BY |
| 297 | + open_time ASC |
| 298 | +LIMIT ?"); |
| 299 | + |
| 300 | + $sth->execute($days, $number); |
| 301 | + |
| 302 | + while (my ($user, $bugid, $elapsed) = $sth->fetchrow_array) { |
| 303 | + |
| 304 | + my %bf_results; |
| 305 | + |
| 306 | + # defang the email address |
| 307 | + $user =~ y/\@\./ / if (Bugzilla->user->id == 0); |
| 308 | + $bf_results{'name'} = $user; |
| 309 | + $bf_results{'elapsed'} = ${elapsed}; |
| 310 | + my $html_elapsed = "${elapsed}s"; |
| 311 | + $html_elapsed = int($elapsed/60) . " min" if ($elapsed > 60); |
| 312 | + $html_elapsed = int($elapsed/(60*60)) . " h" if ($elapsed > (4*60*60)); |
| 313 | + $html_elapsed = int($elapsed/(60*60*24)) . " days" if ($elapsed > (58*60*60)); |
| 314 | + $bf_results{'formatted_elapsed'} = $html_elapsed; |
| 315 | + $bf_results{'bugid'} = $bugid; |
| 316 | + |
| 317 | + push @results, \%bf_results; |
| 318 | + } |
| 319 | + |
| 320 | + return \@results; |
| 321 | +} |
| 322 | + |
| 323 | + |
| 324 | +Bugzilla->login(LOGIN_OPTIONAL); |
| 325 | + |
| 326 | +# For most scripts we don't make $cgi and $template global variables. But |
| 327 | +# when preparing Bugzilla for mod_perl, this script used these |
| 328 | +# variables in so many subroutines that it was easier to just |
| 329 | +# make them globals. |
| 330 | +local our $cgi = Bugzilla->cgi; |
| 331 | +local our $template = Bugzilla->template; |
| 332 | +local our $vars = {}; |
| 333 | + |
| 334 | +# Output appropriate HTTP response headers |
| 335 | +print $cgi->header(-type => 'text/html', -expires => '+3M'); |
| 336 | + |
| 337 | +my %defaults; |
| 338 | + |
| 339 | +# If they didn't tell us a time period we choose the last week. |
| 340 | +my $current_days = 7; |
| 341 | +$current_days = $cgi->param('days') if (defined $cgi->param('days')); |
| 342 | +$current_days = 7 if (!detaint_natural($current_days)); |
| 343 | +$defaults{'days'} = $current_days; |
| 344 | + |
| 345 | +my $current_tops = 20; |
| 346 | +$current_tops = $cgi->param('tops') if (defined $cgi->param('tops')); |
| 347 | +$current_tops = 20 if (!detaint_natural($current_tops)); |
| 348 | +$defaults{'tops'} = $current_tops; |
| 349 | + |
| 350 | +$vars->{'duration'} = $current_days; |
| 351 | +$vars->{'top_number'} = $current_tops; |
| 352 | + |
| 353 | +($vars->{'totalbugs'}, $vars->{'totalwishes'}) = &total_bugs_in_bugzilla(); |
| 354 | + |
| 355 | +my $bo = &bugs_opened("%", $current_days); |
| 356 | +my $wo = &wishes_opened("%", $current_days); |
| 357 | +my $bc = &bugs_closed("%", $current_days); |
| 358 | +my $wc = &wishes_closed("%", $current_days); |
| 359 | + |
| 360 | +$vars->{'new_open_bugs'} = $bo; |
| 361 | +$vars->{'new_closed_bugs'} = $bc; |
| 362 | +$vars->{'new_open_wishes'} = $wo; |
| 363 | +$vars->{'new_closed_wishes'} = $wc; |
| 364 | + |
| 365 | +my @tops = (10, 20, 30, 50, 100); |
| 366 | +$vars->{'tops'} = \@tops; |
| 367 | + |
| 368 | +my @days = (1, 2, 7, 14, 31, 180, 365); |
| 369 | +$vars->{'days'} = \@days; |
| 370 | + |
| 371 | +$vars->{'default'} = \%defaults; |
| 372 | + |
| 373 | +$vars->{'product_bug_lists'} = &print_product_bug_lists($current_tops, $current_days, "HTML"); |
| 374 | + |
| 375 | +$vars->{'bug_hunters_list'} = &print_bug_hunters_list($current_tops, $current_days); |
| 376 | + |
| 377 | +$vars->{'bug_fixers_list'} = &print_bug_fixers_list($current_tops, $current_days); |
| 378 | + |
| 379 | +$template->process("weeklyreport/weekly-bug-summary.html.tmpl", $vars) |
| 380 | + || ThrowTemplateError($template->error()); |
| 381 | + |
| 382 | + |
| 383 | + |
| 384 | + |
| 385 | + |
| 386 | +print "</div>\n"; |
| 387 | + |
Property changes on: trunk/tools/bugzilla/bugzilla-4.0/extensions/WeeklyReport/weekly-bug-summary.cgi |
___________________________________________________________________ |
Added: svn:executable |
1 | 388 | + * |
Index: trunk/tools/bugzilla/bugzilla-4.0/extensions/WeeklyReport/template/en/default/hook/README |
— | — | @@ -0,0 +1,5 @@ |
| 2 | +Template hooks go in this directory. Template hooks are called in normal |
| 3 | +Bugzilla templates like [% Hook.process('some-hook') %]. |
| 4 | +More information about them can be found in the documentation of |
| 5 | +Bugzilla::Extension. (Do "perldoc Bugzilla::Extension" from the main |
| 6 | +Bugzilla directory to see that documentation.) |
\ No newline at end of file |
Index: trunk/tools/bugzilla/bugzilla-4.0/extensions/WeeklyReport/template/en/default/weeklyreport/weekly-bug-summary.html.tmpl |
— | — | @@ -0,0 +1,95 @@ |
| 2 | +[%# Wikimedia weekly bug summary template #%] |
| 3 | + |
| 4 | +[% PROCESS global/variables.none.tmpl %] |
| 5 | + |
| 6 | +[% PROCESS global/header.html.tmpl |
| 7 | + title = "Wikimedia Weekly Bug Summary" |
| 8 | +%] |
| 9 | + |
| 10 | +<h3 style="text-align:center;">Total: [% totalbugs %] bugs and [% totalwishes %] enhancements</h3> |
| 11 | + |
| 12 | +<h4 style="text-align:center;">[% new_open_bugs %] bugs opened, [% new_closed_bugs %] bugs closed in the last [% duration %] days<br> |
| 13 | +([% new_open_wishes %] enhancements opened, [% new_closed_wishes %] enhancements closed)</h4> |
| 14 | + |
| 15 | +<form action="weekly-bug-summary.cgi" style="text-align:center;">Report top |
| 16 | + [% sel = { name => 'tops'} %] |
| 17 | + [% INCLUDE select %] |
| 18 | +summary over the last |
| 19 | + [% sel = { name => 'days'} %] |
| 20 | + [% INCLUDE select %] |
| 21 | +days and <input type="submit" value="Show" /> |
| 22 | +</form> |
| 23 | + |
| 24 | +<h3 style="text-align:center;">Top [% top_number %] Wikimedia products with the most bugs:</h3> |
| 25 | + |
| 26 | +<table align="center" border="0" cellspacing="2" cellpadding="5"> |
| 27 | +<tr style="background-color: #EEF6FF;"><th>Product</th> |
| 28 | +<th>Open<br />bugs</th> |
| 29 | +<th>Opened in<br />last [% duration %] days</th> |
| 30 | +<th>Closed in<br />last [% duration %] days</th> |
| 31 | +<th>Change</th> |
| 32 | +<th>Open<br />enhancements</th> |
| 33 | +<th>Opened in<br />last [% duration %] days</th> |
| 34 | +<th>Closed in<br />last [% duration %] days</th> |
| 35 | +<th>Change</th> |
| 36 | +<th> </th></tr> |
| 37 | + |
| 38 | +[%- FOREACH pr = product_bug_lists %] |
| 39 | +<tr> |
| 40 | + <td><a href="component-report.cgi?product=[%- pr.name -%]">[%- pr.name -%]</a></td> |
| 41 | + <td style="text-align:right;"><a href="buglist.cgi?product=[%- pr.name -%]&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=critical&bug_severity=grave&bug_severity=major&bug_severity=crash&bug_severity=normal&bug_severity=minor">[%- pr.count -%]</a></td> |
| 42 | + <td style="text-align:right;">+[%- pr.bugs_opened -%]</td> |
| 43 | + <td style="text-align:right;">-[%- pr.bugs_closed -%]</td> |
| 44 | + <td style="text-align:right; background-color: [%- pr.bugs_change_color -%];">[%- pr.bugs_change -%]</td> |
| 45 | + <td style="text-align:right;"><a href="buglist.cgi?product=[%- pr.name -%]&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=enhancement">[%- pr.total_wishes -%]</a></td> |
| 46 | + <td style="text-align:right;">+[%- pr.open_wishes -%]</td> |
| 47 | + <td style="text-align:right;">-[%- pr.closed_wishes -%]</td> |
| 48 | + <td style="text-align:right; background-color: [%- pr.wishes_change_color -%];">[%- pr.wishes_change -%]</td> |
| 49 | + <td style="text-align:right;"><a href="reports.cgi?product=[%- pr.name -%]&output=show_chart&datasets=NEW%3A&datasets=ASSIGNED%3A&datasets=REOPENED%3A&datasets=UNCONFIRMED%3A&datasets=RESOLVED%3A&banner=1">Graph</a></td> |
| 50 | +</tr> |
| 51 | +[% END %] |
| 52 | +</table> |
| 53 | + |
| 54 | +<h3 style="text-align:center;"><a name="closers">Top [% top_number %] people who resolved the most reports in the last [% duration %] days:</a></h3> |
| 55 | +<table align="center" border="0" cellspacing="2" cellpadding="5"> |
| 56 | +<tr style="background-color: #EEF6FF;"> |
| 57 | + <th>User</th><th># Resolved</th> |
| 58 | +</tr> |
| 59 | +[%- FOREACH bh = bug_hunters_list %] |
| 60 | +<tr> |
| 61 | + <td>[% bh.user FILTER html %]</td> |
| 62 | + <td>[% bh.count %]</td> |
| 63 | +<tr> |
| 64 | +[% END %] |
| 65 | +</table> |
| 66 | + |
| 67 | +<h3 style="text-align:center;"><a name="fixers">Top [% top_number %] people who most quickly fixed a report in the last [% duration %] days:</a></h3> |
| 68 | +<table align="center" border="0" cellspacing="2" cellpadding="5"> |
| 69 | +<tr style="background-color: #EEF6FF;"> |
| 70 | +<th>User</th><th>Elapsed time</th></tr> |
| 71 | +[%- FOREACH bf = bug_fixers_list %] |
| 72 | +<tr> |
| 73 | + <td>[% bf.name FILTER html %]</td> |
| 74 | + <td>[% bf.formatted_elapsed %] (<a href="show_bug.cgi?id=[% bf.bugid %]">[% bf.bugid %]</a>)</td> |
| 75 | +</tr> |
| 76 | +[% END %] |
| 77 | +</table> |
| 78 | + |
| 79 | +[% PROCESS global/footer.html.tmpl %] |
| 80 | + |
| 81 | + |
| 82 | +[%##########################################################################%] |
| 83 | +[%# Block for SELECT fields #%] |
| 84 | +[%##########################################################################%] |
| 85 | + |
| 86 | +[% BLOCK select %] |
| 87 | + <select name="[% sel.name %]"> |
| 88 | + [%- FOREACH x = ${sel.name} %] |
| 89 | + <option value="[% x FILTER html %]" |
| 90 | + [% " selected=\"selected\"" IF x == default.${sel.name} %]> |
| 91 | + [% x FILTER html %] |
| 92 | + </option> |
| 93 | + [% END %] |
| 94 | + </select> |
| 95 | +[% END %] |
| 96 | + |
Index: trunk/tools/bugzilla/bugzilla-4.0/extensions/WeeklyReport/template/en/default/weeklyreport/component-report.html.tmpl |
— | — | @@ -0,0 +1,33 @@ |
| 2 | +[%# KDE component report template #%] |
| 3 | + |
| 4 | +[% PROCESS global/variables.none.tmpl %] |
| 5 | + |
| 6 | +[% PROCESS global/header.html.tmpl |
| 7 | + title = "Component Report" |
| 8 | + h1 = "Report Count by Component and Severity" |
| 9 | +%] |
| 10 | + |
| 11 | +<p align="center"> |
| 12 | +<table border="1" cellspacing="2" cellpadding="5" align="center"> |
| 13 | +<tr style="background-color: #EEF6FF;"> |
| 14 | +<td><b>Component</b></td> |
| 15 | +[% FOREACH sev = all_severities %] |
| 16 | +<td><b>[% sev %]</b></td> |
| 17 | +[% END %] |
| 18 | +<td><b>total</b></td> |
| 19 | +</tr> |
| 20 | +[% FOREACH comp = all_components %] |
| 21 | +<tr> |
| 22 | + <td>[% product %] - [% comp %]</td> |
| 23 | + [% FOREACH sev = all_severities %] |
| 24 | + <td><a href="buglist.cgi?product=[% product %]&component=[% comp %]&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=[% sev %]">[% bug_sev_counts.$comp.$sev %]</a></td> |
| 25 | + [% END %] |
| 26 | + <td><a href="buglist.cgi?product=[% product %]&component=[% comp %]&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED">[% bug_sev_counts.$comp.total %]</a></td> |
| 27 | +</tr> |
| 28 | +[% END %] |
| 29 | + |
| 30 | + |
| 31 | +</table> |
| 32 | +</p> |
| 33 | +[% PROCESS global/footer.html.tmpl %] |
| 34 | + |
Index: trunk/tools/bugzilla/bugzilla-4.0/extensions/WeeklyReport/template/en/default/weeklyreport/README |
— | — | @@ -0,0 +1,16 @@ |
| 2 | +Normal templates go in this directory. You can load them in your |
| 3 | +code like this: |
| 4 | + |
| 5 | +use Bugzilla::Error; |
| 6 | +my $template = Bugzilla->template; |
| 7 | +$template->process('weeklyreport/some-template.html.tmpl') |
| 8 | + or ThrowTemplateError($template->error()); |
| 9 | + |
| 10 | +That would be how to load a file called some-template.html.tmpl that |
| 11 | +was in this directory. |
| 12 | + |
| 13 | +Note that you have to be careful that the full path of your template |
| 14 | +never conflicts with a template that exists in Bugzilla or in |
| 15 | +another extension, or your template might override that template. That's why |
| 16 | +we created this directory called 'weeklyreport' for you, so you |
| 17 | +can put your templates in here to help avoid conflicts. |
\ No newline at end of file |
Index: trunk/tools/bugzilla/bugzilla-4.0/extensions/WeeklyReport/component-report.cgi |
— | — | @@ -0,0 +1,113 @@ |
| 2 | +#!/usr/bin/perl -wT |
| 3 | +# -*- Mode: perl; indent-tabs-mode: nil -*- |
| 4 | +# |
| 5 | +# The contents of this file are subject to the Mozilla Public |
| 6 | +# License Version 1.1 (the "License"); you may not use this file |
| 7 | +# except in compliance with the License. You may obtain a copy of |
| 8 | +# the License at http://www.mozilla.org/MPL/ |
| 9 | +# |
| 10 | +# Software distributed under the License is distributed on an "AS |
| 11 | +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
| 12 | +# implied. See the License for the specific language governing |
| 13 | +# rights and limitations under the License. |
| 14 | +# |
| 15 | +# The Original Code is the Bugzilla Bug Tracking System. |
| 16 | +# |
| 17 | +# The Initial Developer of the Original Code is Netscape Communications |
| 18 | +# Corporation. Portions created by Netscape are |
| 19 | +# Copyright (C) 1998 Netscape Communications Corporation. All |
| 20 | +# Rights Reserved. |
| 21 | +# |
| 22 | +# Contributor(s): Harrison Page <harrison@netscape.com>, |
| 23 | +# Terry Weissman <terry@mozilla.org>, |
| 24 | +# Dawn Endico <endico@mozilla.org> |
| 25 | +# Bryce Nesbitt <bryce@nextbus.COM>, |
| 26 | +# Added -All- report, change "nobanner" to "banner" (it is strange to have a |
| 27 | +# list with 2 positive and 1 negative choice), default links on, add show |
| 28 | +# sql comment. |
| 29 | +# Joe Robins <jmrobins@tgix.com>, |
| 30 | +# If using the usebuggroups parameter, users shouldn't be able to see |
| 31 | +# reports for products they don't have access to. |
| 32 | +# Gervase Markham <gerv@gerv.net> and Adam Spiers <adam@spiers.net> |
| 33 | +# Added ability to chart any combination of resolutions/statuses. |
| 34 | +# Derive the choice of resolutions/statuses from the -All- data file |
| 35 | +# Removed hardcoded order of resolutions/statuses when reading from |
| 36 | +# daily stats file, so now works independently of collectstats.pl |
| 37 | +# version |
| 38 | +# Added image caching by date and datasets |
| 39 | +# Myk Melez <myk@mozilla.org): |
| 40 | +# Implemented form field validation and reorganized code. |
| 41 | +# |
| 42 | +# Luis Villa <louie@ximian.com>: |
| 43 | +# modified it to report things in a new format |
| 44 | +# Matt Rogers <mattr@kde.org>: |
| 45 | +# Rewritten for bugzilla 3.0 including template |
| 46 | + |
| 47 | +use strict; |
| 48 | +use lib qw(.); |
| 49 | + |
| 50 | +use Bugzilla; |
| 51 | +use Bugzilla::Product; |
| 52 | +use Bugzilla::Constants; |
| 53 | +use Bugzilla::Error; |
| 54 | + |
| 55 | +use vars qw($vars $template); |
| 56 | + |
| 57 | +eval "use GD"; |
| 58 | +my $use_gd = $@ ? 0 : 1; |
| 59 | +eval "use Chart::Lines"; |
| 60 | +$use_gd = 0 if $@; |
| 61 | + |
| 62 | +# If we're using bug groups for products, we should apply those restrictions |
| 63 | +# to viewing reports, as well. Time to check the login in that case. |
| 64 | + |
| 65 | +my $cgi = Bugzilla->cgi; |
| 66 | +my $template = Bugzilla->template; |
| 67 | +my $vars = {}; |
| 68 | +my $user = Bugzilla->login(LOGIN_OPTIONAL); |
| 69 | + |
| 70 | +print $cgi->header(-type => 'text/html', -expires => '+3M'); |
| 71 | + |
| 72 | +my $query = <<EOF |
| 73 | +SELECT count(*), products.name, components.name, bug_severity |
| 74 | + FROM bugs, products, components |
| 75 | + WHERE ( bug_status = 'NEW' or bug_status = 'ASSIGNED' or bug_status = 'REOPENED' or bug_status = 'UNCONFIRMED' ) |
| 76 | + AND products.name = ? |
| 77 | + AND bugs.product_id = products.id |
| 78 | + AND bugs.component_id = components.id |
| 79 | + AND products.id = components.product_id |
| 80 | +GROUP BY products.name, components.name, bug_severity |
| 81 | +ORDER BY components.name |
| 82 | +EOF |
| 83 | +; |
| 84 | + |
| 85 | +#Report on components by severity and priority |
| 86 | +my $sth = Bugzilla->dbh->prepare($query); |
| 87 | +my $product = $cgi->param('product'); |
| 88 | +if ($product =~ /^([\w.-\s]+)$/) { $product = $1 } |
| 89 | +$sth->execute($product); |
| 90 | + |
| 91 | +my (@bug_counts, %bugs, %total_bugs); |
| 92 | +my $disp_component; |
| 93 | +my $total_bug_count; |
| 94 | + |
| 95 | +my $product_obj = new Bugzilla::Product({ 'name' => $product }); |
| 96 | + |
| 97 | +$vars->{'product'} = $product; |
| 98 | +$vars->{'all_severities'} = Bugzilla::Field::get_legal_field_values('bug_severity'); |
| 99 | +my @compnames; |
| 100 | +for my $comp (@{$product_obj->components}) { |
| 101 | + push @compnames, $comp->name |
| 102 | +} |
| 103 | +$vars->{'all_components'} = \@compnames; |
| 104 | + |
| 105 | +while (my ($bcount, $product, $component, $sever) = $sth->fetchrow_array) { |
| 106 | + $bugs{$component}{$sever} = $bcount; |
| 107 | + $bugs{$component}{'total'} += $bcount; |
| 108 | +} |
| 109 | + |
| 110 | +$vars->{'bug_sev_counts'} = \%bugs; |
| 111 | + |
| 112 | +$template->process("weeklyreport/component-report.html.tmpl", $vars) |
| 113 | + || ThrowTemplateError($template->error()); |
| 114 | + |
Property changes on: trunk/tools/bugzilla/bugzilla-4.0/extensions/WeeklyReport/component-report.cgi |
___________________________________________________________________ |
Added: svn:executable |
1 | 115 | + * |