Showing posts with label RSS feed parsing. Show all posts
Showing posts with label RSS feed parsing. Show all posts

Thursday, February 4, 2010

Forget Part 1 - done right Groovy don't need a part 2

I had put this project on the shelf for time. New solution is half the code, requires only the one script file, and does even more.
Groovy's so flexible I can see where this could be condensed further, but then I'd have to double the comments to remember what it's doing next time I go to modify it.

def cruiseServer = 'http://build.server.com:9000'
def uploaddir = "user@123.123.123.123:/path/to/deployment/dir"
def downloaddir = 'D:\\localbuild\\downloaddir\\'

def rssPath = '/cruisebuild/rss/'
def artifactPath = '/cruisecontrol/artifacts'

//The common list of assets to download. With this list structure I can just comment out
// any asset to skip over each release or do the full download. Also can control if I want latest
// and greatest or a specific tested version.
def projects = [
//['comment out', 'assets not needed', 'latest'],
['Build-Project1', 'assetname.ear', 'latest'],
['Build-Project2', 'assestname.war', '12.12.1002']
]
//for the identified collection, do the download
projects.each() { project, ear, version ->
//get rss feed into a navigable object
def rssFeed = new XmlParser().parse( cruiseServer + rssPath + project).channel[0]
//get either the latest good build OR a specific version number
def passeditem
if ('latest'.equals(version) {
passeditem = rssFeed.item.find{ it.description.text() == 'Build passed' }
} else {
passeditem = rssFeed.item.find{ it.link.text() =~ version )
}
//link in RSS feed goes to the cruisebuild details, but what I need is asset download path.
def link = passeditem.link.text()
//reprocess the build number from link based on regex pattern for 4 sets digits w/ dot separator.
def buildMatcher = ( link =~ /\d+[.]\d+[.]\d+[.]\d+/ )
def buildNo = buildMatcher[0]
//Then the crucial info is the cruisebuild ID 14 digit number
def matcher = ( link =~ /\d{14}/)
def assetNo = matcher[0]
//so I can publish which ears were deployed
println "${project}.ear (V-${buildNo})"
//Now for the cool automatic download
def srcLoc = "${cruiseServer}${artifactPath}${project}/${assetNo}/${ear}"
def file = new File(dwnldDir + srcLoc.tokenize("/")[-1])
def out = new BufferedOutputStream(new FileOutputStream(file))
out <<>
//publish file size to confirm end of download
println file.length()
out.close()
} // end of download closure

//ah the miracle of AntBuilder - my files loaded straight to server after download
ant = new AntBuilder()
//note: in eclipse scp requires some path configuration.
//google the error you get when this runs to find correct jars for your version.
ant.scp( todir: "${uploadDir}",
password: "opensesme",
trust: "true" {
fileset(dir:"$dwnldDir") {
//this little closure ensures I only upload new assets.
//pretty cool to be able to mix builder syntax and script code.
projects.each() { project, ear, version ->
include(name: "$ear")
} //end projects.each closure
} // end fileset closure
} //end ant.scp closure

Tuesday, April 7, 2009

Groovy CruiseControl Helper - part 1 RSS and Regex

I've been wasting entirely too much time deploying builds lately as our CruiseControl instance produces upwards of 35 builds, of which I only care about 4.   Not to mention that downloading each ear file is at least 3 page 'clicks'.   Ignoring for now that CruiseControl would happily deploy my ears for me (team's CruiseControl guru is overbooked right now),  I've started building a Groovy utility to leverage the RSS feeds produced by CruiseControl in order to run an automatic pull of the latest builds for my 4 target ears.

I started tinkering with examples found in "Groovy In Action" and in Netbeans, but moved over to Eclipse 3.4.1 when things were ready to implement as that's the standard at work.   Netbeans was more 'Groovyish' and very easy to start scripting with, whereas Eclipse is more 'Javaish' expecting you to produce classes rather than 'scripts'

In the end I built one Class  to handle  the RSS and information parsing  and one Script to act as my main and run my new process.

My Class simply opens an RSS feed, pulls data from the top item and parses out the stuff I need to find my assets for deployment.

/*
   For a specific RSS feed and project.   Get the key data for the latest build
*/
public class GetRss {
   private myBase;
   private myProject;
   private buildNo;
   private assetNo;

   GetRss (String base,  String project) {
     myBase = base;
     myProject = project;
  }

   void doRss()
   {
       //open the Rss Feed URL,  parse date into XML Document
       def items = new XmlParser().parse(myBase + myProject).channel[0].item
       //GPath notation to get to elements of interest
       // title tells me if this build passed or failed
       println items[0].title.text()
       //The link is to build HTML - I want only some of this info
       parseLink( items[0].link.text())
    }
    
/*
   parseLink uses regular expressions to pull out the two items I need from the link
   Build No is what I will use to identify the build to QA  ##.##.##.##  
   Asset No is what CruiseControl uses to uniquely identify build results - 14 digit number
*/
      void parseLink(String link)
     {
            //Link contains build #  - what the build will be know by in the real world
            // build number is pattern of 4 sets of digits separated by .
            def buildMatcher = ( link =~ /-\d+[.]\d+[.]\d+[.]\d+/ )
            buildNo = matcher[0]
            //link also contains CruiseControl build ID - 14 digit number
            def matcher = ( link =~ /\d{14}/ )
            assetNo = matcher[0]

      }

Part 1 - merely generates URLs for where each ear file is stored by the CruiseControl process.   So instead of many page clicks to download.  I can run the following script and get 4 URLs ready to download the assets from.   Stay tuned for Part2 where I will use AntBuilder and Groovy to automatically FTP these assets to where I need to stage them...

//The common paths set by cruisecontrol
def cruiseServer = 'http://mybuild.server.com:8081'
def allRSS = "$cruiseServer/cruisecontrol/rss/"
def allAsset = "$cruiseServer/crusiecontrol/artifacts"

//Read RSS for Project1 and get key data
GetRss uiservices = new GetRss( allRss, "Project1-BuildWar")
uiservices.doRss()

//Print the line with build No and URL to deployment asset
println " $uiservices.buildNo $allAsset$uiservices.myProject/$uiservices.assetNo/project1.war"

//... Repeated above for each additional project
The script outputs two lines, first the item title with time of build and status.  Then a second line with the build No and a link that I can cut and paste into browser to initiate the download of the deployment asset.

Example output for first project

Tue Apr 07 20:41:47 EDT 2009, passed   
-10.12.1.191  http://mybuild.server.com:8081/cruisecontrol/artifacts/Project1-BuildWar/20090403180111.project1.war


As mentioned, in part 2 I will develop the code to directly download the build assets using the URLs generated in part 1.