Phing, Xinc and Nabaztags

Finally got around to setting up continuous integration for some of the projects that comprise the day-job. We’re using the PEAR package Xinc, which has proved to be excellent thus far - especially as it integrates so well with my deployment tool of choice: Phing. Part of the fun in setting it up was looking for suitable feedback mechanisms or devices. Email notifications are a given but there are a range of more interesting feedback mechanisms available such as toolbar notifications, remote-controlled lava lamps, or plain humiliation tactics (such as making the person who broke the build wear the dunce’s hat till it is fixed). By a strange twist of fate there happened to be an unused Nabaztag in the office: a strange Rabbit-like fellow able to play sounds, move its ears and activate a selection of brightly colours LEDs contained in its body. Nabaztags are controlled through a simple HTTP web-service, with the various actions been specified by GET requests using a simple API.

Out of the box, Xinc only provides email notifications for feedback but its design is such that plugins are easy to create. Indeed, Raphael Stolt has written recently on creating a publisher that uses the Growl notifications native to Macs. A natural extension to this would be to create an Linux version, given the inclusion of libnotify in the latest Ubuntu release. That’s not for today though.

The true flexibility in Xinc comes from the phingpublisher publisher, which allows an arbitrary target to be called from a phing script. Rather than create a Xinc plugin for the Nabaztag, writing a Phing task seemed to offer more flexibility as it could then be used in deployment scripts elsewhere.

I’ve previously created a couple of simple phing tasks for updating a Twitter status, and interacting with the Unfuddle API. Creating a Nabaztag task was just a simple extension of these cURL-based tasks. The various attributes mirror those from the API docs.

  Name                Type      Description                                         Default   Required
  ------------------- --------- --------------------------------------------------- --------- ----------
  serialNum           String    Serial number                                       n/a       Yes
  token               Integer   Token number                                        n/a       Yes
  leftEarPosition     String    Position of the left ear (0-16)                     n/a       No
  rightEarPosition    String    Position of the right ear (0-16)                    n/a       No
  message             String    Message.                                            n/a       No
  messageId           Integer   Message id.                                         n/a       No
  voice               Integer   Voice to use (use the API to fetch the full list)   n/a       No
  choreography        String    A string which prescribes the choreography
                                to use (see API docs)                               n/a       No
  choreographyTitle   Boolean   Choreography title                                  n/a       No
  urlList             Boolean   List of URLs to pass to the Nabaztag (can be
                                used for playing audio files)                       n/a       No
  checkReturn         Boolean   Whether to check the return code of the request,
                                throws a BuildException if the update fails         false     No

The code for this task can be found in my github repo - to install locally, export the file to a local phing tasks folder (I use /usr/share/php/phing/tasks/my on my Ubuntu machine). Having done that, a simple example build.xml file to exercise the task would be:

<?xml version="1.0" ?>
<project name="Example Nabaztag update" basedir=".">
    <taskdef name="nabaztag" classname="phing.tasks.my.NabaztagTask" />
    <target name="build-failure">
        <nabaztag serialNum="${nabaztag.serialNum}" token="${nabaztag.token}" message="The build failed!" voice="US-Liberty" />
    </target>
</project>

To use this with Xinc, you simply need to called the appropriate target from your project configuration file. Another toy example:

<?xml version="1.0"?>
<xinc>
    <project name="Toy example">
        <configuration>
                <setting name="loglevel" value="1"/>
                <setting name="timezone" value="Europe/London"/>
        </configuration>
        <property name="dir" value="/var/xinc/projects/sample"/>
        <cron timer="*/15 * * * *"/>
        <modificationset>
            <svn directory="${dir}" update="true" />
        </modificationset>
        <builders>
                <phingBuilder buildfile="${dir}/build.xml" target="build-project"/>
        </builders>
        <publishers>
            <onfailure>
                <phingpublisher buildfile="${dir}/build.xml" target="build-failure" />
            </onfailure>
        </publishers>
    </project>
</xinc>

Some of the options for controlling the Nabaztag are only available with the V2 version. The one on my desk is V1 and so I haven’t tested every action, I’ve just followed the instructions in the API docs. Unfortunately, the Nabaztag webservice isn’t as RESTful as would be desired - it returns a 200 response code for every request, whether it fails or not. This makes it a touch tricky to handle failed updates.

Nabaztags are also useful for general reminders - I have the following line in my crontab:

15 18 * * 5 curl "http://api.nabaztag.com/vl/FR/api.jsp?sn=$SERIAL&token=$TOKEN&tts=It+is+now+time+to+go+to+the+pub"
——————

Something wrong? Suggest an improvement or add a comment (see article history)
Tagged with: phing
Filed in: tips

Previous: Ingenious use of an anonymous function
Next: Inspecting Javascript objects

Copyright © 2005-2024 David Winterbottom
Content licensed under CC BY-NC-SA 4.0.