Building task branches with CruiseControl
Welcome back PlastiKers! :-)If you follow this blog or if you've reading about the latest changes in version control all around, you're probably familiar with task branches.
Simply put: it is all about keeping your mainline as stable as possible and isolating all changes in separate branches, as we introduced a few days ago.
Well, whether you already joined the new wave you probably have several questions. And one of them is:
what happens with my continuous toolset? how should I manage my builds now?.
Instead of just monitoring a single branch (the trunk or main in most cases) now you've to build and test each branch separately, and only after it has been finished.
How can you achive that?
I'm going to propose a solution based on Plastic and CruiseControl.net (cc.net)
First, let's have a look at the whole set up involved.
We've a version control server and a CruiseControl server (they could run in the same machine, of course), and what we need to achieve is:
CruiseControl supports a number of version control systems and Plastic is on that list.
But what we need is not a regular version control block which is able to download code if new revisions are created, but perform something a little bit more specific.
In Plastic (and also in other SCMs out there) there's a very handful concept known as attributes. Attributes are values that can be attached to any controlled object.
We can create an attribute named branch_status and associate it to branches with a given value. The developer can set the branch_status value to closed once the feature or bugfix is finished, and this value will be used by the CC.net integration to trigger the build.
In Plastic the command would be (only one line):
cm find branch where
attribute='branch_status'
and attrvalue='closed'
--nototal --format={name}
Of course instead of closed you can define another value.
And, once the tests are run, you can use the following command to set the branch as tested.
cm statt att:branch_status br:/main/feature101 tested
We'll use a couple of ruby scripts to implement the calls to the Plastic command line inside exec configuration blocks.
Take a look at the ccnet.config file
<cruisecontrol>
<project name="helloworld">
<modificationDelaySeconds>
5
</modificationdelayseconds>
<sourcecontrol type="nullSourceControl"/>
<triggers>
<intervalTrigger
name="continuous"
seconds="10"
buildCondition="ForceBuild"
initialSeconds="10"/>
</triggers>
<tasks>
<exec>
<executable>ruby.exe</executable>
<baseDirectory>D:\code\</basedirectory>
<buildArgs>D:\code\findchanges.rb</buildargs>
<buildTimeoutSeconds>10</buildtimeoutseconds>
<successExitCodes>0</successexitcodes>
</exec>
<nant>
<executable>nant.exe</executable>
<baseDirectory>D:\code</basedirectory>
<buildFile>default.build</buildfile>
</nant>
<exec>
<executable>ruby.exe</executable>
<baseDirectory>D:\code\</basedirectory>
<buildArgs>D:\code\testedbranch.rb</buildargs>
<buildTimeoutSeconds>10</buildtimeoutseconds>
<successExitCodes>0</successexitcodes>
</exec>
</tasks>
</project>
</cruisecontrol>
<project name="helloworld">
<modificationDelaySeconds>
5
</modificationdelayseconds>
<sourcecontrol type="nullSourceControl"/>
<triggers>
<intervalTrigger
name="continuous"
seconds="10"
buildCondition="ForceBuild"
initialSeconds="10"/>
</triggers>
<tasks>
<exec>
<executable>ruby.exe</executable>
<baseDirectory>D:\code\</basedirectory>
<buildArgs>D:\code\findchanges.rb</buildargs>
<buildTimeoutSeconds>10</buildtimeoutseconds>
<successExitCodes>0</successexitcodes>
</exec>
<nant>
<executable>nant.exe</executable>
<baseDirectory>D:\code</basedirectory>
<buildFile>default.build</buildfile>
</nant>
<exec>
<executable>ruby.exe</executable>
<baseDirectory>D:\code\</basedirectory>
<buildArgs>D:\code\testedbranch.rb</buildargs>
<buildTimeoutSeconds>10</buildtimeoutseconds>
<successExitCodes>0</successexitcodes>
</exec>
</tasks>
</project>
</cruisecontrol>
And the two ruby scripts:
findchanges.rb
input = `cm find branch
where attribute='branch_status'
and attrvalue='closed'
--nototal --format={name}`
if ( input == "")
print "no pending branches"
exit(1)
end
branch = input.split(/\n/)[0]
selector =
"rep \"default\" path \"/\" smartbranch \"#{branch}\""
File.open("selector.txt", "w") do |f|
f.write(selector)
end
File.open("activebranch.txt", "w") do |f|
f.write(branch)
end
system("cm setselector --file=selector.txt")
exit(0)
And testedbranch.rb
File.open("activebranch.txt", "r") do |f|
branch = f.read()
system("cm statt
att:branch_status br:#{branch} tested")
end
And the picture depicting the whole process:
Which is very simple.
Please note I've used exec blocks in order to customize the entire process with simple ruby scripts, but we're plannig to add this capability to the Plastic SCM configuration block in cc.net.
And the branch explorer can highlight branches based on certain properties or attributes.
This way we have the skeleton to start up.
Next Steps
The goal would be setting up an automated process based on CruiseControl to build, test and report separated branches before they get integrated into the main line.
So the project configuration file: ccnet.config would have to extended from a hello world into a real script including testing tasks, deployment and so on.
Also reporting would be key, and specially adding data about which one is the branch being built and tested.
Hope you find it interesting!
have you tried hudson?
ReplyDelete