Login   I   Sitemap   I   Contact Us   I   Sales: (US) 1-866-468-5210   (EU) +49-711-67400677
Intland Software - Collaboration Begins Here
Download or Try the fully functional version of codeBeamer. It's free, simple and secure.
codeBeamer is the award winning Collaborative Application Lifecycle Management (ALM) solution for distributed software development.
Project management, wiki, document management, issue tracking, ITIL, continuous integration, version control, source code analysis and forums.

Links

Feeds

Editor Menu

JavaForge: Remote Build- and Deploy Automation using Groovy

Repetitive tasks are boring, especially if they take long. And since they are boring, they are inherently error prone. A typical example is a long and complicated build procedure that is performed manually every time. This is where programmatic automation enters the game to accelerate builds, and to reduce costs and errors.

Olaf Davidson of the U.S. Department of Agriculture shows us how his project hosted at JavaForge solves a fairly complicated build scenario with a surprisingly concise script. The script itself is written in Groovy, an alternative language that runs on the JVM, and the solution relies on the Groovy Codebeamer Scripting framework, also maintained by Olaf.

The actual script does the followings:

  1. Checks the need for a build
  2. Performs the build (locally)
  3. Changes the item status
  4. Creates a new 'milestone' item
  5. Uploads the build product to the Document Manager
  6. Attaches the build product and build process output to the milestone item
  7. Tags the source code repository
  8. Associates the fixed bugs and implemented features to the milestone build
  9. Posts a notification
Sounds pretty familiar, huh? Although the script included here is primarily for inspiration, you can easily implement your own build procedure, based on the same idea. Plus, an alternative use of this could be relocating your builds to an external server or servers, thus offloading the one that hosts your codeBeamer instance.

One more note: Groovy might not be your cup of tea, but this should not stop you. At the end, all you need is a client application written in your favourite language, accessing the codeBeamer remote API. The primary bindings for the API are Java and C#, but some of our customers have successfully implemented remote clients in PHP and C/C++, too.

package ngmfbuild

import cbscript.*
import static cbscript.CB.*

def SVN = "c:/cygwin/bin/svn.exe"
def ANT = "c:/java/apache-ant-1.7.1/bin/ant.bat"
def SVN_URL = "http://svn.javaforge.com/svn/oms"

def ms = "3.0.11"
def qstatus = "Ready"
def dry = false

println "Login JF/OMS..."
def jf = CB.login("http://javaforge.com/remote-api", "odavid", new
File("c:/tmp/jfpass").text)
def prj = jf.projects.find{ it.name == "Object Modeling System" }

println "Query bugs and tracker ..."
// query for candidates: fixed bugs

def readyBugs = prj.trackers.find {it.name == "Bugs"}.issues.findAll {
    it.status == qstatus
}

// query for candidates in Feature requests
def readyFeatures = prj.trackers.find {it.name == "Features"}.issues.findAll {
    it.status == qstatus
}

// combine all features and bugs into one single list
def readyList = readyBugs + readyFeatures

println "There are ${readyList.size} bug fixes/new features ready for
the build..."
if (!readyList.empty) {    // or require a minimum number of fixes/feature
    println " Bugs:"
    readyBugs.each{println "   ${it.id} -  ${it.summary}"}
    println " Features:"
    readyFeatures.each{println "   ${it.id} -  ${it.summary}"}


    println "Building ngmf.all ..."
    StringBuffer stdout = new StringBuffer()
    StringBuffer stderr = new StringBuffer()
    p = "${ANT} -Doms.version=${ms} -f c:/od/projects/ngmf.all/build.xml clean jar".execute()
    p.consumeProcessOutput(stdout, stderr)
    p.waitFor()
    if (p.exitValue()) {
        println "ERROR !!!!!!!!!!!!!"
        println stderr
        return
    }

    println "Branding Console with ${ms}"
    replaceVar(new File("C:/od/projects/ngmf.dcon/src/ngmfcon/resources/ConApp.properties"), ms)

    println "Building ngmf.con ..."
    stdout = new StringBuffer()
    stderr = new StringBuffer()
    p = "${ANT} -f c:/od/projects/ngmf.con/build.xml clean jar".execute()
    p.consumeProcessOutput(stdout, stderr)
    p.waitFor()
    if (p.exitValue()) {
        println "ERROR !!!!!!!!!!!!!"
        println stderr
        return
    }

    // dry run is done here.
    if (dry) {
        println "DRY RUN, STOP HERE !!!!!!!!!!!!!!!"
        jf.logout();
        return
    }

    // commit new release About
    println "Committing Branding ..."
    svn = """${SVN} ci "../ngmf.dcon/src/ngmfdcon/resources/NgmfdconApp.properties" -m 'Branding ${ms}'""".execute()
    tag_out = svn.text.trim()
    tag_err = svn.err.text
    println tag_out
    println tag_err

    // tag the whole trunk
    println "Tagging ${SVN_URL}/tags/${ms} ..."
    svn = "${SVN} copy ${SVN_URL}/trunk ${SVN_URL}/tags/${ms} -m 'tagged ${ms}'".execute()
    tag_out = svn.text.trim()
    tag_err = svn.err.text

    String info = "!!!Milestone ${ms} Build Info \n" +
            "; __Build Process Exit Status__: ${p.exitValue()} (see attachments for details)\n" +
            "; __SVN Tag URL__: " +
            "[tags/${ms}|http://javaforge.com/proj/sources/sccBrowse.do?proj_id=1781&dirname=tags/${ms}] " +
            "(external: [${SVN_URL}/tags/${ms}])\n" +
            "; __SVN Log__: " +
            "[${tag_out}|http://javaforge.com/proj/sources/sccFileLog.do?proj_id=1781&filename=tags%2F${ms}&isDir=true]"

    println "Creating new Milestone Item ${ms} ... "
    def mt = prj.trackers.find {it.name == "Milestones"}
    def milestone = mt.submit(summary:ms, text:info, priority:NORMAL)
    //
    println "  Attaching build output  ... "
    milestone.attach(name:"stdout.txt", content:stdout.toString(), text:"Build output.")
    println "  Attaching build product ... "
    milestone.attach(name:"oms-"+ms+".zip", file:"c:/od/projects/ngmf.all/oms3.zip", text:"OMS Zip Distribution.")

    println "  Uploading to documents ... "

    // copy the build to documents
    doc = prj.artifact("Releases/v3/oms-"+ms+".zip")
    doc << new File("c:/od/projects/ngmf.all/oms3.zip")
    //
    println "Associating all bugs/features to the new milestone ..."
    readyList.each{ task -> milestone.relate(task, RELATED) }

    println "Closing related bugs/features ..."
    readyList.each{ it.status = "Closed" }

    println "Spreading the news ..."
    def news = prj.forums.find {it.name == "News"}
    news.post(subject:"Milestone Release: " + ms, text:"Milestone details : " + CB.link(milestone));
} else {
    println " Nothing is ready for build."
}

println "Logout ..."
jf.logout();

def replaceVar(File file, String val) {
    file.text = file.text.replaceAll(/(Application.version = )\S+/, "\$1$val")
}

Comments:

Post a Comment:
Comments are closed for this entry.