Bug management with NARVAL's Bugnicar 0.9 module

Nicolas CHAUVAT

Alexandre FAYOLLE

Bruno VAN FRACHEM


Table of Contents

Install and setup
Using Bugnicar
Execution of Bugnicar
Creating the database
Using emails
Using a web interface
Here is the corresponding state-machine

Abstract

This HOW-TO explains how to use NARVAL's Bugnicar 0.9 module to manage bugs and patches for a project, using e-mail or web forms.

Install and setup

Download the Bugnicar tarball and unpack it. You will get a bugnicar-0.9/ directory, that will be refered to as BUG_HOME in this document.

We will use the memory file for NARVAL located at BUG_HOME/data/bugnicar-memory.xml; you need to edit it to enter your settings.

From a shell, launch python, and import the AccessControl module which is in BUG_HOME/modules/. Run AccessControl.compile_password('turlututu'). Copy the resulting string in the password attribute associated to a "bugnicar" login as shown below:

<memory>
...
<access-control-list>
    <access-control-item login='bugnicar' password='result-of-turlututu'/>
</access-control-list>
</memory>

In order to operate without risk, I added the following lines to my .procmailrc and assigned this mailbox to Bugnicar by setting the path attribute of the mailbox element.

:0:
* ^Subject: \[BUGNICAR\]
mail/bugnicar

and

<memory>
...
  <mailbox path='/home/nico/mail/bugnicar'/>
...
<memory>

Using Bugnicar

Execution of Bugnicar

The ~/bin/bugnicar.sh script could look like:

#!/bin/sh
cd ~/Narval
export PYTHONPATH=~/Narval
python narval/Engine.py --home ~/bugnicar-0.9/ \
    --start-plan "email.Mail_Sensor" \
    --start-plan "bugnicar.Catch-mail" \
    --start-plan "bugnicar.Task-process" \
    --load-memory-file ~/bugnicar-0.9/data/bugnicar-memory.xml \
    --socket-manager $1

using BUG_HOME equal to ~/bugnicar-0.9/.

Launching ~/bin/bugnicar.sh --debug from the command enables testing the recipe. The result of the recipe should appear in BUG_HOME/data/bugnicar.html. This file can be regenerated by applying an XSL Transformation on BUG_HOME/data/bugnicar-database.xml; a sample transformation is BUG_HOME/transforms/Bugnicar/bug2htmlreport.xslt.

Creating the database

Bugnicar writes the bug database in the file BUG_HOME/data/bugnicar-database.xml. To create a new database just replace this file with the string <bugnicar-database/>. You can specify at this time the name of your project and the URL of its homepage with this second string: <bugnicar-database project='Narval' url='http://www.logilab.org/narval/'/>.

This new version of Bugnicar allows more commands for managing bugs than the previous one, and so uses a different format for saving its database. If you were already managing your bugs with Bugnicar 0.1, change the current directory to BUG_HOME and use the following commands to convert your base to the new format:

  mv data/bugnicar-database.xml data/bugnicar-database.xml.old

  4xslt data/bugnicar-database.xml.old extensions/bugnicar-convert-database.xslt \
    > data/bugnicar-database.xml
  

Using emails

To insert a new bug to the database, you just have to send an email with the subject looking like [BUGNICAR] bug report about foo and with the details in the body of the message.

To add a comment to the bug report #1, you must send a mail with subject [BUGNICAR] bug comment 1 and with your observation in the body of the mail.

To change the 'about' field for the bug #1, you must send a mail with subject [BUGNICAR] bug set 1 pass turlututu about other foo, and you can join a comment in the body of the mail. This command needs the admin password to work, here it is turlututu.

To assign the bug #1 to somebody (identified by an email address), you must send a mail with subject [BUGNICAR] bug assign 1 pass turlututu to somebody@somewhere.org , and you can join a comment in the body of the mail. This command needs the admin password to work.

To close the bug #1 which has been fixed, send a mail with subject [BUGNICAR] bug close 1 pass turlututu and details in the body of the mail. This command needs the admin password to work.

To reopen the bug #1 which has been closed, send a mail with subject [BUGNICAR] bug reopen 1 pass turlututu and details in the body of the mail. This command needs the admin password to work.

Using a web interface

Now you can use Bugnicar with a web interface for listing the bug reports and sending commands; then NARVAL will recept HTTP requests instead of emails. A sample interface using HTML and PHP3 is located at BUG_HOME/data/bugnicar/.

To fit the interface to your system, change directory to BUG_HOME/data/bugnicar/ and execute the following script, where MACHINE must be replaced by the name of the server where NARVAL is running; it will write the right URL in the forms.

  #!/bin/sh
  my_machine=MACHINE
  for i in `ls *.php3`
  do a=`cat $i`;
     printf "$a" | sed "s/action=\"http:\/\/.*:/action=\"http:\/\/$my_machine:/g" > $i
  done
  

Here is the corresponding state-machine

<?xml version="1.0"?>

<state-machine xmlns:xupdate="http://www.xmldb.org/xupdate" name="buggy">
 <object nodename="bug">
  <storage type="plain-file" uri="$NARVAL_HOME/data/bugnicar-database.xml">
   <location>/bugnicar-database</location>
  </storage>
  <get-object-from-storage>
   <event>
    <element called="operation" nodename="bugnicar-task">
     <match>@for</match>
     <match>not(bug-report)</match>
    </element>
   </event>
   <query>@id = #operation#/@for</query>
  </get-object-from-storage>
 </object>

 <!-- States declaration -->

 <state id="not-assigned">
  <description>
   <match>@state = 'not-assigned'</match>
  </description>
 </state>


 <state id="assigned">
  <description>
   <match>@state = 'assigned'</match>
  </description>
 </state>


 <state id="fixed">
  <description>
   <match>@state = 'fixed'</match>
  </description>
 </state>

 <!-- Initialization declaration -->

 <transition type="init" id="add-new" out="not-assigned">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>bug-report</match>
   </element>
  </event>
  <actions>
   <create-object>
    <xupdate:attribute name="id">
     <xupdate:value-of select="position()"/>
    </xupdate:attribute>
    <xupdate:attribute name="state">not-assigned</xupdate:attribute>
    <xupdate:element name="label">
     <xupdate:value-of select="#operation#/about/text()" />
    </xupdate:element>
    <xupdate:element name="report-info">
     <from><xupdate:value-of select="#operation#/bug-report/@sender" /></from>
     <date><xupdate:value-of select="#operation#/bug-report/@date" /></date>
     <description><xupdate:value-of select="#operation#/text()" /></description>
    </xupdate:element>
    <xupdate:element name="comments" />
   </create-object>
  </actions>
 </transition>


 <!-- Destroy declaration -->
 <transition type="destr" id="remove" in="any">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>remove</match>
   </element>
  </event>
  <actions>
   <xupdate:remove select="#object#" />
  </actions>
 </transition>


 <!-- Transitions declaration -->

 <transition id="set-label-not-assigned" in="not-assigned" out="not-assigned">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>set-label</match>
   </element>
  </event>
  <actions>
   <xupdate:remove select="#object#/label"/>
   <xupdate:element name="label">
    <xupdate:value-of select="#operation#/about/text()" />
   </xupdate:element>
  </actions>
 </transition>

 <transition id="set-label-assigned" in="assigned" out="assigned">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>set-label</match>
   </element>
  </event>
  <actions>
   <xupdate:remove select="#object#/label"/>
   <xupdate:element name="label">
    <xupdate:value-of select="#operation#/about/text()" />
   </xupdate:element>
  </actions>
 </transition>

 <transition id="set-label-fixed" in="fixed" out="fixed">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>set-label</match>
   </element>
  </event>
  <actions>
   <xupdate:remove select="#object#/label"/>
   <xupdate:element name="label">
    <xupdate:value-of select="#operation#/about/text()" />
   </xupdate:element>
  </actions>
 </transition>

 <transition id="add-comment" in="not-assigned" out="not-assigned">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>bug-comment</match>
   </element>
  </event>
  <actions>
   <modify-object>
    <xupdate:append select="#object#/comments">
     <xupdate:element name="comment">
      <xupdate:attribute name='from'><xupdate:value-of select="#operation#/bug-comment/@sender" /></xupdate:attribute>
      <xupdate:attribute name='date'><xupdate:value-of select="#operation#/bug-comment/@date" /></xupdate:attribute>
       <xupdate:value-of select="#operation#/text()" />
     </xupdate:element>
    </xupdate:append>
   </modify-object>
  </actions>
 </transition>


 <transition id="add-comment-when-assigned" in="assigned" out="assigned">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>bug-comment</match>
   </element>
  </event>
  <actions>
   <modify-object>
    <xupdate:append select="#object#/comments">
     <xupdate:element name="comment">
      <comment>
       <xupdate:attribute name='from'><xupdate:value-of select="#operation#/bug-comment/@sender" /></xupdate:attribute>
       <xupdate:attribute name='date'><xupdate:value-of select="#operation#/bug-comment/@date" /></xupdate:attribute>
       <xupdate:value-of select="#operation#/text()" />
      </comment>
     </xupdate:element>
    </xupdate:append>
   </modify-object>
  </actions>
 </transition>


 <transition id="assign" in="not-assigned" out="assigned">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>bug-assign</match>
    <match>@password</match>
   </element>
  </event>
  <actions>
   <modify-object>
    <xupdate:append select="#object#">
    <xupdate:attribute name="state">assigned</xupdate:attribute>  
     <xupdate:element name="worker">
      <xupdate:attribute name="id"><xupdate:value-of select="#operation#/worker-id/text()" /></xupdate:attribute>
      <xupdate:attribute name='date'><xupdate:value-of select="#operation#/bug-assign/@date" /></xupdate:attribute>
     </xupdate:element>
    </xupdate:append>
   </modify-object>
  </actions>
 </transition>


 <transition id="unassign" in="assigned" out="not-assigned">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>bug-unassign</match>
    <match>@password</match>
   </element>
  </event>
  <actions>
   <modify-object>
    <xupdate:append select="#object#">
     <xupdate:attribute name="state">not-assigned</xupdate:attribute>  
    </xupdate:append>
    <xupdate:remove select="#object#/worker"/>
   </modify-object>
  </actions>
 </transition>


 <transition id="change-assignment" in="assigned" out="assigned">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>bug-assign</match>
    <match>@password</match>
   </element>
  </event>
  <conditions>
   <match-cond>#operation#/worker-id/text()</match-cond>
  </conditions>
  <actions>
   <modify-object>
    <xupdate:remove select="#object#/worker"/>
   </modify-object>

   <modify-object>
    <xupdate:append select="#object#">
     <xupdate:element name="worker">
      <xupdate:attribute name="id"><xupdate:value-of select="#operation#/worker-id/text()" /></xupdate:attribute>
      <xupdate:attribute name='date'><xupdate:value-of select="#operation#/bug-assign/@date" /></xupdate:attribute>
     </xupdate:element>
    </xupdate:append>
   </modify-object>
	
  </actions>
 </transition>


 <transition id="close-bug" in="assigned" out="fixed">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>bug-close</match>
    <match>@password</match>
   </element>
  </event>
  <actions>
   <modify-object>
    <xupdate:append select="#object#">
    <xupdate:attribute name="state">fixed</xupdate:attribute>
    <xupdate:attribute name='date'><xupdate:value-of select="#operation#/bug-close/@date" /></xupdate:attribute>
    </xupdate:append>
   </modify-object>
	
  </actions>
 </transition>



 <transition id="reopen-bug" in="fixed" out="assigned">
  <event>
   <element called="operation" nodename="bugnicar-task">
    <match>bug-reopen</match>
    <match>@password</match>
   </element>
  </event>
  <actions>
   <modify-object>
    <xupdate:append select="#object#">
     <xupdate:attribute name="state">assigned</xupdate:attribute> 
    </xupdate:append>
   </modify-object>
	
  </actions>
 </transition>


</state-machine>