A nice convention that we’ve enjoyed using is to make the “environment shortnames” in environments — synonymous with the “statuses” in the Life-cycle model of your project in Anthill Pro. This way, upon deployment you “stamp” the build life with the environment shortname that you’re deploying to. This allows you to see what state a given build life is in your development lifecycle. This will account 100% that the build artifacts you deploy are the same exact ones that were deployed to previous ancestor environments (stage, qa1, qa2, uat, sit, dev, etc).

We create a global Library Job which stamps the environment shortname as the last step of all our workflow models. Only upon success of deployment does the buildlife get “promoted” from one environment to the other.

Additionally, the “stamp” we use the build life always show the REVISION_NUM-(trunk|branches/num). Therefore, upon successful “builds” this stamp is applied to the build life, so we know ‘exactly’ where this code located in our repository, and what environment it exists on and when it was deployed there.

We create the stamp by getting the revision number with this “stamping script” that comes pre-baked into the latest version of AnthillPro.

import com.urbancode.vcsdriver3.*;
import com.urbancode.anthill3.domain.buildlife.*;
import com.urbancode.anthill3.runtime.scripting.helpers.*;

int getMaxChangeSet(BuildLife life) {
 int result = 0;
 ChangeLog[] changelogArray = ChangeLogHelper.getChangeLogArray(life);
 for (int i = 0; i < changelogArray.length; i++) {
  ChangeSet[] changesetArray = changelogArray[i].getChangeSetArray();
  for (int j = 0; j < changesetArray.length; j++) {
   ChangeSet changeset = changesetArray[j];
   id = changeset.getId();

   // edit out the "r" character for svn
   if (id.startsWith("r")) {
    id = id.substring(1);
   }
   int num = (new Integer(id.trim())).intValue();
   if (num > result) {
    result = num;
   }
  }
 }
 return result;
}

// If there is no changelog, look up the previous build
// and take the highest number from that (if present, else keep searching).

int highestChangeset = 0;
BuildLife life = BuildLifeLookup.getCurrent();
while(highestChangeset == 0 && life != null) {
 highestChangeset = getMaxChangeSet(life);
 life = life.getPrevBuildLife();
}

stampContext.put("changeset", ""+highestChangeset);
import com.urbancode.vcsdriver3.*;
import com.urbancode.anthill3.domain.buildlife.*;
import com.urbancode.anthill3.runtime.scripting.helpers.*;

int getMaxChangeSet(BuildLife life) {  
 int result = 0;
 ChangeLog[] changelogArray = ChangeLogHelper.getChangeLogArray(life);  
 for (int i = 0; i < changelogArray.length; i++) {    
  ChangeSet[] changesetArray = changelogArray[i].getChangeSetArray();    
  for (int j = 0; j < changesetArray.length; j++) {      
   ChangeSet changeset = changesetArray[j];      
   id = changeset.getId();      // edit out the "r" character for svn      
   if (id.startsWith("r")) {        
    id = id.substring(1);      
   }      
  int num = (new Integer(id.trim())).intValue();      
  if (num > result) {        
   result = num;      
  }    
 }  
}  
return result;
}

// If there is no changelog, look up the previous build
// and take the highest number from that (if present, else keep searching).

int highestChangeset = 0;
BuildLife life = BuildLifeLookup.getCurrent();while(highestChangeset == 0 && life != null) {  
 highestChangeset = getMaxChangeSet(life);  
 life = life.getPrevBuildLife();
}

stampContext.put("changeset", ""+highestChangeset);

This allows the use of this “stamp” code as defined in the build job.

${stampContext:changeset}-${property:svn.source}

This is what provides is with a build stamp that looks like: 82773-trunk or 82881-branches/v_613

In order to capture the svn.source, we create a text input called “svn.source” on the originating workflow as a workflow property with the default of value. This variable is also used when pulling the source from the repository, such that the resource is $SVN_BASE/$svn.source as defined when you edit the sources in the originating buildlife.

This makes the “Main” tab of the build-life screen, extremely useful to managers and upper management because it reflects the real time status of the lifecycle development of any given piece of software. Allowing one to reconcile the amount of development time and money went into the production of X defects / features deployed to production, or any other environment one would be interested in knowing this information about. This method also provides clear credibility for, perhaps auditing purposes that a given buildlife which was deployed to production, was also deployed to all the proper testing and staging environments as well. What a treat.