2010-08-02

CruiseControl with Maven2 & SVN on Ubuntu

CruiseControl is a great tool to automate builds; I use SVN and Maven2, so these are the steps I took to get it working. Anywhere you see HOSTNAME, replace it with the hostname of the machine on which CruiseControl is running; anywhere you see PROJECT1, replace it with the name of a Maven2 project.
  1. Download the binary distribution from the CruiseControl download page.
  2. Extract it to /opt. This creates the install directory, /opt/cruisecontrol-VERSION, which I'll call INSTALL.
  3. Add a new user under which CruiseControl will be run; pick whatever username you want, and keep it in mind.
    sudo adduser ccmaster
  4. Create the working directory structure. The base directory /var/lib/cruisecontrol I'll call WORK.
    mkdir -p /var/lib/cruisecontrol/artifacts
    mkdir /var/lib/cruisecontrol/logs
    mkdir /var/lib/cruisecontrol/projects
  5. Move config files to the working dir.
    mv INSTALL/config.xml INSTALL/dashboard-config.xml WORK
  6. The embedded Jetty server (for the dashboard, reporting) runs on port 8080, but I already have Tomcat on 8080, so I'm running it on port 8081. In order to do so, a few changes are needed. In INSTALL/cruisecontrol.sh, replace
    EXEC="$JAVA_HOME/bin/java $CC_OPTS -Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder -Dcc.library.dir=$LIBDIR -Djetty.logs=$JETTY_LOGS -jar $LAUNCHER $@ -jmxport 8000 -webport 8080 -rmiport 1099"
    echo $EXEC
    $JAVA_HOME/bin/java $CC_OPTS -Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder "-Dcc.library.dir=$LIBDIR" "-Djetty.logs=$JETTY_LOGS" -jar "$LAUNCHER" $@ -jmxport 8000 -webport 8080 -rmiport 1099 &
    
    with
    EXEC="$JAVA_HOME/bin/java $CC_OPTS -Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder -Dcc.library.dir=$LIBDIR -Djetty.logs=$JETTY_LOGS -jar $LAUNCHER $@ -jmxport 8000 -webport 8081 -rmiport 1099"
    echo $EXEC
    $JAVA_HOME/bin/java $CC_OPTS -Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder "-Dcc.library.dir=$LIBDIR" "-Djetty.logs=$JETTY_LOGS" -jar "$LAUNCHER" $@ -jmxport 8000 -webport 8081 -rmiport 1099 &
    
    For extra credit, make the webport a variable at the top of the script for easy modification.
    Next make the port change in INSTALL/etc/jetty.xml; replace
    <Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
    with
    <Set name="port"><SystemProperty name="jetty.port" default="8081"/></Set>
    Finally we need to set the dashboard URL, so add the following line to WORK/config.xml, just inside the cruisecontrol element:
    <dashboard url="http://HOSTNAME:8081/dashboard" />
  7. Checkout your project(s) to the CruiseControl projects dir we created earlier. Modify the SVN URL for your project as necessary.
    cd WORK/projects
    svn co http://HOSTNAME/svn/PROJECT1
  8. Add project configuration to WORK/config.xml This is a single project, but you can have any number of projects within the cruisecontrol element.
      <project name="PROJECT1" buildafterfailed="true">
        <listeners>
          <currentbuildstatuslistener
              file="logs/PROJECT1/status.txt" />
        </listeners>
    
        <!-- Bootstrappers are run every time the build runs,
            *before* the modification checks -->
        <bootstrappers>
        </bootstrappers>
    
        <!-- Defines where CruiseControl looks for changes, to decide
             whether to run the build -->
        <modificationset quietperiod="300">
          <svn localWorkingCopy="projects/PROJECT1" />
        </modificationset>
    
        <!-- Configures the actual build loop, how often and which
             build file/target -->
        <schedule interval="60">
          <maven2 
            mvnhome="/usr/share/maven2/" 
            pomfile="projects/PROJECT1/pom.xml"
            goal="clean | scm:update | package" />
        </schedule>
    
        <!-- directory to write build logs to 
             default: logs/[projectname] -->
        <log>
            <merge
               dir="projects/PROJECT1"
               pattern="TEST-*.xml" />
        </log>
    
        <!-- Publishers are run *after* a build completes -->
        <publishers>
          <artifactspublisher
            file="projects/PROJECT1/target/PROJECT1.war"
            dest="artifacts/PROJECT1" />
        </publishers>
      </project>
    Using the Maven2 goal scm:update requires that SCM info be included in your pom.xml file; something like the following within the project element should work, but again, modify the SVN URL as necessary:
        <scm>
            <connection>scm:svn:http://HOSTNAME/svn/PROJECT1/</connection>
            <developerConnection>scm:svn:http://HOSTNAME/svn/PROJECT1/</developerConnection>
        </scm>
  9. Make sure the INSTALL and WORK dirs are owned by your CruiseControl user:
    sudo chown -R ccmaster:ccmaster INSTALL WORK
  10. Setup the init script for startup and shutdown. The following was taken from the CruiseControl wiki and modified for my directory structure, CruiseControl user, Jetty port, and JAVA_HOME, and should be placed in /etc/init.d/cruisecontrol.
    #!/bin/sh
    #content of /opt/cruisecontrol/init script
    # chkconfig: 345 99 05
    # description: CruiseControl build loop (see /home/tools)
    
    # CruiseControl Unix Startup Script Version 2.1
    #
    # based on http://confluence.public.thoughtworks.org/display/CC/UnixStartupScriptVersion1.x
    # adapted for multiple projects
    # also based on the file attached to the above page created by Jerome Lacoste
    
    #
    # CruiseControl startup: Startup and kill script for Cruise Control
    #
    
    ###################################################################################################
    # USER CONFIGURATION
    #
    # Fill in these values for your Cruise Control setup
    
    # What user will Cruise Control run as?  The user will need permission to write and modify files
    # in the next entries.
    CC_USER=ccmaster
    
    # Where is the CC startup script located?
    CC_INSTALL_DIR=/opt/cruisecontrol-bin-2.8.3
    
    # In what directory is the config.xml file located for CC?
    # default: CC_WORK_DIR=$CC_INSTALL_DIR
    CC_WORK_DIR=/var/lib/cruisecontrol
    
    # Where will the cruisecontrol.log file be located?
    # default: CC_LOGFILE_DIR=$CC_INSTALL_DIR
    CC_LOGFILE_DIR=$CC_WORK_DIR
    
    #######################
    # ENVIRONMENT ADDITIONS
    
    # Add environement variables here that are needed by your build.
    # example:
    #  export JAVA_HOME=/usr/local/java
    #
    # or like this for local variables ONLY used in this file:
    #  JAVA_HOME=/usr/local/java
    
    export JAVA_HOME=/usr/lib/jvm/java-6-sun/
    
    # Add path to additional executables needed for project build.  See PATH entry below for base config.
    # No additional action taken when blank.
    PATH_ADDITIONS=
    
    ##############################
    # CRUISE CONTROL PORT SETTINGS
    
    # Port for Jetty reporting application.  You can access it by going to http://localhost:8080
    # default CC_WEBPORT=8080
    CC_WEBPORT=8081
    
    # JMX port for webapp and Java Management eXtensions (JMX).  You can access it by going to http://localhost:8080
    # Change only if this port is in use as the webapp will also need modification.
    # default CC_JMXPORT=8082
    CC_JMXPORT=8082
    
    # RMI port for control via Java's Remote Management Interface (RMI)
    # Leave blank to disable.
    CC_RMIPORT=
    
    ###################################################################################################
    # DO NOT MODIFY ENTRIES BELOW THIS LINE
    
    NAME=cruisecontrol
    DESC="CruiseControl - continuous integration build loop"
    
    PATH=/sbin:/usr/sbin:/usr/bin:/bin
    # add additions if variable has text defined
    if [ -n "$PATH_ADDITIONS" ]; then
        PATH=$PATH_ADDITIONS:$PATH
    fi
    export PATH
    
    CC_DAEMON=$CC_INSTALL_DIR/cruisecontrol.sh
    
    CC_CONFIG_FILE=$CC_WORK_DIR/config.xml
    
    CC_LOG_FILE=$CC_LOGFILE_DIR/cruisecontrol.log
    
    CC_COMMAND="$CC_DAEMON -configfile $CC_CONFIG_FILE -webport $CC_WEBPORT -jmxport $CC_JMXPORT -rmiport $CC_RMIPORT"
    
    # overwrite settings from default file
    if [ -f /etc/default/cruisecontrol ]; then
      . /etc/default/cruisecontrol
    fi
    
    # does the executable exist?
    test -f $CC_DAEMON || (echo "The executable $CC_DAEMON does not exist!" && exit 0)
    
    if [ `id -u` -ne 0 ]; then
            echo "Not starting/stopping $DESC, you are not root."
            exit 4
    fi
    
    # Get the PID output from the startup script
    if [ -f $CC_WORK_DIR/cc.pid ]; then
            CC_PID=`cat $CC_WORK_DIR/cc.pid`
    else
            echo "No cc.pid file found.  CC process may not be controllable from this script!"
    fi
    
    case "$1" in
    
      'start')
        cd $CC_WORK_DIR
        #echo "CC environtment at startup" > cc.startup.env
        #env >> cc.startup.env
        su $CC_USER -c "/bin/sh -c \"$CC_COMMAND >> $CC_LOG_FILE 2>&1\"" & RETVAL=$?
        echo "$NAME started with jmx on port ${CC_JMXPORT}"
        ;;
    
      'stop')
        if [ -n "$CC_PID" ] && ps -p ${CC_PID} > /dev/null ; then
          kill -9 ${CC_PID}
          sleep 5
          $0 status
          RETVAL=$?
        else
          echo "$NAME is not running"
          RETVAL=1
        fi
        ;;
    
      'status')
        if [ -n "$CC_PID" ] && ps -p ${CC_PID} > /dev/null ; then
          echo $NAME \(pids $CC_PID\) is running
          RETVAL=0
        else
          echo "$NAME is stopped"
          RETVAL=1
        fi
        ;;
    
      'restart')
        $0 stop && $0 start
        RETVAL=$?
        ;;
    
      *)
        echo "Usage: $0 { start | stop | status | restart }"
        exit 1
        ;;
    esac
    #echo ending $0 $$....
    exit 0;
  11. Make the init script executable:
    sudo chmod 755 /etc/init.d/cruisecontrol
  12. Add CruiseControl to the default runlevel so that it starts on boot.
    sudo update-rc.d cruisecontrol defaults
  13. Start it up!
    /etc/init.d/cruisecontrol start
Check /var/lib/cruisecontrol.log for exceptions.

No comments:

Post a Comment