From 12b3b674e4dac42707c39ce2389907f2e4e6a74c Mon Sep 17 00:00:00 2001 From: "lpsolit%gmail.com" <> Date: Fri, 14 Jul 2006 01:00:40 +0000 Subject: Bug 94534: Customised resolutions - Patch by Frédéric Buclin r=mkanat a=myk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- collectstats.pl | 195 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 134 insertions(+), 61 deletions(-) (limited to 'collectstats.pl') diff --git a/collectstats.pl b/collectstats.pl index 0739d0312..5ba56fe4b 100755 --- a/collectstats.pl +++ b/collectstats.pl @@ -23,6 +23,7 @@ # Gervase Markham # Richard Walters # Jean-Sebastien Guay +# Frédéric Buclin # Run me out of cron at midnight to collect Bugzilla statistics. # @@ -41,6 +42,7 @@ use Bugzilla::Util; use Bugzilla::Search; use Bugzilla::User; use Bugzilla::Product; +use Bugzilla::Field; # Turn off output buffering (probably needed when displaying output feedback # in the regenerate mode.) @@ -55,7 +57,7 @@ if (chdir("graphs")) { # Let Throw*Error() work correctly outside a web browser. Bugzilla->batch(1); -Bugzilla->switch_to_shadow_db(); +my $dbh = Bugzilla->switch_to_shadow_db(); # To recreate the daily statistics, run "collectstats.pl --regenerate" . my $regenerate = 0; @@ -69,6 +71,39 @@ my $datadir = bz_locations()->{'datadir'}; my @myproducts = map {$_->name} Bugzilla::Product::get_all_products(); unshift(@myproducts, "-All-"); +# As we can now customize the list of resolutions, looking at the actual list +# of available resolutions only is not enough as some now removed resolutions +# may have existed in the past, or have been renamed. We want them all. +my @resolutions = @{get_legal_field_values('resolution')}; +my $old_resolutions = + $dbh->selectcol_arrayref('SELECT bugs_activity.added + FROM bugs_activity + INNER JOIN fielddefs + ON fielddefs.fieldid = bugs_activity.fieldid + LEFT JOIN resolution + ON resolution.value = bugs_activity.added + WHERE fielddefs.name = ? + AND resolution.id IS NULL + + UNION + + SELECT bugs_activity.removed + FROM bugs_activity + INNER JOIN fielddefs + ON fielddefs.fieldid = bugs_activity.fieldid + LEFT JOIN resolution + ON resolution.value = bugs_activity.removed + WHERE fielddefs.name = ? + AND resolution.id IS NULL', + undef, ('resolution', 'resolution')); + +push(@resolutions, @$old_resolutions); +# Exclude "" from the resolution list. +@resolutions = grep {$_} @resolutions; + +# Actually, the list of statuses is predefined. This will change in the near future. +my @statuses = qw(NEW ASSIGNED REOPENED UNCONFIRMED RESOLVED VERIFIED CLOSED); + my $tstart = time; foreach (@myproducts) { my $dir = "$datadir/mining"; @@ -143,56 +178,108 @@ sub collect_stats { my $file = join '/', $dir, $file_product; my $exists = -f $file; - if (open DATA, ">>$file") { - push (my @row, &today); - my $status_sql = q{SELECT COUNT(*) - FROM bugs - WHERE bug_status = ?}; - - my $reso_sql = q{SELECT COUNT(*) - FROM bugs - WHERE resolution = ?}; - - if ($product ne '-All-') { - $status_sql .= q{ AND product_id = ?}; - $reso_sql .= q{ AND product_id = ?}; - } - - my $sth_status = $dbh->prepare($status_sql); - my $sth_reso = $dbh->prepare($reso_sql); - - my @values ; - foreach my $status ('NEW', 'ASSIGNED', 'REOPENED', 'UNCONFIRMED', 'RESOLVED', 'VERIFIED', 'CLOSED') { - @values = ($status); - push (@values, $product_id) if ($product ne '-All-'); - my $count = $dbh->selectrow_array($sth_status, undef, @values); - push(@row, $count); - } - foreach my $resolution ('FIXED', 'INVALID', 'WONTFIX', 'LATER', 'REMIND', 'DUPLICATE', 'WORKSFORME', 'MOVED') { - @values = ($resolution); - push (@values, $product_id) if ($product ne '-All-'); - my $count = $dbh->selectrow_array($sth_reso, undef, @values); - push(@row, $count); - } + # if the file exists, get the old status and resolution list for that product. + my @data; + @data = get_old_data($file) if $exists; + + # If @data is not empty, then we have to recreate the data file. + if (scalar(@data)) { + open(DATA, '>', $file) + || ThrowCodeError('chart_file_open_fail', {'filename' => $file}); + } + else { + open(DATA, '>>', $file) + || ThrowCodeError('chart_file_open_fail', {'filename' => $file}); + } + + # Now collect current data. + my @row = (today()); + my $status_sql = q{SELECT COUNT(*) FROM bugs WHERE bug_status = ?}; + my $reso_sql = q{SELECT COUNT(*) FROM bugs WHERE resolution = ?}; + + if ($product ne '-All-') { + $status_sql .= q{ AND product_id = ?}; + $reso_sql .= q{ AND product_id = ?}; + } + + my $sth_status = $dbh->prepare($status_sql); + my $sth_reso = $dbh->prepare($reso_sql); + + my @values ; + foreach my $status (@statuses) { + @values = ($status); + push (@values, $product_id) if ($product ne '-All-'); + my $count = $dbh->selectrow_array($sth_status, undef, @values); + push(@row, $count); + } + foreach my $resolution (@resolutions) { + @values = ($resolution); + push (@values, $product_id) if ($product ne '-All-'); + my $count = $dbh->selectrow_array($sth_reso, undef, @values); + push(@row, $count); + } - if (! $exists) { - print DATA <{$_} ? $data->{$_} : ''} + ('DATE', @statuses, @resolutions)) . "\n"; + } + print DATA (join '|', @row) . "\n"; + close DATA; + chmod 0644, $file; +} + +sub get_old_data { + my $file = shift; + + open(DATA, '<', $file) + || ThrowCodeError('chart_file_open_fail', {'filename' => $file}); + + my @data; + my @columns; + my $recreate = 0; + while () { + chomp; + next unless $_; + if (/^# fields?:\s*(.+)\s*$/) { + @columns = split(/\|/, $1); + # Compare this list with @statuses and @resolutions. + # If they are identical, then we can safely append new data + # to the end of the file; else we have to recreate it. + $recreate = 1; + my @new_cols = ($columns[0], @statuses, @resolutions); + if (scalar(@columns) == scalar(@new_cols)) { + my ($removed, $added) = diff_arrays(\@columns, \@new_cols); + last if (!scalar(@$removed) && !scalar(@$added)); + } + } + next unless $recreate; + next if (/^#/); # Ignore comments. + # If we have to recreate the file, we have to load all existing + # data first. + my @line = split /\|/; + my %data; + foreach my $column (@columns) { + $data{$column} = shift @line; + } + push(@data, \%data); } + close(DATA); + return @data; } sub calculate_dupes { @@ -317,12 +404,13 @@ sub regenerate_stats { if (open DATA, ">$file") { DATA->autoflush(1); + my $fields = join('|', ('DATE', @statuses, @resolutions)); print DATA <