Skip navigation.

Ramblings

a test …

Bugzilla crawling on IRC

, , , ,

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.

Open source seminar in OsloThe latest development about web technologies

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies

Download Opera, the fastest and most secure browser
January 2010
M T W T F S S
December 2009February 2010
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31