SVNLabelIncrementer in CruiseControl

SVNLabelIncrementer in CruiseControl is supposed to get the latest revision number for the project, and use this revision number as part of the cruisecontrol build number.

Unfortunately, we always got the revision number from the last successful build as the new label. For example, if the local working copy has revision-10 before CruiseControl build, and the current SVN repository revision is 12. We will get 10 as the revision number even if we get revision 12 code in the build. It's kind of annoying, isn't it?

After some investigation, we found that the SVNLabelIncrementer class was using "svnversion" command to get the revision number. Let's look at the definition of "svnversion":

svnversion — Summarize the local revision(s) of a working copy.

Apparently, that's not what we want. We want the revision number of the remote repository.

In the end, we modified the code to use "svn info" to get the remote svn repository revision. I have attached the code here, hope this helps other folks.

package net.sourceforge.cruisecontrol.labelincrementers;

import org.jdom.Element;

To properly set this up put the following in your cruise config.xml


public class SVNLabelIncrementer extends DefaultLabelIncrementer {

private String targetURL;

private String username="";

private String password="";

public String incrementLabel(String oldLabel, Element buildLog) {

String SVNRev = "";

try {
SVNRev = getSvnRevision();
} catch (IOException e) {

String label = getNonSubversionPartOfLabel(oldLabel);
if (SVNRev == null || SVNRev.equals(""))
return oldLabel;

return label + "." + SVNRev;

protected String getSvnRevision() throws IOException {
Process p = null;
try {
String[] commands = new String[]{"svn", "info", targetURL, "--username", username, "--password", password};
p = Runtime.getRuntime().exec(commands);

BufferedReader stdInput = new BufferedReader(new
String thisLine = stdInput.readLine();
while (thisLine != null) {
if (thisLine.startsWith("Revision:")) {
return thisLine.split(":")[1].trim();
thisLine = stdInput.readLine();
} finally {
if (p != null)
return "";

public boolean isValidLabel(String label) {
return super.isValidLabel(getNonSubversionPartOfLabel(label));

private String getNonSubversionPartOfLabel(String label) {
int index = label.lastIndexOf(".");
if (index == -1)
index = label.length();
return label.substring(0, index);

public String getTargetURL() {
return targetURL;

public void setTargetURL(String targetURL) {
this.targetURL = targetURL;

public String getUsername() {
return username;

public void setUsername(String username) {
this.username = username;

public String getPassword() {
return password;
public void setPassword(String password) {
this.password = password;

1 comment:

Jeffrey Fredrick said...

Just curious, but did you ever submit this change to the CruiseControl developers mailing list or the CruiseControl issue tracker?