+=pod
+
+=head1 NAME $RCSfile: BugzillaUtils.pm,v $
+
+Some shared functions dealing with Bugzilla. Note this uses DBI to directly
+access Bugzilla's database. This requires that your userid was granted access.
+For this I setup adefaria with pretty much read only access.
+
+=head1 VERSION
+
+=over
+
+=item Author
+
+Andrew DeFaria <Andrew@ClearSCM.com>
+
+=item Revision
+
+$Revision: 1.0 $
+
+=item Created
+
+Fri Mar 12 10:17:44 PST 2004
+
+=item Modified
+
+$Date: 2013/05/30 15:48:06 $
+
+=head1 ROUTINES
+
+The following routines are exported:
+
+=cut
+
+package BugzillaUtils;
+
+use strict;
+use warnings;
+
+use base 'Exporter';
+
+use FindBin;
+use Display;
+use Carp;
+use DBI;
+
+use lib 'lib';
+
+use JIRAUtils;
+
+our $bugzilla;
+
+our @EXPORT = qw (
+ openBugzilla
+ getRelationships
+ getDependencies
+ getBlockers
+ getDuplicates
+ getRelated
+ getBug
+ getBugComments
+ getWatchers
+);
+
+sub _checkDBError ($$) {
+ my ($msg, $statement) = @_;
+
+ my $dberr = $bugzilla->err;
+ my $dberrmsg = $bugzilla->errstr;
+
+ $dberr ||= 0;
+ $dberrmsg ||= 'Success';
+
+ my $message = '';
+
+ if ($dberr) {
+ my $function = (caller (1)) [3];
+
+ $message = "$function: $msg\nError #$dberr: $dberrmsg\n"
+ . "SQL Statement: $statement";
+ } # if
+
+ $main::log->err ($message, $dberr) if $dberr;
+
+ return;
+} # _checkDBError
+
+sub openBugzilla (;$$$$) {
+ my ($dbhost, $dbname, $dbuser, $dbpass) = @_;
+
+ $dbhost //= 'jira-dev';
+ $dbname //= 'bugzilla';
+ $dbuser //= 'adefaria';
+ $dbpass //= 'reader';
+
+ $main::log->msg ("Connecting to Bugzilla ($dbuser\@$dbhost)");
+
+ $bugzilla = DBI->connect (
+ "DBI:mysql:$dbname:$dbhost",
+ $dbuser,
+ $dbpass, {
+ PrintError => 0,
+ RaiseError => 1,
+ },
+ );
+
+ _checkDBError 'Unable to execute statement', 'Connect';
+
+ return $bugzilla;
+} # openBugzilla
+
+sub getBug ($;@) {
+ my ($bugid, @fields) = @_;
+
+ push @fields, 'short_desc' unless @fields;
+
+ my $statement = 'select ' . join (',', @fields) .
+ " from bugs where bug_id = $bugid";
+
+ my $sth = $bugzilla->prepare ($statement);
+
+ _checkDBError 'Unable to prepare statement', $statement;
+
+ _checkDBError 'Unable to execute statement', $statement;
+
+ $sth->execute;
+
+ return $sth->fetchrow_hashref;
+} # getBug
+
+sub getBugComments ($) {
+ my ($bugid) = @_;
+
+ my $statement = <<"END";
+select
+ bug_id,
+ bug_when,
+ substring_index(login_name,'\@',1) as username,
+ thetext
+from
+ longdescs,
+ profiles
+where
+ who = userid and
+ bug_id = $bugid
+END
+
+ my $sth = $bugzilla->prepare ($statement);
+
+ _checkDBError 'Unable to prepare statement', $statement;
+
+ $sth->execute;
+
+ _checkDBError 'Unable to execute statement', $statement;
+
+ my @comments;
+
+ while (my $comment = $sth->fetchrow_hashref) {
+ my $commentText = <<"END";
+The following comment was entered by [~$comment->{username}] on $comment->{bug_when}:
+
+$comment->{thetext}
+END
+
+ push @comments, $commentText;
+ } # while
+
+ return \@comments;
+} # getBugComments
+
+sub getRelationships ($$$$@) {
+ my ($table, $returnField, $testField, $relationshipType, @bugs) = @_;
+
+ $main::log->msg ("Getting $relationshipType");
+
+ my $statement = "select $returnField from $table where $table.$testField = ?";
+
+ my $sth = $bugzilla->prepare ($statement);
+
+ _checkDBError 'Unable to prepare statement', $statement;
+
+ my %relationships;
+
+ my %bugmap;
+
+ map {$bugmap{$_} = 1} @bugs unless %bugmap;
+
+ for my $bugid (@bugs) {
+ $sth->execute ($bugid);
+
+ _checkDBError 'Unable to exit statement', $statement;
+
+ my $result = JIRAUtils::findIssue ($bugid, %bugmap);
+
+ if ($result =~ /^Unable/) {
+ $main::log->warn ($result);
+
+ $main::total{'Missing JIRA Issues'}++;
+
+ undef $result;
+ } elsif ($result =~ /^Future/) {
+ $main::total{'Future JIRA Issues'}++;
+
+ undef $result;
+ } # if
+
+ my $jiraIssue = $result;
+ my $key = $jiraIssue || $bugid;
+
+ my @relationships;
+ my $relations = $sth->fetchall_arrayref;
+ my @relations;
+
+ map {push @relations, $_->[0]} @$relations;
+
+ for my $relation (@relations) {
+ $jiraIssue = JIRAUtils::findIssue ($relation);
+
+ if ($jiraIssue =~ /^Unable/ || $jiraIssue =~ /^Future/) {
+ $main::log->warn ($jiraIssue);
+
+ $main::total{'Missing JIRA Issues'}++ if $jiraIssue =~ /^Unable/;
+ $main::total{'Future JIRA Issues'}++ if $jiraIssue =~ /^Future/;
+
+ push @relationships, $relation;
+ } else {
+ push @relationships, $jiraIssue;
+ } # if
+ } # for
+
+ push @{$relationships{$key}}, @relationships if @relationships;
+ } # for
+
+ $main::total{$relationshipType} = keys %relationships;
+
+ return \%relationships;
+} # getRelationships
+
+sub getDependencies (@) {
+ my (@bugs) = @_;
+
+ return getRelationships (
+ 'dependencies', # table
+ 'dependson', # returned field
+ 'blocked', # test field
+ 'Depends on', # relationship
+ @bugs
+ );
+} # getDependencies
+
+sub getBlockers (@) {
+ my (@bugs) = @_;
+
+ return getRelationships (
+ 'dependencies',
+ 'blocked',
+ 'dependson',
+ 'Blocks',
+ @bugs
+ );
+} # getBlockers
+
+sub getDuplicates (@) {
+ my (@bugs) = @_;
+
+ return getRelationships (
+ 'duplicates',
+ 'dupe',
+ 'dupe_of',
+ 'Duplicates',
+ @bugs
+ );
+} # getDuplicates
+
+sub getRelated (@) {
+ my (@bugs) = @_;
+
+ return getRelationships (
+ 'bug_see_also',
+ 'value',
+ 'bug_id',
+ 'Relates',
+ @bugs
+ );
+} # getRelated
+
+sub getWatchers ($) {
+ my ($bugid) = @_;
+
+ my $statement = <<"END";
+select
+ profiles.login_name
+from
+ cc,
+ profiles
+where
+ cc.who = profiles.userid and
+ bug_id = ?
+END
+
+ my $sth = $bugzilla->prepare ($statement);
+
+ _checkDBError 'Unable to prepare statement', $statement;
+
+ $sth->execute ($bugid);
+
+ _checkDBError 'Unable to execute statement', $statement;
+
+ my @rows = @{$sth->fetchall_arrayref};
+
+ my %watchers;
+
+ for (@rows) {
+ if ($$_[0] =~ /(.*)\@/) {
+ $watchers{$1} = 1;
+ } # if
+
+ $main::total{'Watchers Processed'}++;
+ } # for
+
+ return %watchers;
+} # getWatchers
\ No newline at end of file