Bugzilla crawling on IRC
Tuesday, October 17, 2006 6:29:23 AM
Sometimes when you are working with a bug tracking system you want to see the bugs as they appear or heavy changes are done. This was the case with me and a project I'm working on and without finding anyone else having done the same I took the challenge.
The goal was to show new bugs appearing and changes done to them in an IRC channel. I had already an eggdrop bot running there and I needed to somehow connect Bugzilla with it.
1. I started out by adding a QA contact in bugzilla which gets all new bugs and changes done to them.
2. Then I had to configure exim4 to send email received to a script that could communicate with eggdrop. As it turned out, I simply let the script add each mail message as a file in an explicit catalogue.
Exim config: /etc/exim4/exim4.conf.template
bugs_router:
driver = accept # accept the mail
# the following two lines makes it get email sent to bugzilla@bugs.domain.com
local_parts = bugzilla # username it should answer to
domains = bugs.domain.com # which domain it should answer to
senders = bugzilla-daemon@bugzillahost.com # Only mail sent from bugzilla
transport = bugs_transport # which transport should take care of the mail
# ...
bugs_transport:
driver = pipe # pipe the mail content to a command
command = /home/bugsuser/scripts/bugzillahandler.pl
user = bugsuser # run as this user
group = bugsuser
return_output # fail on output
log_output
Then the script that puts the mail messages in individual files looked like this:
/home/bugsuser/scripts/bugzillahandler.pl:
#!/usr/bin/perl
use strict;
use warnings;
my $ts = time();
if (open(my $out, ">", "/var/log/bugzillahandler/$ts")) {
local $/;
print $out (<>);
close($out) or die "Cannopt close $ts: $!";
} else {
die "cannot open $ts for >: $!";
}
3. Now the eggdrop has to get these files somehow and I add a timer based part that runs whenever the eggdrop is online in a script file included in the eggdrop:
# this code basically calls a perl script every 60 seconds
# and outputs its output to the channel
set interval 60
set channel "#bugsoutput"
# delete existing timers
foreach t [utimers] {
if {[lindex $t 1] == "checkbugzilla"} {
killutimer [lindex $t end]
}
}
# set up a new timer
set bugzillatimer [utimer $interval checkbugzilla]
# function that is called
proc checkbugzilla {} {
global interval channel
set ret "[exec /home/bugsuser/eggdrop/scripts/perl/checkbugzilla.pl]"
if {$ret != 0} {
set lines [split "$ret" "\n"]
foreach line $lines {
# output each line as one line to the irc channel
putquick "NOTICE $channel :$line"
}
}
# set up next call
set bugzillatimer [utimer $interval checkbugzilla]
}
4. Finally the perl script that parses the files and outputs them in a nice fashion, one line per bug that has appeared since last time.
/home/bugsuser/eggdrop/scripts/perl/checkbugzilla.pl:
#!/usr/bin/perl
# get all the files that have changed since last time we checked (1 minute)
$files = `find /var/log/bugzillahandler -mmin -1 \! -type d`;
foreach $file (split/\n/,$files) {
if(open(IN,$file)) {
# open the file and read out its content.
my $content;
while(<IN>) {
$content .= $_;
}
close(IN);
# do some crude pattern matching to get out info about new bugs
# and bugs that have changed to or from RESOLVED state.
($head, $body) = split(/\n\n/,$content,2);
$head =~ /^Subject:\s*(.*)$/mgi;
$subject = $1;
$subject =~ /\[Bug (\d+)\]/mgi;
$bugnum = $1;
$subject =~ s/\s*\[.*?\]\s*//mgi;
$subject = trim($subject);
if ($subject =~ /New/mgi) {
$body =~ /Product: (.*?)\s*$/mgi;
$product = $1;
$body =~ /Component: (.*?)\s*$/mgi;
$component = $1;
$body =~ /ReportedBy: (.*?)\s*$/mgi;
$reporter = $1;
$out .= "[Bug $bugnum] $subject <$product/$component> ($reporter)".
" | http://bugzillahost.com/bugzilla/show_bug.cgi?id=$bugnum\n";
} elsif ($body =~ /Status\|([^\|]+?)\|([^|]+?)$/mgi) {
$from_status = trim($1);
$to_status = trim($2);
$resolution = "";
if ($body =~ /Resolution\|([^\|]+?)\s*\|([^|]+?)\s*$/mgi) {
$from_resolution = trim($1);
$to_resolution = trim($2);
if ($to_status eq "RESOLVED") {
$resolution = "$to_resolution: ";
}
}
# populate output buffer
$out .= "[Bug $bugnum] $to_status: $resolution$subject".
" | http://bugzillahost.com/bugzilla/show_bug.cgi?id=$bugnum\n";
}
}
}
# if there is no output print out a single "0" to let
# the eggdrop part know it shouldn't do anything.
if ($out ne "") {
print $out;
} else {
print "0";
}
exit(0);
sub trim($) {
# remove whitespaces in front and behind a string
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
5. Voilá, a bot that outputs bug information automatically.
07:45 [Bug 1234] New: There is an error <Coffemaker/filter_obj> \
(reporter@customer.com) | http://bugzillahost.com/bugzilla/show_bug.cgi?id=1234
Most of the scripts are kind of patchwork evolved while experimenting. They could all have been smaller and smarter, and also fewer steps. However, this solution worked and I didn't feel like fixing it. (If it works don't fix it).
If you want to suggest improvements I'm all ears though. Hopefully some of you will find this useful. I felt I had to write it down somewhere at least so that next time I need to add something I don't have to go back and decipher it.














