Miscellaneous Scripts

This page lists miscellaneous scripts that are not directly defined by the other categories listed in the scripting site. These scripts were taken straight from the public JIRA site. Please note that some scripts may be snippets and probably WILL need modification to work properly for your situation. Treat these as templates that you can modify from.

Add a Debugger to Log System Events

  • Please note this event listener stays in the System until the next restart. Running the script more than once will create duplicate listeners and logging.

AHPSCRIPTS-121

import com.urbancode.anthill3.domain.buildrequest.BuildRequestEvent; 
 import com.urbancode.anthill3.domain.security.UserFactory; 
 import com.urbancode.anthill3.domain.workflow.WorkflowEvent; 
 import com.urbancode.anthill3.persistence.UnitOfWork; 
 import com.urbancode.anthill3.services.event.EventListener; 
 import com.urbancode.anthill3.services.event.EventService; 
 import com.urbancode.anthill3.services.event.criteria.Criteria; 
 import java.util.EventObject; 
 import org.apache.log4j.Logger; 

 public class LoggingEventListener implements EventListener { 

     Logger log = Logger.getLogger("LoggingEventListener"); 

     public void handleEvent(EventObject event) { 
         if (event instanceof BuildRequestEvent) { 
             UnitOfWork uow = UnitOfWork.create(UserFactory.getSystemUser()); 
             try { 
                 requestEvent = (BuildRequestEvent) event; 
                 request = requestEvent.getSource(); 
                 log.warn("Received " + event.getClass().getSimpleName() + " for request " + request.getId() + " with status " + request.getStatus()); 
             } 
             finally { 
                 uow.close(); 
             } 
         } 
         else if (event instanceof WorkflowEvent) { 
             UnitOfWork uow = UnitOfWork.create(UserFactory.getSystemUser()); 
             try { 
                 workflowEvent = (WorkflowEvent) event; 
                 workflow = workflowEvent.getSource(); 
                 log.warn("Received " + event.getClass().getSimpleName() + " for workflow " + workflow.getId() + " with status " + workflow.getStatus()); 
             } 
             finally { 
                 uow.close(); 
             } 
         } 
     } 

     public Class getEventClass() { 
         // get all events 
         return EventObject.class; 
     } 

     public Criteria[] getCriteria() { 
         return null; 
     } 
 } 

 EventService.getInstance().registerEventListener(new LoggingEventListener());

Add Random Test Results to a BuildLife

Script Notes:

  • This is a good script to use if you need some garbage results on the Tests tab.
import com.urbancode.anthill3.domain.test.*;
import java.util.Random;

Random timerand = new Random();
Random successrand = new Random();
Random totalrand = new Random();
int timeint = timerand.nextInt(1048576) + 1;
int successint = successrand.nextInt(32768) + 1;
int totalint = totalrand.nextInt(32769) + 1;

Random srunrand = new Random();
Random frunrand = new Random();
int srun = srunrand.nextInt(254) + 1;
int frun = frunrand.nextInt(254) + 1;

public newnums()
{
    timeint = timerand.nextInt(1048576) + 1;
    successint = successrand.nextInt(32768) + 1;
    totalint = totalrand.nextInt(32769) + 1;
}

public newtimeint()
{
    timeint = timerand.nextInt(1048576) + 1;
}

public roller()
{
    int rollnum=0;
    while(totalint < successint){
        newnums();
	    rollnum++;
	    commandOutput.println("REROLL #"+rollnum+". . .TRYING FOR BETTER NUMBERS");
    }
}

while(totalint < successint){roller();}

testReport = new TestReport();
testReport.setName("Unit Tests");
testReport.setNumberOfSuites(1);
testReport.setNumberOfTests(totalint);
testReport.setNumberOfSuccesses(successint);
testReport.setNumberOfFailures(totalint-successint);
testReport.setJobTrace(JobTraceLookup.getCurrent());
testReport.store();

while(totalint < successint){roller();}

testSuite = new TestSuite();
testSuite.setName("Test Suite");
testSuite.setTestReport(testReport);
testSuite.setNumberOfTests(totalint);
testSuite.setNumberOfSuccesses(successint);
testSuite.store();

for (i=0; i<srun; i++){
    String stringpre  = "Inserting test #";
    String stringpost = " into Anthill";
    String pass       = Integer.toString(i+1);
    String stringer = stringpre + pass + stringpost;
    
	while(totalint < successint){roller();}
        newtimeint();
    testCase = new TestCase();
    testCase.setName("testMethod");
    testCase.setClassName("com.urbancode.Test");
    testCase.setTestSuite(testSuite);
    testCase.setTime(timeint);
    testCase.setMessage(stringer);
    testCase.setResult("success");
    testCase.store();
}

for (i=0; i<frun; i++){
    String stringpre  = "Inserting test #";
    String stringpost = " into Anthill";
    String pass       = Integer.toString(i+1);
    String stringer = stringpre + pass + stringpost;
    
	while(totalint < successint){roller();}
	newtimeint();
	
    testCase = new TestCase();
    testCase.setName("testMethod");
    testCase.setClassName("com.urbancode.Test");
    testCase.setTestSuite(testSuite);
    testCase.setTime(timeint);
    testCase.setMessage(stringer);
    testCase.setResult("failure");
    testCase.store();
}

Add unknown SCM users as AHP users

Script Notes:

  • Automatically add users that we see in change logs to Anthill so we can send notification to them.
  • Needs to have the logging reworked.

AHPSCRIPTS-3

import com.urbancode.anthill3.runtime.scripting.properties.*;
import com.urbancode.anthill3.runtime.scripting.session.*;
import java.util.*;
import java.io.*;


import com.urbancode.anthill3.domain.authentication.*;
import com.urbancode.anthill3.domain.project.*;
import com.urbancode.anthill3.domain.persistent.PersistenceException;
import com.urbancode.anthill3.domain.security.*;
import com.urbancode.anthill3.domain.singleton.security.*;
import com.urbancode.anthill3.domain.userprofile.UserProfile;

import com.urbancode.commons.util.CollectionUtil;
import com.urbancode.vcsdriver3.*;


HashSet userSet = new HashSet();

ChangeLog[] changelogs = ChangeLogHelper.getChangeLogArray(workflow);
Long repoId = workflow.getBuildLife().getProfile().getSourceConfig().getId();
userFactory = UserFactory.getInstance();

developerRole = RoleFactory.getInstance().restoreForName("Sonata Developers");
userRole = RoleFactory.getInstance().restoreForName("User");

// Look-up the LDAP realm here
AuthenticationRealm ldapRealm = AuthenticationRealmFactory.getInstance().restore("LDAP");


File f = new File("/tmp/script.log");
StringBuffer sb = new StringBuffer();
for (int i = 0; i < changelogs.length; i++){
ChangeSet[] changeset = changelogs[i].getChangeSetArray();
for (int j = 0; j < changeset.length; j++){
try {
String username = changeset[j].getUser();
String domain = null;
String[] splitValue = username.split("\\\\");

if(splitValue.length == 2) {
domain = splitValue[0];
username = splitValue[1].trim().toLowerCase();
}

sb.append("Changelog username : "+username+"\n");

User[] tempUsers = userFactory.restoreAllForChangelogNameAndRepository(username, repoId);

if (tempUsers.length > 0) {
CollectionUtil.addAll(userSet, tempUsers);
} else {
sb.append(username+" User does not exist. Adding User\n");
User user1 = new User(true, ldapRealm);
user1.setName(username);
user1.setPassword("Bogus");

Long[] roleArray = new Long[] {userRole.getId(), developerRole.getId()};
user1.addRole(developerRole);
user1.addRole(userRole);
user1.store();

UserProfile p = new UserProfile();
p.setUser(user1);
p.setEmailAddress(username+"@mycompany.com");
p.setFirstName("New");
p.setLastName("User");
p.setNew();
p.store();

// Adding the user into the notification userset again
User[] tempUsers = userFactory.restoreAllForChangelogNameAndRepository(username, repoId);
CollectionUtil.addAll(userSet, tempUsers);
}
}
catch (PersistenceException e) {
throw new PersistenceRuntimeException(e);
}
}
}


User[] result = new User[userSet.size()];
userSet.toArray(result);

for(int i=0; i<result.length;i++) {
sb.append("user name "+result[i].toString());
sb.append("realm "+result[i].getAuthenticationRealm().getName()+"\n");
}

try {
    BufferedWriter out = new BufferedWriter(new FileWriter("/tmp/script.log"));
    out.write(sb.toString());
    out.close();
} catch (IOException e) {
}

Annihilate a Source Config on a Project

  • This script needs to be ran as an evaluate script step. It will search for the first project that matches the name string and obliterate the source config on it. Please keep a backup of the database/project handy in case this is used accidentally/maliciously.

AHPSCRIPTS-130

import com.urbancode.anthill3.domain.project.Project; 
 import com.urbancode.anthill3.domain.project.ProjectFactory; 
 import com.urbancode.anthill3.domain.workflow.Workflow; 
 import com.urbancode.anthill3.domain.source.SourceConfig; 
 import com.urbancode.anthill3.domain.profile.BuildProfile; 
 import com.urbancode.anthill3.domain.profile.BuildProfileFactory; 
 import com.urbancode.anthill3.domain.project.*; 

 Project project = ProjectFactory.getInstance().restoreForName("PUT THE NAME OF YOUR PROJECT HERE"); 

 for (Workflow workflow : project.getOriginatingWorkflowArray()) { 
     BuildProfile profile = workflow.getBuildProfile(); 
     SourceConfig sourceConfig = profile.getSourceConfig(); 
     sourceConfig.delete(); 
     profile.setSourceConfig(null); 
 }

Build Step Via Script and Run It

  • This was created for a customer who wanted to change some inputs to our CvsGetChangelog Step, but could be used for other steps as well.

AHPSCRIPTS-98

import com.urbancode.anthill3.domain.source.cvs.CvsGetChangelogStepConfig; 
 import com.urbancode.anthill3.domain.buildlife.*; 
 import com.urbancode.anthill3.services.jobs.*; 
 import org.apache.log4j.Logger; 
 Logger log = Logger.getLogger("script"); 

 CvsGetChangelogStepConfig stepConfig = new CvsGetChangelogStepConfig(); 
 var status = StatusLookup.getStatusByName("passed-tests"); 

 BuildLife buildLife = BuildLifeLookup.mostRecentByStatus(status); 
 if (buildLife == null) { 
 var array = BuildLifeFactory.getInstance().restoreAllBefore(BuildLifeLookup.getCurrent()); 
 for (int i = array.length - 1; i >= 0; i--) { 
 var curBuildLife = array[i]; 
 if (curBuildLife.hasStatus(ProjectLookup.getCurrent().getStatusGroup().getSuccessStatus())) { 
 buildLife = curBuildLife; 
 break; 
 } 
 } 
 } 

 stepConfig.setStartDate(buildLife.getActualWorkspaceDate()); 
 var step = stepConfig.buildStep(); 
 var stepExecutor = StepExecutor.getCurrent(); 
 step.setAgent(JobTraceLookup.getCurrent().getAgent()); 

 try { 
 stepExecutor.execute(step, "Generated Changelog Step"); 
 } 
 catch (Throwable e) { 
 log.error("Exception:", e); 
 }


Change Owner of Project or Other Resource

This script must be run as the admin user. Just change the projectName and newOwnerName.

AHPSCRIPTS-35

import com.urbancode.anthill3.main.client.AnthillClient;
import com.urbancode.anthill3.persistence.UnitOfWork;
import com.urbancode.anthill3.domain.project.*;
import com.urbancode.anthill3.domain.security.*;


String projectName = "JUnit";
String newOwnerName = "user";


String serverHost = "localhost";
int serverPort = 4567;
String userName = "admin";
String password = "admin";

//serverHost = bsh.args[0];
//serverPort = Integer.parseInt(bsh.args[1]);
//userName = bsh.args[2];
//password = bsh.args[3];

// obtain connection to the Anthill server
AnthillClient anthill = AnthillClient.connect(serverHost, serverPort,
                                              userName, password);

// create a Unit of Work
UnitOfWork uow = anthill.createUnitOfWork();


// Project
Project project = ProjectFactory.getInstance().restoreForName(projectName);
if (project == null) {
    throw new Exception("Project not found. Please check the project name and if this user has permissions to it.");
}

User user = UserFactory.getInstance().restoreForName(newOwnerName);
if (user == null) {
    throw new Exception("New Owner User not found. Please check the user name and if this user has permissions to it.");
}

Role ownerRole = RoleFactory.getInstance().restoreUserRole(user);
if (ownerRole == null) {
    throw new Exception("New Owner User Role not found. This could be due to data inconsistency, every user should have a unique role.");
}

Resource resource = ResourceFactory.getInstance().restoreForPersistent(project);
if (resource == null) {
    throw new Exception("Project Resource not found. Please contact support.");
}

Permission[] permissions = PermissionFactory.getInstance().restoreAllForResource(resource);
for (int p=0; p<permissions.length; p++) {
    System.out.println("Found " + projectName + " / " + permissions[p].getRole().getName() + " / " + permissions[p].getAction());
    if (permissions[p].getRole().isUserRole() && permissions[p].isDeleteable()) {
        System.out.println(" -- Removing this permission.");
        permissions[p].delete();
    }
}
uow.commit();

System.out.println("====================");
Permission read = new Permission(resource, "read", ownerRole);
System.out.println("Creating " + projectName + " / " + ownerRole.getName() + " / read");
read.store();
Permission write = new Permission(resource, "write", ownerRole);
System.out.println("Creating " + projectName + " / " + ownerRole.getName() + " / write");
write.store();
Permission security = new Permission(resource, "security", ownerRole);
System.out.println("Creating " + projectName + " / " + ownerRole.getName() + " / security");
security.store();

// commit to database
uow.commitAndClose();

System.out.println("Changed owner of project " + project.getName() + " [" + project.getId() + "] to " + user.getName());

Clean up Massive Job Log Directories

  • A script to find and remove unnecessary (empty) directories in the job log (or other) directory in the anthill server.

AHPSCRIPTS-116

/** 
  * It is advisable that this script only be run by Anthill administrators. 
  * This script will only remove empty directories left by our cleanup policy. 
  * Typically directories are not removed because they are likely to be reused 
  * soon. For some clients, the sheer number of jobs requires these empty 
  * directories to be managed, despite not being part of the more typical 
  * cleanup policy. 
  * 
  * This script does not remove any files! Only directories. 
  * 
  * To prevent conflicts, it is advisable to run this script during a time that 
  * uses very little activity. 
  * 
  * This script uses the AH3ServerJobLogDir property. Ensure this is set when 
  * running the script. 
  * 
  * If the AH3ServerJobLogDir property does not conform to the expected value, 
  * it will not proceed. This is to prevent the accidental deletion of logs or 
  * directories. 
  * 
  * During testing, the performance of the script is about 2000 directory reads 
  * per second, and about 1000 directory deletes per second. Milage may vary. 
  * 
  * With very little effort, this script could be modified to handle this 
  * procedure on any accessible directory. Note that the safeguards in place 
  * should also be updated accordingly. 
  */ 
 import com.urbancode.devilfish.services.var.VarService; 
 import com.urbancode.anthill3.main.DefaultConfiguration; 

 /** 
  * function to delete the given directory if and only if 
  * it consists of empty directories or is empty itself. 
  */ 
 int deleteEmptyDirs(File dir) { 
 int deleteCount = 0; 
 // we only do this to directories 
 if (dir.isDirectory()) { 
 // verify we can list the files here 
 try { 
 // first, recurse for all directories in this directory 
             for (File subdir : dir.listFiles()) { 
                 if(subdir.isDirectory()) { 
                     deleteCount += deleteEmptyDirs(subdir); 
                 } 
             } 

             // only delete if we managed to eliminate the subdirectories 
             if (dir.listFiles().length == 0 && dir.delete()) { 
                 deleteCount++; 
             } 
 } 
 catch (Exception e) { 
 System.out.println("Permission access error in " + dir.toString() + "."); 
 } 
 } 
 return deleteCount; 
 } 

 /** 
  * Begin actual script. 
  */ 
 VarService vs = VarService.getInstance(); 
 String logDirStr = vs.getVarValue(DefaultConfiguration.LOGS_DIR) + File.separator + "job"; 
 File logDir = new File(logDirStr); 
 if(logDir == null) { 
     throw new IllegalStateException("Log parent directory not found: " + logDir); 
 } 
 if(!logDir.isDirectory()) { 
     throw new IllegalStateException("Log parent directory strangely not a directory: " + logDir); 
 } 

 // init metrics 
 int totalDeletes = 0; 
 long start = System.currentTimeMillis(); 

 // perform the delete 
 for(File dir : logDir.listFiles()) { 
     totalDeletes += deleteEmptyDirs(dir); 
 } 
 // calc metrics 
 long end = System.currentTimeMillis(); 
 long secs = (end-start) / 1000; 
 double deletionRate = ((double)totalDeletes) / ((double)secs); 
 System.out.println("Deleted " + totalDeletes + " empty directories in " + secs + " seconds (" + deletionRate + " deletes per second).");

Consolidate Dependency Reports And Publish on Parent Project

  • This is a script that will take logs published as reports for dependency projects and consolidate them so that they can be viewed in one location on the reports tab of the blanket project. A more efficient way is listed secondly.

AHPSCRIPTS-7

import com.urbancode.anthill3.runtime.scripting.helpers.BuildLifeLookup;
 import com.urbancode.anthill3.runtime.paths.PublishPathHelper;
 import com.urbancode.anthill3.domain.buildlife.BuildLife;
 import com.urbancode.anthill3.domain.workflow.WorkflowCase;
 import com.urbancode.devilfish.services.var.VarService;
 import com.urbancode.anthill3.domain.jobtrace.JobTrace;
 import com.urbancode.commons.fileutils.FileUtils;
 import com.urbancode.codestation2.domain.buildlife.CodestationCompatableBuildLife;
 import java.util.*;

 static final private org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger("ReportScript");

 final String REPORT_NAME = "LogReport";

 VarService vs = VarService.getInstance();

 void centrallyLocateLogsForBuildLife(BuildLife buildLife, String reportPath) {

 File reportDir = new File(reportPath + File.separator + buildLife.getProfile().getProject().getName().replace(" ", "_"));
 reportDir.mkdirs();
 log.warn("Report Path Dir" + reportDir.getAbsolutePath());

 WorkflowCase workflowCase = buildLife.getOriginatingWorkflow();
 JobTrace[] jobTraces = workflowCase.getJobTraceArray();

 for (int i = 0; i < jobTraces.length; i++) {
 String dependencyPath = PublishPathHelper.getInstance().getPublishPath(jobTraces[i], REPORT_NAME);
 log.warn("Dependency Path " + dependencyPath);
 dependencyPath = vs.resolve(dependencyPath);
 File dependencyReportDir = new File(dependencyPath);
 if (dependencyReportDir != null && 
 dependencyReportDir.exists() &&
 dependencyReportDir.isDirectory()) {
 log.warn("Copying reports from " + dependencyReportDir.getAbsolutePath() + " to " + reportDir.getAbsolutePath());
 FileUtils.copyFiles(dependencyReportDir, reportDir);
 }
 }
 }

 Set buildDependencyBuildLivesSet(BuildLife buildLife) {
 Set result = new HashSet();

 CodestationCompatableBuildLife[] dependencyBuildLives = buildLife.getDependencyBuildLifeArray();
 for (int i = 0; i < dependencyBuildLives.length; i++) {
 CodestationCompatableBuildLife dependencyBuildLife = dependencyBuildLives[i];
 if (dependencyBuildLife instanceof BuildLife) {
 log.warn("DependencyBuildLife " + dependencyBuildLife.getName());
 result.add(dependencyBuildLife);
 result.addAll(buildDependencyBuildLivesSet((BuildLife) dependencyBuildLife));
 }
 }

 return result;
 }


 BuildLife buildLife = BuildLifeLookup.getCurrent();

 String reportPath = PublishPathHelper.getInstance().getPublishPath(JobTraceLookup.getCurrent(), REPORT_NAME);
 reportPath = vs.resolve(reportPath);
 log.warn("Report Path " + reportPath);

 Set dependencyBuildLifeSet = buildDependencyBuildLivesSet(buildLife);
 Iterator itr = dependencyBuildLifeSet.iterator();

 while (itr.hasNext()) {
 BuildLife buildLife = (BuildLife) itr.next();
 centrallyLocateLogsForBuildLife(buildLife, reportPath);
 }

More Efficient Way:

  • more efficient way of getting the entire dependency graph. This will not process the same build life more than once.
Set buildDependencyBuildLivesSet(BuildLife buildLife) { 
     Set result = new HashSet(); 
     buildDependencyBuildLivesSet(buildLife, result, new HashSet()); 
     return result; 
 } 

 buildDependencyBuildLivesSet(BuildLife buildLife, Set depSet, Set traversedSet) { 
     if (!travesedSet.contains(buildLife)) { 
         travesedSet.add(buildLife): 
         CodestationCompatableBuildLife[] dependencyBuildLives = buildLife.getDependencyBuildLifeArray(); 
         for (int i = 0; i < dependencyBuildLives.length; i++) { 
             CodestationCompatableBuildLife dependencyBuildLife = dependencyBuildLives[i]; 
             if (dependencyBuildLife instanceof BuildLife) { 
                 log.warn("DependencyBuildLife " + dependencyBuildLife.getName()); 
                 depSet.add(dependencyBuildLife); 
                 buildDependencyBuildLivesSet((BuildLife) dependencyBuildLife, depSet, traversedSet)); 
             } 
         } 
     } 
 }

Consolidate Reports of Dependency Projects & Publish Them in Parent Project Report

Script Notes:

  • This is a script that will take logs published as reports for dependency projects and consolidate them so that they can be viewed in one location on the reports tab of the blanket project.
  • Here is a more efficient way of getting the entire dependency graph. This will not process the same build life more than once.
  • Set buildDependencyBuildLivesSet(BuildLife buildLife) {
        Set result = new HashSet();
        buildDependencyBuildLivesSet(buildLife, result, new HashSet());
        return result;
    }
    
    buildDependencyBuildLivesSet(BuildLife buildLife, Set depSet, Set traversedSet) {
        if (!travesedSet.contains(buildLife)) {
            travesedSet.add(buildLife):
            CodestationCompatableBuildLife[] dependencyBuildLives = buildLife.getDependencyBuildLifeArray();
            for (int i = 0; i < dependencyBuildLives.length; i++) {
                CodestationCompatableBuildLife dependencyBuildLife = dependencyBuildLives[i];
                if (dependencyBuildLife instanceof BuildLife) {
                    log.warn("DependencyBuildLife " + dependencyBuildLife.getName());
                    depSet.add(dependencyBuildLife);
                    buildDependencyBuildLivesSet((BuildLife) dependencyBuildLife, depSet, traversedSet));
                }
            }
        }
    } 
    

AHPSCRIPTS-7

import com.urbancode.anthill3.runtime.scripting.helpers.BuildLifeLookup;
import com.urbancode.anthill3.runtime.paths.PublishPathHelper;
import com.urbancode.anthill3.domain.buildlife.BuildLife;
import com.urbancode.anthill3.domain.workflow.WorkflowCase;
import com.urbancode.devilfish.services.var.VarService;
import com.urbancode.anthill3.domain.jobtrace.JobTrace;
import com.urbancode.commons.fileutils.FileUtils;
import com.urbancode.codestation2.domain.buildlife.CodestationCompatableBuildLife;
import java.util.*;

static final private org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger("ReportScript");

final String REPORT_NAME = "LogReport";

VarService vs = VarService.getInstance();

void centrallyLocateLogsForBuildLife(BuildLife buildLife, String reportPath) {

File reportDir = new File(reportPath + File.separator + buildLife.getProfile().getProject().getName().replace(" ", "_"));
reportDir.mkdirs();
log.warn("Report Path Dir" + reportDir.getAbsolutePath());

WorkflowCase workflowCase = buildLife.getOriginatingWorkflow();
JobTrace[] jobTraces = workflowCase.getJobTraceArray();

for (int i = 0; i < jobTraces.length; i++) {
String dependencyPath = PublishPathHelper.getInstance().getPublishPath(jobTraces[i], REPORT_NAME);
log.warn("Dependency Path " + dependencyPath);
dependencyPath = vs.resolve(dependencyPath);
File dependencyReportDir = new File(dependencyPath);
if (dependencyReportDir != null &&
dependencyReportDir.exists() &&
dependencyReportDir.isDirectory()) {
log.warn("Copying reports from " + dependencyReportDir.getAbsolutePath() + " to " + reportDir.getAbsolutePath());
FileUtils.copyFiles(dependencyReportDir, reportDir);
}
}
}

Set buildDependencyBuildLivesSet(BuildLife buildLife) {
Set result = new HashSet();

CodestationCompatableBuildLife[] dependencyBuildLives = buildLife.getDependencyBuildLifeArray();
for (int i = 0; i < dependencyBuildLives.length; i++) {
CodestationCompatableBuildLife dependencyBuildLife = dependencyBuildLives[i];
if (dependencyBuildLife instanceof BuildLife) {
log.warn("DependencyBuildLife " + dependencyBuildLife.getName());
result.add(dependencyBuildLife);
result.addAll(buildDependencyBuildLivesSet((BuildLife) dependencyBuildLife));
}
}

return result;
}


BuildLife buildLife = BuildLifeLookup.getCurrent();

String reportPath = PublishPathHelper.getInstance().getPublishPath(JobTraceLookup.getCurrent(), REPORT_NAME);
reportPath = vs.resolve(reportPath);
log.warn("Report Path " + reportPath);

Set dependencyBuildLifeSet = buildDependencyBuildLivesSet(buildLife);
Iterator itr = dependencyBuildLifeSet.iterator();

while (itr.hasNext()) {
BuildLife buildLife = (BuildLife) itr.next();
centrallyLocateLogsForBuildLife(buildLife, reportPath);
} 


Dashboard Not Displaying Latest BuildLife For Workflow Fix

  • In older versions there was a bug where some build lives did not get entries in the BUILD_WORKFLOW_SUMMARY table that feeds the latest activity on the dashboard.
    • This can be run from Evaluate Script step. Enter the build life ids in the array for which ones to fix.

AHPSCRIPTS-136

import com.urbancode.anthill3.domain.buildlife.BuildLife; 
 import com.urbancode.anthill3.domain.buildlife.BuildLifeFactory; 
 import com.urbancode.anthill3.domain.workflow.WorkflowCase; 
 import com.urbancode.anthill3.domain.workflow.WorkflowEndEvent; 
 import com.urbancode.anthill3.services.event.EventService; 

 long[] buildLifeIds = new long[] { 
     400L, 468L, 469L, 506L, 512L, 537L, 576L, 585L, 596L, 642L, 649L, 
     658L, 780L, 786L, 980L, 1025L, 1046L, 1051L, 1057L, 1086L, 1090L, 
     1094L, 1095L, 1110L, 1168L, 1174L, 1228L, 1366L, 1367L, 1378L, 
     1379L, 1383L, 1400L, 1426L, 1609L, 1712L, 1719L, 1749L, 1758L, 
     1770L, 1889L, 1917L, 1920L, 1931L, 1968L, 2033L, 2119L 
 }; 
 for (long buildLifeId : buildLifeIds) { 
     BuildLife buildLife = BuildLifeFactory.getInstance().restore(buildLifeId); 
     WorkflowCase workflowCase = buildLife.getOriginatingWorkflow(); 
     WorkflowEndEvent workflowEndEvent = new WorkflowEndEvent(workflowCase); 
     EventService.getInstance().sendEvent(workflowEndEvent); 
 }

Double Dynamic Dependency Selection

Script Notes:

  • This scripted step searches all your projects for ones with a specific stamp (technically stamp pattern I think) and adds matching builds as dependencies. Only the most recent build of each project is added and the project will not add itself as a dependency.
  • The idea is to identify some set of projects / applications / services that need to be deployed out together for a particular release. Each project would have a workflow that just assigns a release id to a stamp style dedicated to that purpose. So as a QA person or release engineer, I can approve specific builds for a release.
  • A release manager would then run a workflow that includes this script. That would define a release set containing the builds flagged for this release. It could pull in the artifacts for the subprojects and package them, or just establish the dependency relationships for use in a "Run Workflow on Dependencies" step that runs the deployment workflow for each dependency in turn.

AHPSCRIPTS-61

import com.urbancode.codestation2.domain.project.*;
import com.urbancode.anthill3.domain.buildlife.*;
import com.urbancode.anthill3.runtime.scripting.helpers.*;
import com.urbancode.anthill3.dashboard.*;
import java.util.*;

/////////////////////////////////////////////////////////////////////
// CHANGE STAMP AND LOG TO REUSE THE SCRIPT //
// //
// STAMP_PROPERTY -- Name of workflow property identifying release //
// Logger passes in the name of the step. "Run Script" by default. //
/////////////////////////////////////////////////////////////////////
final String STAMP_PROPERTY = "release id";
private org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger
("Lookup Dependencies");

//----------------------------------------------

project = ProjectLookup.getCurrent();
buildLife = BuildLifeLookup.getCurrent();
stamp = PropertyLookup.getValue(STAMP_PROPERTY);

buildLifeSummaries = DashboardFactory.getInstance().
  getBuildLifeSummariesForProjectWithStamp(null, null, stamp, null, null);

log.info("Found " + buildLifeSummaries.length + " builds for stamp " + stamp);
// Great, we found candidates. Let's take the most recent for each project.
HashSet projectIds = new HashSet();
     
for (int i = 0; i < buildLifeSummaries.length; i++) {
   if (projectIds.contains(buildLifeSummaries[i].getProjectId())) {
      log.warn("Found duplicates for " + buildLifeSummaries[i].getProjectName()
         + ". Keeping only the most recent.");
   }
   else if (project.getId().equals(buildLifeSummaries[i].getProjectId())) {
      log.warn("Found myself. This is at least the second assembly of " +
               "deployables for this release.");
   }
   else {
      // We found a target to deploy
      projectIds.add(buildLifeSummaries[i].getProjectId());
      depBuildLife = BuildLifeFactory.getInstance().
         restore(buildLifeSummaries[i].getBuildLifeId());
      buildLife.addDependencyBuildLife(depBuildLife);
      log.info("Adding: " + buildLifeSummaries[i].getProjectName() + " - " +
                buildLifeSummaries[i].getWorkflowName() + " build: " +
                buildLifeSummaries[i].getBuildLifeId() );
   }
} 

When the workflows to select are a well known set, you might want to use the strategy identified by AHPSCRIPTS-4

Duplicate a Project and Verify Workflows in it

Script Notes:

  • This was tested against 3.8.7_313317
  • THERE IS A BUG IN THE AnthillClient that will cause some errors to appear with the CodestationIndexService. So run this as an evaluate script step instead.
import com.urbancode.anthill3.persistence.UnitOfWork;
import com.urbancode.anthill3.domain.project.*;
import com.urbancode.anthill3.domain.workflow.*;

/**********************************
 * GET THIS JOB'S UNIT OF WORK    *
 **********************************/
uow = UnitOfWork.getCurrent();

/**********************************
 * CREATE DUPLICATE OF SOURCE     *
 **********************************/
Project srcProj = ProjectFactory.getInstance().restore(11); //CVS Anthill-Example Project (Default)
Project tgtProj = srcProj.duplicate();
tgtProj.store();  //should create 'CVS Anthill-Example (copy)'
uow.commit();  //commit the change

/**********************************
 * DIAGNOSTIC INFORMATION         *
 **********************************/
//Original Project Information
commandOutput.println("[SRCPROJ] ID is #" + srcProj.getId());
commandOutput.println("[SRCPROJ] Name is " + srcProj.getName());
commandOutput.println("[       ]");

//Target Project Information (duplicated project info.)
commandOutput.println("[TGTPROJ] ID is #" + tgtProj.getId());
commandOutput.println("[TGTPROJ] Name is " + tgtProj.getName());
commandOutput.println("[       ]");

//Verify all the workflows are present in the new project
for(workflow:tgtProj.getWorkflowArray()){
    commandOutput.println("[TGTPROJ] Workflow found with name " + workflow.getName());
	commandOutput.println("[TGTPROJ] " + workflow.getName() + " has ID #" + workflow.getId());
	}

//End

// Brad M. Galla

Dynamic Dependency Selection

Script Notes:

  • This script is used to select only a subset of the dependencies. So if my project is dependent on the componets S1, S2, S3. This script empowers you to select only S1 and S3. It does this by looking for builds that have been stamped with some value passed into this workflow.
  • The relationships to S1, S2, and S3 can't be defined in the workflow running this script or else they'll be locked in at build time, so we use a separate "template" workflow that defines the base relationships. This script inspects that workflow to determine which build tracks produce candidates for dependency selection.
  • you will need to change the replace(String, String) to replace(Char, Char) if you are not running java 1.5, oops sorry.

AHPSCRIPTS-4

import com.urbancode.codestation2.domain.project.*;
import com.urbancode.anthill3.domain.buildlife.*;
import com.urbancode.anthill3.runtime.scripting.helpers.*;
import com.urbancode.anthill3.dashboard.*;


private org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger
("ScriptEval");

String TEMPLATE_WORKFLOW_NAME="All Dependencies (Most Recent)";

project = ProjectLookup.getCurrent();
buildLife = BuildLifeLookup.getCurrent();
workflowArray = project.getOriginatingWorkflowArray();
stamp = PropertyLookup.getValue("stamp");

templateWorkflow = null;
for (int i = 0; i < workflowArray.length; i++) {
  if (workflowArray[i].getName().equals(TEMPLATE_WORKFLOW_NAME)) {
     templateWorkflow = workflowArray[i];
     break;
  }
}

if (templateWorkflow == null) {
  throw new Exception("Could not find expected workflow on this project: " + TEMPLATE_WORKFLOW_NAME);
}

dependencyArray = templateWorkflow.getBuildProfile().getDependencyArray();
log.error("Dependencies found in template: " + dependencyArray.length);
for (int i = 0; i < dependencyArray.length; i++) {
  dep = dependencyArray[i].getDependency();
  if (dep instanceof AnthillProject) {
     buildProfile = dep.getBuildProfile();
     workflow = buildProfile.getWorkflow();
     depProject = buildProfile.getProject();
        buildLifeSummaries = DashboardFactory.getInstance().getBuildLifeSummariesForProjectWithStamp(depProject, workflow, stamp, null, null);
     log.info("Found " + buildLifeSummaries.length + " builds for stamp " + stamp + " on project " + depProject.getName() + " " + workflow.getName());
         // We found a build life matching the right stamp, let's add it as a dependency
     if (buildLifeSummaries.length > 0) {
        // take the most recent build matching that stamp.
        depBuildLife = BuildLifeFactory.getInstance().restore(buildLifeSummaries[0].getBuildLifeId());
        buildLife.addDependencyBuildLife(depBuildLife);
     }
  }
}

Dynamically Resolve Artifact Set Based Upon Current Environment

AHPSCRIPTS-41

import com.urbancode.anthill3.domain.artifacts.*;
import com.urbancode.anthill3.runtime.scripting.helpers.*;
import com.urbancode.anthill3.step.artifacts.*;
import com.urbancode.anthill3.services.jobs.StepExecutor;

log = org.apache.log4j.Logger.getLogger("Scripted_Artifact_Resolve");

try {
    String setName = EnvironmentLookup.getCurrent().getName();

ArtifactModule module = new ArtifactModule();
    module.setArtifactSet(ProjectLookup.getCurrent().getLifeCycleModel().getArtifactSetGroup().getArtifactSet(setName));
    module.setTargetDirectory("artifacts");

ResolveMyArtifactsStep step = new ResolveMyArtifactsStep(module);
    step.setExecutor(StepExecutor.getCurrent());
    step.setJob(StepExecutor.getCurrent().getJob());
    step.setAgent(StepExecutor.getCurrent().getJobTrace().getAgent());
    step.perform();
}
catch (Exception e) {
    log.error(e.getMessage(), e);
    throw e;
}


Export Project Configuration to XML

Script Notes:

  • Set this script up as an evaluate script step in an operational workflow within an operational project. You will then need to set up a property on the workflow called ProjectName to pass in the project you would like to export. Finally, this script's output will be placed in the %SERVER_HOME%\bin directory unless otherwise noted by setting a working directory.

AHPSCRIPTS-9

import org.w3c.dom.Document;
import com.urbancode.anthill3.runtime.scripting.helpers.*;
import com.urbancode.anthill3.domain.project.Project;
import com.urbancode.anthill3.domain.project.ProjectFactory;
import com.urbancode.anthill3.domain.xml.XMLImporterExporter;
import com.urbancode.commons.xml.DOMUtils;
import java.io.*;

//Set a property on the operational workflow called 'ProjectName'
//so that you can input which project name you want to run this
//script on. Alternatively, you could remove the references to
//a property and just substitute in a string.
String PROJECT_NAME = PropertyLookup.getValue("ProjectName");

//Restores the property and writes to a string
Project project = ProjectFactory.getInstance().restoreForName(PROJECT_NAME);
Document doc = XMLImporterExporter.exportXML(project, "project");
String xmlString = DOMUtils.documentToString(doc);

//Writes the xmlString to a file determined by the project name
//and appends '.xml' to the export.
FileWriter outFile = new FileWriter(PathHelper.makeSafe(PropertyLookup.getValue("ProjectName"))+".xml");
BufferedWriter buffer = new BufferedWriter(outFile);
PrintWriter out = new PrintWriter(buffer);
out.println(xmlString);
out.flush();
out.close(); 

Export Dependencies

import org.w3c.dom.Document;
import com.urbancode.anthill3.runtime.scripting.helpers.*;
import com.urbancode.anthill3.domain.project.*;
import com.urbancode.anthill3.domain.xml.XMLImporterExporter;
import com.urbancode.anthill3.domain.xml.*;
import com.urbancode.commons.xml.*;
import com.urbancode.anthill3.domain.profile.*;
import com.urbancode.anthill3.domain.workflow.*;
import java.io.*;

//Set a property on the operational workflow called 'ProjectName'
//so that you can input which project name you want to run this
//script on. Alternatively, you could remove the references to
//a property and just substitute in a string.
String PROJECT_NAME = PropertyLookup.getValue("ProjectName");

//Restores the property and writes to a string
Project project = ProjectFactory.getInstance().restoreForName(PROJECT_NAME);
Document doc = XMLImporterExporter.exportXML(project, "project");
String xmlString = DOMUtils.documentToString(doc);

//Writes the xmlString to a file determined by the project name
//and appends '.xml' to the export.
DependencyXml depXml = new DependencyXml();
String pDep = depXml.exportDependencies(project);

FileWriter outFile = new FileWriter(PathHelper.makeSafe(PropertyLookup.getValue("ProjectName"))+"_dependencies.xml");
BufferedWriter buffer = new BufferedWriter(outFile);
PrintWriter out = new PrintWriter(buffer);
out.println(pDep);
out.flush();
out.close(); 

Export Project Configuration to XML Using Beanshell or Remoting Script

AHPSCRIPTS-9

import org.w3c.dom.Document; 
 import com.urbancode.anthill3.domain.project.Project; 
 import com.urbancode.anthill3.domain.project.ProjectFactory; 
 import com.urbancode.anthill3.domain.xml.XMLImporterExporter; 
 import com.urbancode.commons.xml.DOMUtils; 

 String PROJECT_NAME = "....."; 

 Project project = ProjectFactory.getInstance().restoreForName(PROJECT_NAME); 
 Document doc = XMLImporterExporter.exportXML(project, "project"); 
 String xmlString = DOMUtils.documentToString(doc);
  • A working case that is based off of having a workflow property entered at run-time which the user can specify a project name to export. Needs thrown in an evaluate step:
/*------------------------------------------------------*/ 
 /* Set this script up as an an evaluate script step in */ 
 /* an operational workflow within an operational */ 
 /* project. You will then need to set up a property on */ 
 /* the workflow called 'ProjectName' to pass in the */ 
 /* project you would like to export. Finally, this */ 
 /* script's output will be placed in the */ 
 /* %SERVER_HOME%\bin directory unless otherwise noted */ 
 /* by setting a working directory */ 
 /*------------------------------------------------------*/ 

 import org.w3c.dom.Document; 
 import com.urbancode.anthill3.runtime.scripting.helpers.*; 
 import com.urbancode.anthill3.domain.project.Project; 
 import com.urbancode.anthill3.domain.project.ProjectFactory; 
 import com.urbancode.anthill3.domain.xml.XMLImporterExporter; 
 import com.urbancode.commons.xml.DOMUtils; 
 import java.io.*; 

 //Set a property on the operational workflow called 'ProjectName' 
 //so that you can input which project name you want to run this 
 //script on. Alternatively, you could remove the references to 
 //a property and just substitute in a string. 
 String PROJECT_NAME = PropertyLookup.getValue("ProjectName"); 

 //Restores the property and writes to a string 
 Project project = ProjectFactory.getInstance().restoreForName(PROJECT_NAME); 
 Document doc = XMLImporterExporter.exportXML(project, "project"); 
 String xmlString = DOMUtils.documentToString(doc); 

 //Writes the xmlString to a file determined by the project name 
 //and appends '.xml' to the export. 
 FileWriter outFile = new FileWriter(PathHelper.makeSafe(PropertyLookup.getValue("ProjectName"))+".xml"); 
 BufferedWriter buffer = new BufferedWriter(outFile); 
 PrintWriter out = new PrintWriter(buffer); 
 out.println(xmlString); 
 out.flush(); 
 out.close();
  • This should export the dependencies to an XML file.
/*------------------------------------------------------*/ 
 /* Set this script up as an an evaluate script step in */ 
 /* an operational workflow within an operational */ 
 /* project. You will then need to set up a property on */ 
 /* the workflow called 'ProjectName' to pass in the */ 
 /* project you would like to export. Finally, this */ 
 /* script's output will be placed in the */ 
 /* %SERVER_HOME%\bin directory unless otherwise noted */ 
 /* by setting a working directory. This script will */ 
 /* export the dependency configuration on the current */ 
 /* project. */ 
 /*------------------------------------------------------*/ 

 import org.w3c.dom.Document; 
 import com.urbancode.anthill3.runtime.scripting.helpers.*; 
 import com.urbancode.anthill3.domain.project.*; 
 import com.urbancode.anthill3.domain.xml.XMLImporterExporter; 
 import com.urbancode.anthill3.domain.xml.*; 
 import com.urbancode.commons.xml.*; 
 import com.urbancode.anthill3.domain.profile.*; 
 import com.urbancode.anthill3.domain.workflow.*; 
 import java.io.*; 

 //Set a property on the operational workflow called 'ProjectName' 
 //so that you can input which project name you want to run this 
 //script on. Alternatively, you could remove the references to 
 //a property and just substitute in a string. 
 String PROJECT_NAME = PropertyLookup.getValue("ProjectName"); 

 //Restores the property and writes to a string 
 Project project = ProjectFactory.getInstance().restoreForName(PROJECT_NAME); 
 Document doc = XMLImporterExporter.exportXML(project, "project"); 
 String xmlString = DOMUtils.documentToString(doc); 

 //Writes the xmlString to a file determined by the project name 
 //and appends '.xml' to the export. 
 DependencyXml depXml = new DependencyXml(); 
 String pDep = depXml.exportDependencies(project); 

 FileWriter outFile = new FileWriter(PathHelper.makeSafe(PropertyLookup.getValue("ProjectName"))+"_dependencies.xml"); 
 BufferedWriter buffer = new BufferedWriter(outFile); 
 PrintWriter out = new PrintWriter(buffer); 
 out.println(pDep); 
 out.flush(); 
 out.close();
  • Importing Dependencies:
import com.urbancode.anthill3.main.client.AnthillClient;
import com.urbancode.anthill3.persistence.UnitOfWork;
import org.w3c.dom.Document;
import com.urbancode.anthill3.domain.project.*;
import com.urbancode.anthill3.domain.profile.*;
import com.urbancode.anthill3.domain.workflow.*;
import com.urbancode.anthill3.domain.xml.*;
import com.urbancode.commons.xml.*;
import java.io.File;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.*;
import javax.xml.transform.stream.StreamResult;

String PROJECT_NAME=PropertyLookup.getValue("ProjectName");
Project project = ProjectFactory.getInstance().restoreForName(PROJECT_NAME);
DocumentBuilderFactory documentBuilderFactory=DocumentBuilderFactory.newInstance();
	
	//Hardcoded for now; could be modified to dynamically find the file from the bin directory
	InputStream inputStream = new FileInputStream(new File("Iterations_Test_dependencies.xml"));
	
	org.w3c.dom.Document doc = documentBuilderFactory.newDocumentBuilder().parse(inputStream);
	StringWriter stw = new StringWriter();
	Transformer serializer = TransformerFactory.newInstance().newTransformer();
	serializer.transform(new DOMSource(doc), new StreamResult(stw));
	String xmlString = stw.toString();

commandOutput.println(xmlString);
System.out.println(xmlString);

DependencyXml depXml = new DependencyXml();
depXml.importDependencies(xmlString);

Give Read, Write, and Security Permissions to Build Master and System Admin For Non-Ignored Agents

  • This can be used to fix broken permissions on the agents

AHPSCRIPTS-96

import com.urbancode.anthill3.main.client.AnthillClient; 
 import com.urbancode.anthill3.persistence.UnitOfWork; 
 import com.urbancode.anthill3.domain.agent.*; 
 import com.urbancode.anthill3.domain.authentication.*; 
 import com.urbancode.anthill3.domain.security.*; 
 import java.util.*; 

 try { 

 agentArray = AgentFactory.getInstance().restoreAllNotIgnored(); 
 Role bmRole = RoleFactory.getInstance().restoreForName("Build Master"); 
 Role saRole = RoleFactory.getInstance().restoreForName("System Admin"); 

 for (Agent agent: agentArray) { 
   boolean bmHasWrite = false; 
   boolean bmHasRead = false; 
   boolean bmHasSec = false; 
   boolean saHasWrite = false; 
   boolean saHasRead = false; 
   boolean saHasSec = false; 

   resource = ResourceFactory.getInstance().restoreForPersistent(agent); 
     
   // Determine roles don't have read access to an agent 
   Permission[] permissions = PermissionFactory.getInstance().restoreAllForResource(resource); 
   for (Permission permission : permissions) { 
     Role role = permission.getRole(); 
     action = permission.getAction(); 
     if (role.equals(bmRole) && action.equals("read")) { 
         bmHasRead = true; 
     } 
     else if (role.equals(bmRole) && action.equals("write")) { 
         bmHasWrite = true; 
     } 
     else if (role.equals(bmRole) && action.equals("security")) { 
         bmHasSec = true; 
     } 
     else if (role.equals(saRole) && action.equals("read")) { 
         saHasRead = true; 
     } 
     else if (role.equals(saRole) && action.equals("write")) { 
         saHasWrite = true; 
     } 
     else if (role.equals(saRole) && action.equals("security")) { 
         saHasSec = true; 
     } 
   } 
        
     
   // Give Build Master Write Permission 
   if (!bmHasWrite) { 
     p = new Permission(true, resource, "write", bmRole); 
     p.store(); 
   } 

   if (!bmHasRead) { 
     p = new Permission(true, resource, "read", bmRole); 
     p.store(); 

   } 

   if (!bmHasSec) { 
     p = new Permission(true, resource, "security", bmRole); 
     p.store(); 

   } 

   if (!saHasWrite) { 
     p = new Permission(true, resource, "write", saRole); 
     p.store(); 
   } 

   if (!saHasRead) { 
     p = new Permission(true, resource, "read", saRole); 
     p.store(); 
   } 

   if (!saHasSec) { 
     p = new Permission(true, resource, "security", saRole); 
     p.store(); 
   } 

 } 

 } 
 catch (Exception e) { 
  e.printStackTrace(commandOutput); 
 }

Invoke Build of Another Project and Wait for Results

This script needs to launch a build of another project that is not a dependency but treat it like it is.

AHPSCRIPTS-40

// beanshell script to mimic dependencies without actually configuring them

import com.urbancode.anthill3.domain.buildrequest.*;
import com.urbancode.anthill3.domain.project.*;
import com.urbancode.anthill3.domain.security.*;
import com.urbancode.anthill3.domain.workflow.*;
import com.urbancode.anthill3.persistence.UnitOfWork;
import com.urbancode.anthill3.runtime.scripting.helpers.*;
import com.urbancode.anthill3.services.build.BuildService;
import com.urbancode.anthill3.services.event.EventListener;
import com.urbancode.anthill3.services.event.EventService;
import com.urbancode.anthill3.services.event.criteria.Criteria;
import com.urbancode.command.CommandException;
import java.util.EventObject;

//import org.apache.log4j.Logger;
//log = Logger.getLogger("MasterScript");

class BlockingEventListener implements EventListener {
    
private BuildRequest request;
    private WorkflowEndEvent event;
    private User user;
    
public BlockingEventListener(BuildRequest request, User user) {
        this.request = request;
        this.user = user;
    }
 
public void handleEvent(EventObject event) {
        if (event instanceof WorkflowEndEvent) {
            UnitOfWork uow = null;
            try {
                uow = UnitOfWork.create(user);
            
WorkflowEndEvent workflowEndEvent = (WorkflowEndEvent) event;
                if (request.equals(workflowEndEvent.getBuildRequest())) {
                    synchronized (this) {
                        this.event = workflowEndEvent;
                        this.notifyAll();
                    }
                }
            }
            catch (PersistenceException e) {
                throw new PersistenceRuntimeException(e);
            }
            finally {
                if (uow != null) {
                    uow.close();
                }
            }
        }
    }

public Class getEventClass() {
        return WorkflowEndEvent.class;
    }

public Criteria[] getCriteria() {
        return null;
    }
    
public void register() {
        EventService.getInstance().registerEventListener(this);
    }
    
public void unregister() {
        EventService.getInstance().removeEventListener(this);
    }
    
public void waitForEvent()
    throws InterruptedException {
        if (this.event == null) {
            synchronized (this) {
                this.wait();
            }
        }
    }
    
public WorkflowEndEvent getEvent() {
        return this.event;
    }
}

try {
    thisRequest = BuildRequestLookup.getCurrent();
    
// BEGIN SECTION TO REPEAT FOR EACH DEPENDENCY
    project = ProjectFactory.getInstance().restoreForName("Project C");
    workflow = project.getWorkflow("Wait");
    
request = new BuildRequest(workflow.getBuildProfile(), thisRequest.getUser(), RequestSourceEnum.DEPENDENCY, thisRequest);
    request.setForcedFlag(true); // always build
    // properties can be set here as well
    
listener = new BlockingEventListener(request, UnitOfWork.getCurrent().getUser());
    try {
        listener.register();
        BuildService.getInstance().runBuild(request);
        
listener.waitForEvent();
        
endEvent = listener.getEvent();
        if (endEvent.getCase().getStatus().isSuccess()) {
            BuildLifeLookup.getCurrent().addDependencyBuildLife(endEvent.getCase().getBuildLife());
            UnitOfWork.getCurrent().commit();
        }
        else {
            throw new CommandException("Dependency Request Failed: " + endEvent.getBuildRequest());
        }
    }
    finally {
        listener.unregister();
    }
    // END SECTION TO REPEAT FOR EACH DEPENDENCY
}
catch (Exception e) {
    throw new CommandException("Dependency Request Failed: " + e.getMessage(), e);
}


// continue processing the other dependencies .... 

List Everything Scheduled

AHPSCRIPTS-120

import com.urbancode.anthill3.services.scheduler.*; 

 scheduler = Scheduler.getInstance().getImplementation(); 

 for (jobGroupName : scheduler.getJobGroupNames()) { 
     commandOutput.println("Job Group Name: " + jobGroupName); 
     for (jobName : scheduler.getJobNames(jobGroupName)) { 
         commandOutput.println(" Job Name: " + jobName); 
         jobDetail = scheduler.getJobDetail(jobName, jobGroupName); 
         commandOutput.println(" Job Detail: " + jobDetail); 
         jobDataMap = jobDetail.getJobDataMap(); 
         for (jobDataKey : jobDataMap.getKeys()) { 
             commandOutput.println(" Data: " + jobDataKey + " = " + jobDataMap.get(jobDataKey)); 
         } 
         commandOutput.println(""); 
     } 
 }

Need Report of Agents Not In Environments

AHPSCRIPTS-117

import com.urbancode.anthill3.domain.reporting.*; 

 ReportMetaData rmd = new ReportMetaData(); 

 rmd.addColumn("Agent"); 

 return rmd; 

 ================================================ 

 import com.urbancode.anthill3.domain.agent.*; 
 import com.urbancode.anthill3.domain.reporting.*; 
 import com.urbancode.anthill3.domain.servergroup.*; 

 ReportOutput output = new ReportOutput(metaData); 

 envs = ServerGroupFactory.getInstance().restoreAll(); 
 agents = AgentFactory.getInstance().restoreAllConfigured(); 

 for (Agent agent : agents) { 
     boolean agentInEnv = false; 
     for (ServerGroup env : envs) { 
         if (env.containsServer(agent)) { 
             agentInEnv = true; 
             break; 
         } 
     } 
      
     if (!agentInEnv) { 
         ReportRow row = new ReportRow(output, String.valueOf(agent.getId())); 
         row.setColumnValue("Agent", agent.getName()); 
         output.addRow(row); 
     } 
 } 
 return output;

Overwrite Dependency Pushed Properties

  • AnthillPro pushes properties to builds triggered by dependencies, this script overwrites the values for the properties that are defined on the dependent worfklow/project

AHPSCRIPTS-101

import com.urbancode.anthill3.domain.buildrequest.BuildRequest; 
 import com.urbancode.anthill3.domain.buildrequest.RequestSourceEnum; 
 import com.urbancode.anthill3.domain.persistent.PersistenceException; 
 import com.urbancode.anthill3.domain.project.Project; 
 import com.urbancode.anthill3.domain.project.prop.ProjectProperty; 
 import com.urbancode.anthill3.domain.property.PropertyValue; 
 import com.urbancode.anthill3.domain.workflow.Workflow; 
 import com.urbancode.anthill3.persistence.UnitOfWork; 
 import com.urbancode.anthill3.runtime.scripting.helpers.BuildRequestLookup; 
 import com.urbancode.anthill3.runtime.scripting.helpers.ProjectLookup; 
 import com.urbancode.anthill3.runtime.scripting.helpers.WorkflowLookup; 

 import java.util.HashMap; 
 import java.util.Map; 


 try { 
     BuildRequest request = BuildRequestLookup.getCurrent(); 
     if (request != null && RequestSourceEnum.DEPENDENCY.equals(request.getRequestSource()) && 
             request.getPropertyNames().length > 0) { 
         Project project = ProjectLookup.getCurrent(); 
         Workflow workflow = WorkflowLookup.getCurrent(); 
         Map<String, PropertyValue> changedPropertyMap = new HashMap<String, PropertyValue>(); 
         for (String property : request.getPropertyNames()) { 
             PropertyValue initialValue = request.getPropertyValue(property); 

             // check the workflow first 
             PropertyValue originalValue = workflow.getPropertyValue(property); 

             // if not on the workflow check the project 
             if (originalValue == null) { 
                 ProjectProperty projectProp = project.getProperty(property); 
                 if (projectProp != null) { 
                     originalValue = new PropertyValue(projectProp.getValue(), false); 
                 } 
             } 

             // and now see if they match 
             if (originalValue != null && !originalValue.equals(initialValue)) { 
                 changedPropertyMap.put(property, originalValue); 
             } 
             else if (originalValue == null) { 
                 commandOutput.println("Could not find original value for " + property); 
             } 
             else { 
                 commandOutput.println("Value did not change for " + property); 
             } 
         } 

         if (changedPropertyMap.size() > 0) { 
             request = (BuildRequest) UnitOfWork.getCurrent().lockAndReload(request); 
             for (String property : changedPropertyMap.keySet()) { 
                 request.setPropertyValue(property, changedPropertyMap.get(property)); 
                 commandOutput.println("Replaced value of " + property + " with " + 
                         changedPropertyMap.get(property).getDisplayedValue()); 
             } 
             try { 
                 UnitOfWork.getCurrent().commit(); 
             } 
             catch (PersistenceException pe) { 
                 pe.printStackTrace(commandOutput); 
                 try { 
                     UnitOfWork.getCurrent().cancel(); 
                 } 
                 catch (Exception e) { 
                 } 
             } 
         } 
     } 
     else { 
         commandOutput.println("Not a dependency request!"); 
     } 


 } 
 catch (Throwable t) { 
     t.printStackTrace(commandOutput); 
 }

Parse Output of a Command and Create Report Containing Errors Found in it

AHPSCRIPTS-20

import com.urbancode.anthill3.domain.singleton.serversettings.*;
 import com.urbancode.anthill3.domain.workflow.WorkflowCase ;
 import com.urbancode.vcsdriver3.*;
 import com.urbancode.anthill3.domain.buildlife.*;
 import com.urbancode.anthill3.domain.jobtrace.*;
 import com.urbancode.anthill3.domain.jobtrace.buildlife.*;
 import com.urbancode.anthill3.runtime.paths.*;
 import com.urbancode.anthill3.services.jobs.*;
 import com.urbancode.devilfish.services.var.VarService;
 import java.io.*;
 import java.util.*;

 private org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger("ContextScript");

 // SETTINGS
 // FOUND_TOKEN: indication of build failure
 // BUILD_STEP_NAME: Name of the step within the job that should be inspected
 // COMMAND_NAME: Command within the build step that should have its logged inspected
 // REPORT_NAME: Name of the report to publish.
 // LINES_BEFORE: Lines before and including the 'Found Token' to include in the log.
 // LINES_AFTER: Lines after the 'Found Token' to include in the log.

 String FOUND_TOKEN = "error";
 String BUILD_STEP_NAME = "Echo";
 String COMMAND_NAME = "shell-command";
 String REPORT_NAME = "Error Report";
 int LINES_BEFORE = 6;
 int LINES_AFTER = 1;

 //-------------------------------------------------------
 class LogSection {
 int lineNumber = 0;
     String text = null;

 LogSection(int lineNumber, String text) {
 this.lineNumber = lineNumber;
 this.text = text;
 }
 }

 //-------------------------------------------------------
 LogSection[] getLogSectionsForStep(StepTrace step) {
    CommandTrace[] cmdTraceArray = step.getCommandTraceArray();
    CommandTrace antCmdTrace = null;
    for (int i = 0; i < cmdTraceArray.length; i++) {
        if (cmdTraceArray[i].getName().equalsIgnoreCase(COMMAND_NAME)) {
            cmdTrace = cmdTraceArray[i];
            log.warn("Found the command we want: " + cmdTraceArray[i].getName());
            break;
        }
   }
   if (cmdTrace == null) {
        throw new Exception("Expected to find" + COMMAND_NAME + "command in " + BUILD_STEP_NAME + " step");
   }

 String commandOutput = LogHelper.getOutput(cmdTrace);
   List resultList = new LinkedList();
   String[] logCache = new String[LINES_BEFORE];
   if (commandOutput != null) {
       StringTokenizer logfile = new StringTokenizer(commandOutput,"\n\r\f");
       int index = 0;
       while (logfile.hasMoreTokens()) {
            String line = logfile.nextToken();
            logCache[index % LINES_BEFORE] = line;
            if (line.startsWith(FOUND_TOKEN)) {
                int lineNumber = index + 1;
                StringBuffer result = new StringBuffer();
                // put the cached lines into the log.
                int startIndex = (index > LINES_BEFORE) ? index - LINES_BEFORE + 1 : 0;
                for (int i = startIndex; i <= index; i++) {
                    if (i == index) {
                        result.append("<b>");
                    }
                    result.append(i + 1).append(": ").append(logCache[i % LINES_BEFORE]).append("\n");
                    if (i == index) {
                        result.append("</b>");
                    }
                }
                // get lines after if applicable
                for (int i = 0; i < LINES_AFTER && logfile.hasMoreTokens(); i++) {
                    String next = logfile.nextToken();
                    index++;
                    result.append(index + 1).append(": ").append(next).append("\n");
                }
                LogSection marker = new LogSection(lineNumber, result.toString());
                resultList.add(marker);
            }
            index++;
        }
    }
    return (LogSection[]) resultList.toArray(new LogSection[resultList.size()]);
 }

 //-------------------------------------------------------

 LogSection[] logSections = null;
 BuildLifeJobTrace jobTrace = JobTraceLookup.getCurrent();
 StepTrace[] stepTraceArray = jobTrace.getStepTraceArray();
 StepTrace stepTrace = null;
 for (int j = 0; j < stepTraceArray.length && stepTrace == null; j++) {
     if (stepTraceArray[j].getName().equalsIgnoreCase(BUILD_STEP_NAME)) {
         stepTrace = stepTraceArray[j];
         logSections = getLogSectionsForStep(stepTrace);
     }
 }

 String reportPath = PublishPathHelper.getInstance().getPublishPath(JobTraceLookup.getCurrent(), REPORT_NAME);
 VarService vs = VarService.getInstance();
 reportPath = vs.resolve(reportPath);

 File reportDir = new File(reportPath);
 reportDir.mkdirs();

 File reportFile = new File(reportDir, "Error_Report.html");
 FileWriter writer = new FileWriter(reportFile);
 writer.write("<html><head><style>");
 writer.write(".errors {");
 writer.write(" border: 1px solid #f04040;");
 writer.write(" background-color: #ffa0a0;");
 writer.write(" font-family: arial, helvetica, sans-serif;");
 writer.write(" font-size: 11px;");
 writer.write(" color: #000000;");
 writer.write("}");
 writer.write(".errors_header {");
 writer.write(" border-bottom: 1px solid #f04040;");
 writer.write(" background-color: #f04040;");
 writer.write(" font-size: 12px;");
 writer.write(" font-weight: bold;");
 writer.write(" color: #FFFFFF;");
 writer.write(" padding: 4px;");
 writer.write("}");
 writer.write(".errors_body {");
 writer.write(" margin-right: 10px;");
 writer.write(" padding-top: 4px;");
 writer.write(" padding-left: 4px;");
 writer.write(" padding-bottom: 4px;");
 writer.write("}");
 writer.write(".errors_section {");
 writer.write(" margin-left: 15px;");
 writer.write(" padding-top: 4px;");
 writer.write(" padding-left: 4px;");
 writer.write(" padding-bottom: 4px;");
 writer.write("}");
 writer.write(".errors_output {");
 writer.write(" margin-top: 4px;");
 writer.write(" margin-left: 15px;");
 writer.write(" background-color: #FFFFFF;");
 writer.write(" padding-top: 4px;");
 writer.write(" padding-left: 4px;");
 writer.write(" padding-bottom: 4px;");
 writer.write("}");

 writer.write("</style></head><body>");
 writer.write("<div class=\"errors\">");
 writer.write("<div class=\"errors_header\">Errors:</div>");
 writer.write("<div class=\"errors_body\">");
 writer.write("<div class=\"errors_section\">");
 writer.write("<b>Step " + (stepTrace.getSeq() + 1) + ": " + stepTrace.getName() + " Failed</b>");
 for (int i=0; i<logSections.length; i++) {
     writer.write("<ppre class=\"errors_output\">");
     writer.write(logSections[i].text);
     writer.write("</ppre>");
 }
 writer.write("</div>");
 writer.write("</div>");
 writer.write("</div>");
 writer.write("</body></html>");
 writer.close();

Parse SVN Revision Number from Checkout Output

AHPSCRIPTS-66

// looking for "Checked out revision 19642."
stepName = "Populate Workspace";
revisionStart = "Checked out revision ";
revisionEnd = ".";

latestRevision = 0;

jobTrace = JobTraceLookup.getCurrent();
steps = jobTrace.getStepTraceArray();
step = null;
for (int s=0; s<steps.length; s++) {
    if (stepName.equals(steps[s].getName())) {
        step = steps[s];
        break;
    }
}
commands = step.getCommandTraceArray();
for (int c=0; c<commands.length; c++) {
    if (commands[c].getName().startsWith("populate-workspace")) {
        log = LogHelper.getOutput(commands[c]);
        start = log.lastIndexOf(revisionStart);
        if (start < 0) {
            commandOutput.println("Revision not found in " + commands[c].getName());
        }
        else {
            start += revisionStart.length();
            log = log.substring(start);
            end = log.indexOf(revisionEnd);
            if (end < 0) {
                commandOutput.println("Revision not found in " + commands[c].getName());
            }
            else {
                rev = Long.parseLong(log.substring(0, end).trim());
                
if (rev > latestRevision) {
                    latestRevision = rev;
                }
            }
        }
    }
}

if (latestRevision > 0) {
    BuildRequestLookup.getCurrent().setProperty("svn.revision", String.valueOf(latestRevision));
    commandOutput.println("Found revision " + latestRevision);
}
else {
    commandOutput.println("Revision not found in " + jobTrace.getName());
}

Properties Contained Within Variables

Script Notes:

  • The idea here is that the user has identified a couple agent items (a Track and technology type) that span environments. This scirpt filters agents so that the technology type must always match the technology type specified on the workflow property. The tracks are similar but some agents may participate in mulitple tracks (prod is that same for all) so prod would have a track value of something like 1|2|3 to indicate that it supports tracks 1, 2 and 3. So we need to inspect it to see if any match.
  • I changed the Track one to just see if the agent value contains the requested value. It should work fine until you get up to track 10, then you have to do 01, 02, etc.

AHPSCRIPTS-2

import com.urbancode.anthill3.domain.agent.Agent;
import com.urbancode.anthill3.runtime.scripting.helpers.* ;
import com.urbancode.anthill3.services.agent.AgentRemoteControl;
import com.urbancode.devilfish.services.var.VarServiceClient;
import java.util.*;

public class PropertyBasedAgentVarEqualsCriteria extends VariableEqualsCriteria {

String propertyname;

public PropertyBasedAgentVarEqualsCriteria(String propertyname, String varName) {
        super(varName);
        this.propertyname = propertyname;
    }

public Agent[] filter(Agent[] agents) {
        String value = PropertyLookup.get(propertyname);
        if (value == null || value.length() == 0 || "null".equals(value)) {
            value = BuildLifeLookup.getCurrent().getOriginatingWorkflow().getRequest().getProperty(propertyname);
        }
        this.setValue(value);
        return super.filter(agents);
    }
}

public class PropertyBasedAgentVarContainsCriteria extends Criteria {

String propertyname;
    String varName;

public PropertyBasedAgentVarContainsCriteria(String propertyname, String varName) {
        this.propertyname = propertyname;
        this.varName = varName;
    }

public Agent[] filter(Agent[] agents) {
        ArrayList resultList = new ArrayList();
        
String value = PropertyLookup.get(propertyname);
        if (value == null || value.length() == 0 || "null".equals(value)) {
            value = BuildLifeLookup.getCurrent().getOriginatingWorkflow().getRequest().getProperty(propertyname);
        }
        
for (int i = 0; i < agents.length; i++) {
            Agent agent = agents[i];
            
AgentRemoteControl remote = new AgentRemoteControl(agent);
            VarServiceClient client;
            try {
                client = remote.getVarServiceClient();

String varValue = client.getVarValue(varName);
                if (varValue != null && varValue.contains(value)) {
                    resultList.add(agent);
                }
            }
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        
Agent[] result = new Agent[resultList.size()];
        resultList.toArray(result);
        return result;
    }
}


/**** Start Script *****/
return Where.all(
   new PropertyBasedAgentVarContainsCriteria("Track", "Track"),
   new PropertyBasedAgentVarEqualsCriteria("TechType", "TechType")
);

Publish Output of Step Command in File in Report

AHPSCRIPTS-111

import com.urbancode.anthill3.domain.jobtrace.*; 
 import com.urbancode.anthill3.domain.workflow.*; 
 import com.urbancode.anthill3.runtime.paths.*; 
 import com.urbancode.anthill3.services.file.*; 
 import com.urbancode.devilfish.services.file.FileInfo; 
 import com.urbancode.devilfish.services.var.VarService; 
 import java.io.*; 

 private String getStreamAsString(InputStream inStream) 
 throws IOException { 
     StringBuffer result = new StringBuffer(); 
     try { 
         byte[] buffer = new byte[4096]; 
         int length = 0; 
         while ((length = inStream.read(buffer)) > 0) { 
             result.append(new String(buffer, 0, length)); 
         } 
     } 
     finally { 
         try { 
             inStream.close(); 
         } 
         catch (Exception e) {} 
     } 
     return result.toString(); 
 } 


 String REPORT_NAME = "DB Log"; 
 String REPORT_FILE = "Database_Log.txt"; 
 String STEP_NAME = "Execute Database Patches"; // change to the name of the step 

 JobTrace jobTrace = JobTraceLookup.getCurrent(); 

 StepTrace[] stepTraces = jobTrace.getStepTraceArray(); 
 for (int s=0; s<stepTraces.length; s++) { 
     if (STEP_NAME.equals(stepTraces[s].getName())) { 
         // found the step 
         CommandTrace cmdTrace = stepTraces[s].getCommandTraceArray()[0]; 
         FileInfo outputFile = LogPathHelper.getInstance().getLogFileInfoArray(cmdTrace)[0]; 
         InputStream inStream = FileInfoService.getInstance().getFileInfoAsStream(outputFile); 
         String output = getStreamAsString(inStream); 
          
         // create a report 
         String reportPath = PublishPathHelper.getInstance().getPublishPath(JobTraceLookup.getCurrent(), REPORT_NAME); 
         VarService vs = VarService.getInstance(); 
         reportPath = vs.resolve(reportPath); 
          
         File reportDir = new File(reportPath); 
         reportDir.mkdirs(); 
          
         File reportFile = new File(reportDir, REPORT_FILE); 
         FileWriter writer = new FileWriter(reportFile); 
         writer.write(output); 
         writer.close(); 
          
         break; 
     } 
 }

Put the Output of a Step in an E-Mail

AHPSCRIPTS-103

import com.urbancode.anthill3.domain.jobtrace.*; 
 import com.urbancode.anthill3.domain.workflow.*; 
 import com.urbancode.anthill3.runtime.paths.*; 
 import com.urbancode.anthill3.services.file.*; 
 import com.urbancode.devilfish.services.file.FileInfo; 
 import java.io.*; 

 private String getStreamAsString(InputStream inStream) 
 throws IOException { 
     StringBuffer result = new StringBuffer(); 
     try { 
         byte[] buffer = new byte[4096]; 
         int length = 0; 
         while ((length = inStream.read(buffer)) > 0) { 
             result.append(new String(buffer, 0, length)); 
         } 
     } 
     finally { 
         try { 
             inStream.close(); 
         } 
         catch (Exception e) {} 
     } 
     return result.toString(); 
 } 


 String STEP_NAME = "ant-build"; // change to the name of the step 

 WorkflowCase workflow = (WorkflowCase) context.get("workflow"); 
 JobTrace[] jobTraceArray = workflow.getJobTraceArray(); 

 // find the job trace you want in some meaningful way (this uses the first) 
 JobTrace jobTrace = jobTraceArray[0]; 

 StepTrace[] stepTraces = jobTrace.getStepTraceArray(); 
 for (int s=0; s<stepTraces.length; s++) { 
     if (STEP_NAME.equals(stepTraces[s].getName())) { 
         // this is the step 
         CommandTrace cmdTrace = stepTraces[s].getCommandTraceArray()[0]; 
         FileInfo outputFile = LogPathHelper.getInstance().getLogFileInfoArray(cmdTrace)[0]; 
         InputStream inStream = FileInfoService.getInstance().getFileInfoAsStream(outputFile); 
         context.put("ant-output", getStreamAsString(inStream)); 
         break; 
     } 
 }

Replicate Permissions of One Role to Another

AHPSCRIPTS-133

import com.urbancode.anthill3.domain.security.Permission; 
 import com.urbancode.anthill3.domain.security.PermissionFactory; 
 import com.urbancode.anthill3.domain.security.Resource; 
 import com.urbancode.anthill3.domain.security.ResourceType; 
 import com.urbancode.anthill3.domain.security.ResourceTypeFactory; 
 import com.urbancode.anthill3.domain.security.Role; 
 import com.urbancode.anthill3.domain.security.RoleFactory; 
 import com.urbancode.anthill3.persistence.UnitOfWork; 
 import java.util.*; 

 /* 
 Beanshell script to be run in a Evaluate Script Step. 
 This script will repliact permission from one role to another. 
  - Adjust the role names for your use before running. 
  - Adjust the resource types at the bottom to control the types of permissions replicate. 
 */ 
      
 addPermissionToMap(HashMap map, Permission permission) { 
     resource = permission.getResource(); 
     actions = map.get(resource); 
     if (actions == null) { 
         actions = new HashSet(); 
         map.put(resource, actions); 
     } 
     actions.add(permission.getAction()); 
 } 

 copyResourceTypePermissions(Role source, Role dest, long resourceTypeId) { 
     resourceType = ResourceTypeFactory.getInstance().restore(resourceTypeId); 
      
     permissions = PermissionFactory.getInstance().restoreAllForResourceType(resourceType); 
      
     sourceMap = new HashMap(); 
     destMap = new HashMap(); 
      
     for (Permission permission : permissions) { 
         if (source.equals(permission.getRole())) { 
             addPermissionToMap(sourceMap, permission); 
         } 
         else if (dest.equals(permission.getRole())) { 
             addPermissionToMap(destMap, permission); 
         } 
     } 
      
     for (Resource resource : sourceMap.keySet()) { 
         sourceActions = sourceMap.get(resource); 
         destActions = destMap.get(resource); 
          
         if (destActions != null) { 
             sourceActions.removeAll(destActions); 
         } 
          
         for (String action : sourceActions) { 
             // create the permission 
             commandOutput.println("Adding " + action + " to " + resource); 
             Permission permission = new Permission(resource, action, dest); 
             permission.store(); 
         } 
     } 
 } 

 source = RoleFactory.getInstance().restoreForName("Source"); 
 dest = RoleFactory.getInstance().restoreForName("Destination"); 

 copyResourceTypePermissions(source, dest, ResourceType.TYPE_PROJECT); 
 copyResourceTypePermissions(source, dest, ResourceType.TYPE_ENVIRONMENT); 
 copyResourceTypePermissions(source, dest, ResourceType.TYPE_WORKFLOW); 
 copyResourceTypePermissions(source, dest, ResourceType.TYPE_CODESTATON); 
 copyResourceTypePermissions(source, dest, ResourceType.TYPE_REPOSITORY); 
 copyResourceTypePermissions(source, dest, ResourceType.TYPE_FOLDER); 
 copyResourceTypePermissions(source, dest, ResourceType.TYPE_LIBRARY_WORKFLOW); 
 copyResourceTypePermissions(source, dest, ResourceType.TYPE_LIBRARY_JOB); 
 copyResourceTypePermissions(source, dest, ResourceType.TYPE_AGENT); 
 copyResourceTypePermissions(source, dest, ResourceType.TYPE_ENV_GROUP); 

 UnitOfWork.getCurrent().commit();

Retrieve Stamp From Dependent Project so it is Passed as Property

  • This script assumes that some Project A, is dependent on some Project B. This script would be placed in an Evaluate Script Step, on a Generic Build Job. The script, looks up the most recent stamp value for Project B, and then saves the stamp as a BuildRequest Property. This allows the property to be passed/referenced by using the format
    • ${property: stampValue}

AHPSCRIPTS-15

import com.urbancode.anthill3.domain.buildlife.*; 
 import com.urbancode.anthill3.runtime.scripting.helpers.*; 
 import com.urbancode.codestation2.domain.buildlife.CodestationCompatableBuildLife ; 
 import com.urbancode.codestation2.domain.project.*; 
 import java.util.ArrayList ; 
 import java.lang.Object; 
 import com.urbancode.anthill3.persistence.UnitOfWork; 
 import com.urbancode.anthill3.domain.buildrequest.BuildRequestStatusEnum; 
 import com.urbancode.anthill3.domain.buildrequest.RequestSourceEnum ; 
 import com.urbancode.anthill3.domain.persistent.Handle; 
 import com.urbancode.anthill3.domain.persistent.Persistent; 
 import com.urbancode.anthill3.domain.buildrequest.*; 
 UnitOfWork uow = UnitOfWork.getCurrent (); 
 static final String PROJECT_NAME = "Project B"; 

 //Get most current buildlife. 
 BuildLife blife = BuildLifeLookup.getCurrent(); 
 BuildRequest br = BuildRequestLookup.getCurrent(); 
 //Get dependency Array 
 CodestationCompatableBuildLife[] dArray =blife.getDependencyBuildLifeArray(); 

 String stamp = null; 
 for (int i = 0; i < dArray.length && stamp == null; i++) { 
         if (dArray[i].getCodestationProject() != null && 
             dArray[i].getCodestationProject() instanceof AnthillProject) { 
             AnthillProject project = (AnthillProject) 
 dArray[i].getCodestationProject(); 
             String temp = project.getBuildProfile ().getProject().getName(); 
             if (temp.equals(PROJECT_NAME)){ 
                 stamp = dArray[i].getLatestStampValue(); 
            } 
     } 

 } 
 br.setProperty("Stamp_Value", stamp); 
 uow.commit();

Roll Back: If Step Fails During Deployment, Look Up Previously Deployed Build and Re-Deploy It

AHPSCRIPTS-122

import com.urbancode.anthill3.runtime.scripting.helpers; 
 import com.urbancode.anthill3.domain.servergroup.*; 
 import com.urbancode.anthill3.domain.buildrequest.*; 
 import com.urbancode.anthill3.domain.buildlife.*; 
 import com.urbancode.anthill3.services.build.*; 
 import com.urbancode.anthill3.domain.security.*; 

 //Get the useful information 

 currentEnv = EnvironmentLookup.getCurrent(); 
 currentWorkflow = WorkflowLookup.getCurrent(); 
 envShortName = currentEnv.getShortName(); 
 status = StatusLookup.getStatusByName(envShortName); 
 currentBuildLife = BuildLifeLookup.getCurrent(); 
 currentBuildRequest = BuildRequestLookup.getCurrent(); 
 requester = currentBuildRequest.getRequester(); 
 currentUser = currentBuildRequest.getUser(); 
 currentBuildProfile = currentBuildLife.getProfile(); 

 //Determine the last deployed build for a particular environment 

 previousDeployed = BuildLifeFactory.getInstance().restorePriorMostRecentForProfileAndStatus(currentBuildLife, currentBuildProfile, status); 


 // Create the new build request 

 BuildRequest newBuildRequest = new BuildRequest(previousDeployed, currentWorkflow, currentEnv, currentUser, RequestSourceEnum.EVENT, requester); 

 //store it 

 newBuildRequest.store(); 

 //Run the workflow 

 BuildService.getInstance().runWorkflow(newBuildRequest);

Run Another Non-Originating Workflow On Same Build Life

  • Used as an evaluate script step

AHPSCRIPTS-33

import com.urbancode.anthill3.runtime.scripting.helpers.*;
 import com.urbancode.anthill3.services.build.*;
 import com.urbancode.anthill3.AnthillRuntimeException.*;
 import com.urbancode.anthill3.domain.buildrequest.*;
 import com.urbancode.anthill3.domain.buildlife.*;
 import com.urbancode.anthill3.domain.workflow.*;
 import com.urbancode.anthill3.domain.servergroup.*;
 import com.urbancode.anthill3.domain.security.*;
 import com.urbancode.anthill3.domain.persistent.*;
 import com.urbancode.anthill3.domain.project.*;


 String wf = PropertyLookup.getValue("workflow_prop");
 Project prj = ProjectLookup.getCurrent();
 BuildLife bl = BuildLifeLookup.getCurrent();
 Workflow wflow = WorkflowLookup.getForProjectAndName(prj, wf);
 ServerGroup sg = ServerGroupLookup.getCurrent();
 User usr = BuildRequestLookup.getCurrent().getUser();
 RequestSourceEnum rse = BuildRequestLookup.getCurrent().getRequestSource();
 Persistent req = BuildRequestLookup.getCurrent().getRequester();


 BuildRequest br = new BuildRequest(bl, wflow, sg, usr, rse, req);
 BuildService.getInstance().runWorkflow(br);

Run Originating Workflow and Wait Until Workflow is Finished

AHPSCRIPTS-132

import com.urbancode.anthill3.domain.buildrequest.BuildRequest; 
 import com.urbancode.anthill3.domain.project.Project; 
 import com.urbancode.anthill3.domain.project.ProjectFactory; 
 import com.urbancode.anthill3.domain.security.UserFactory; 
 import com.urbancode.anthill3.domain.workflow.WorkflowCase; 
 import com.urbancode.anthill3.domain.workflow.WorkflowEndEvent; 
 import com.urbancode.anthill3.domain.workflow.WorkflowEvent; 
 import com.urbancode.anthill3.persistence.UnitOfWork; 
 import com.urbancode.anthill3.services.build.BuildService; 
 import com.urbancode.anthill3.services.event.EventListener; 
 import com.urbancode.anthill3.services.event.EventService; 
 import com.urbancode.anthill3.services.event.criteria.Criteria; 
 import com.urbancode.anthill3.services.event.criteria.FieldEqualsCriteria; 

 import com.urbancode.anthill3.persistence.UnitOfWork; 
 import com.urbancode.anthill3.domain.buildrequest.*; 
 import com.urbancode.anthill3.domain.project.*; 
 import com.urbancode.anthill3.domain.security.*; 
 import com.urbancode.anthill3.services.build.*; 

 import java.util.EventObject; 

 class WorkflowEndEventListener implements EventListener { 
          
     private BuildRequest request; 
     private boolean success = false; 
      
     WorkflowEndEventListener(BuildRequest request) { 
         this.request = request; 
     } 
      
     public boolean isSuccess(){ 
         return success; 
     } 
      
     synchronized public void handleEvent(EventObject event) { 
         if (!(event instanceof WorkflowEvent)) { 
             throw new IllegalArgumentException( "The parameter event must be an instance of a WorkflowEvent!" ); 
         } 
         UnitOfWork uow = null; 
         try { 
             uow = UnitOfWork.create(UserFactory.getSystemUser()); 
             WorkflowCase wcase = ((WorkflowEvent) event).getCase(); 
             success = (wcase.getStatus() != null && wcase.getStatus().isSuccess()); 
         } 
         catch (Exception e) { 
             throw new RuntimeException(e.getMessage(), e); 
         } 
         finally { 
             if (uow != null) { 
                 uow.close(); 
             } 
         } 
         this.notify(); 
     } 

     public Class getEventClass() { 
         return WorkflowEndEvent.class; 
     } 

     public Criteria[] getCriteria() { 
         return new Criteria[]{ 
               new FieldEqualsCriteria("request", request) 
         }; 
     } 
 } 
      
      
 buildAndWait(String projectName, String workflowName) 
 throws Exception { 
     project = ProjectFactory.getInstance().restoreForName(projectName); 
 wflow = project.getWorkflow(workflowName); 

 buildService = BuildService.getInstance(); 
 user = UnitOfWork.getCurrent().getUser(); 
 request = new BuildRequest(wflow.getBuildProfile(), user, RequestSourceEnum.REPOSITORY, user ); 
 request.setForcedFlag(true); 
 request.store(); 
 UnitOfWork.getCurrent().commit(); 

 listener = new WorkflowEndEventListener(request); 
 EventService.getInstance().registerEventListener(listener); 
 try { 
 BuildService.getInstance().runBuild(request); 
 synchronized (listener) { 
 listener.wait(); 
 } 

 if (!listener.isSuccess()) { 
 throw new Exception(projectName + " - " + workflowName + " failed."); 
 } 
 } 
 finally { 
 EventService.getInstance().removeEventListener(listener); 
 } 
 } 


 buildAndWait("project", "workflow");

Script That Optionally Cleans Working Directory

  • Sometimes we want to clean the workflow directory, other times we don't. The determination is property drive.

AHPSCRIPTS-34

import com.urbancode.anthill3.command.workdir.PathBuilder;
 import com.urbancode.anthill3.domain.source.*;
 import com.urbancode.anthill3.domain.workdir.*;
 import com.urbancode.command.path.Path;
 import com.urbancode.devilfish.services.file.*;

 org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger("OptionallyCleanWorkingDirectory");

 SourceConfig source = SourceConfigLookup.getCurrent();
 if (source instanceof WithWorkDirScript) {
     WorkDirScript workDirConfig = ((WithWorkDirScript) source).getWorkDirScript();
     Path workDirPath = PathBuilder.buildPath(workDirConfig);
     WorkDirPath.setPath(workDirPath);
     log.warn("Setting working directory to " + workDirPath.getPathStr());
 }
 else {
     log.warn("NOT setting working directory. Source Configuration does not support it.");
 }

 if (Boolean.valueOf(PropertyLookup.getValue("shouldCleanup")).booleanValue()) {
     log.warn("Workflow property configured to clean the working directory.");
     FileServiceClient service = new FileServiceClient(JobTraceLookup.getCurrent().getAgent().getEndpoint());

 File workDir = new File(WorkDirPath.get().getPathStr());
     FileInfo info = service.getFileInfo(workDir);

 if (info.exists()) {
         log.warn("Directory exists. Deleting directory \'"+info.getPath()+"\'.");

 results = service.deleteFile(workDir);

 log.warn("Cleanup of " + info.getPath() + " complete!");
         log.warn("Successfully removed " + results.filesDeleted + " files/directories.");
         log.warn("Failed to remove " + results.getFailedDeletionCount() + " files/directories.");
         if (results.hasFailedDeletions()) {
             throw new Exception("Failed to clean the working directory");
         }
     }
     else {
         log.warn("Directory does not exist. No action needed.");
     }
 }
 else {
     log.warn("Workflow property configured to NOT clean the working directory.");
 }

Script to Update Workflow Property with Names of All Agents in Environment

  • You can use the script with an Evaluate Script Step. You need to change the projectName, workflowName, envName and propertyName values to match your requirements.

AHPSCRIPTS-93

import com.urbancode.anthill3.domain.agent.Agent; 
 import com.urbancode.anthill3.domain.agent.AgentFactory; 
 import com.urbancode.anthill3.domain.project.Project; 
 import com.urbancode.anthill3.domain.project.ProjectFactory; 
 import com.urbancode.anthill3.domain.servergroup.ServerGroup; 
 import com.urbancode.anthill3.domain.servergroup.ServerGroupFactory; 
 import com.urbancode.anthill3.domain.workflow.Workflow; 
 import com.urbancode.anthill3.domain.workflow.WorkflowFactory; 
 import com.urbancode.anthill3.domain.workflow.WorkflowProperty; 
 import com.urbancode.anthill3.domain.workflow.WorkflowPropertyTypeEnum; 
 import com.urbancode.devilfish.client.ServiceEndpoint; 

 import java.io.PrintStream; 
 import java.util.ArrayList; 
 import java.util.List; 

 try { 

     String projectName = "some project"; 
     String workflowName = "some workflow that has a multi select property defined"; 
     String envName = "some environment"; 
     String propertyName = "the property to update that's defined in the workflow above"; 
     List valueList = new ArrayList(); 

     // get all agents that belong to an environment, are configured and not ingnored 
     ServerGroup envirnoment = ServerGroupFactory.getInstance().restoreForName(envName); 
     if (envirnoment != null) { 
         for (ServiceEndpoint endpoint : envirnoment.getServerArray()) { 
             Agent agent = AgentFactory.getInstance().restoreByEndpoint(endpoint); 
             if (agent != null && agent.isConfigured() && !agent.isIgnored()) { 
                 valueList.add(agent.getName()); 
             } 
         } 
     } 

     // now locate the workflow property that you want to update 
     Project project = ProjectFactory.getInstance().restoreForName(projectName); 
     if (project != null) { 
         Workflow workflow = WorkflowFactory.getInstance().restoreForProjectAndWorkflowName(project, workflowName); 
         if (workflow != null) { 
             WorkflowProperty property = workflow.getProperty(propertyName); 
             // here you can change/remove the check for the property type if you want 
             if (property != null && property.getType().equals(WorkflowPropertyTypeEnum.MULTI_SELECT)) { 
                 property.setAllowedValues((String[])valueList.toArray(new String[valueList.size()])); 
             } 
         } 
     } 
 } 
 catch (Exception e) { 
     e.printStackTrace(commandOutput); 
 }

Script Which Can be Used to Trigger All Delayed Builds to Run Immediately

AHPSCRIPTS-107

import com.urbancode.anthill3.domain.buildrequest.*; 
 import com.urbancode.anthill3.domain.schedule.*; 
 import com.urbancode.anthill3.services.build.*; 

 buildRequestsArray=BuildRequestFactory.getInstance().restoreAllBuildLifeRequestsByStatus(BuildRequestStatusEnum.DELAYED_BUILD); 
 for (int i=0;i<buildRequestsArray.length;i++) 
 { 
   buildRequest=buildRequestsArray[i]; 
   buildRequestName=buildRequest.getName(); 
   commandOutput.println("buildRequestName="+buildRequestName); 

   buildRequestId=buildRequest.getId(); 
   commandOutput.println("buildRequestId="+buildRequestId); 

   buildRequestDelayUntil=buildRequest.getDelayUntilDate(); 
   commandOutput.println("buildRequestDelayUntil="+buildRequestDelayUntil); 

   // set the workflow to run on the next scheduled time 
   buildRequest.setDelayUntilDate(new Date()); 
   buildRequest.resetState(); 

   // store and schedule 
   buildRequest.store(); 

   BuildService.getInstance().runWorkflow(buildRequest); 
 }

Set Output of Previous Step's Command As Property

  • This sets the property output on the request

AHPSCRIPTS-95

job = JobTraceLookup.getCurrent(); 
 step = job.getStepTraceForSequence(job.getStepTraceArray().length - 2); 
 cmd = step.getCommandTraceForSequence(step.getCommandTraceArray().length - 1); 
 output = LogHelper.getOutput(cmd); 
 output = output.substring(output.indexOf("command output:") + 15); 
 output = output.substring(0, output.indexOf("command exit code:")); 
 PropertyLookup.set("output", output.trim());

Set Property Based on Results of RESOLVE DEPENDENCY ARTIFACTS Step

Use this script if you need a property to define whether the resolve step was successful or had conflicts.

AHPSCRIPTS-38

import com.urbancode.anthill3.services.jobs.*;

status = null;
workflow = WorkflowLookup.getCurrentCase();
jobs = workflow.getJobTraceArray();
for (int j=0; j<jobs.length; j++) {
    steps = jobs[j].getStepTraceArray();
    for (int s=0; s<steps.length; s++) {
        if ("Get Dependency Artifacts".equals(steps[s].getName())) {
            if (JobStatusEnum.SUCCESS_WARN.equals(steps[s].getStatus())) {
                status = steps[s].getStatus().getName();
            }
            else if (JobStatusEnum.SUCCESS.equals(steps[s].getStatus()) && status == null) {
                status = steps[s].getStatus().getName();
            }
        }
    }
}

// set the property
workflow.getRequest().setProperty("resolve.status", status); 

Show Test Changes

This is designed to be a "Evaluate a Script" step that creates a report that goes under the Build's report tab.

AHPSCRIPTS-62

import com.urbancode.anthill3.domain.buildlife.BuildLife;
import com.urbancode.anthill3.domain.jobtrace.JobTrace;
import com.urbancode.anthill3.domain.test.TestCase;
import com.urbancode.anthill3.domain.test.TestReport;
import com.urbancode.anthill3.domain.test.TestReportFactory;
import com.urbancode.anthill3.domain.test.TestSuite;
import com.urbancode.anthill3.runtime.paths.PublishPathHelper;
import com.urbancode.anthill3.runtime.scripting.helpers.BuildLifeLookup;
import com.urbancode.anthill3.runtime.scripting.helpers.JobTraceLookup;
import com.urbancode.anthill3.services.template.TemplateHelper;
import com.urbancode.commons.fileutils.FileUtils;
import com.urbancode.devilfish.services.var.VarService;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

try {
// helper class for the tests
class TestInstance {
String key = null;
String suite = null;
String test = null;
boolean success = false;
int duration = 0;
}

// two maps to hold test information about this and previous build lives
Map oldTestMap = new HashMap();
Map newTestMap = new HashMap();

TemplateHelper templateHelper = TemplateHelper.getInstance(null);

// populate the sets
BuildLife currentBuildLife = BuildLifeLookup.getCurrent();
TestReport[] testReportArray = TestReportFactory.getInstance()
.restoreAllForBuildLife(currentBuildLife);
for (int i = 0; i < testReportArray.length; i++) {
TestSuite[] testSuiteArray = testReportArray[i].getTestSuites();
for (int j = 0; j < testSuiteArray.length; j++) {
TestCase[] testCaseArray = testSuiteArray[j].getTestCases();
for (int k = 0; k < testCaseArray.length; k++) {
TestInstance testInstance = new TestInstance();
testInstance.suite = testSuiteArray[j].getName();
testInstance.test = testCaseArray[k].getName();
testInstance.key =
testInstance.test + testInstance.suite;
testInstance.success = "success"
.equalsIgnoreCase(testCaseArray[k].getResult());
testInstance.duration = testCaseArray[k].getTime();
newTestMap.put(testInstance.key, testInstance);
}
}
}

BuildLife lastSuccessBuildLife = BuildLifeLookup.mostRecentSuccess();
testReportArray = TestReportFactory.getInstance()
.restoreAllForBuildLife(lastSuccessBuildLife);
for (int i = 0; i < testReportArray.length; i++) {
TestSuite[] testSuiteArray = testReportArray[i].getTestSuites();
for (int j = 0; j < testSuiteArray.length; j++) {
TestCase[] testCaseArray = testSuiteArray[j].getTestCases();
for (int k = 0; k < testCaseArray.length; k++) {
TestInstance testInstance = new TestInstance();
testInstance.suite = testSuiteArray[j].getName();
testInstance.test = testCaseArray[k].getName();
testInstance.key =
testInstance.test + testInstance.suite;
testInstance.success = "success"
.equalsIgnoreCase(testCaseArray[k].getResult());
testInstance.duration = testCaseArray[k].getTime();
oldTestMap.put(testInstance.key, testInstance);
}
}
}

// get the path to the reports directory
JobTrace jobTrace = JobTraceLookup.getCurrent();
if (jobTrace != null) {
String publishPath = VarService.getInstance()
.resolve(PublishPathHelper.getInstance()
.getPublishPath(jobTrace, "Test Changes"));

FileUtils.assertDirectory(publishPath);

// create the report
File reportFile =
new File(publishPath, "Test Differences.html");
BufferedWriter writer =
new BufferedWriter(new FileWriter(reportFile));

writer.write("<HTML>\n" + "<HEAD>\n" +
"<TITLE>Anthill3 - Test Diff Report</TITLE>\n" +
                        "<link rel=\"StyleSheet\" href=\"/css/anthill3.css\" type=\"text/css\">" +
                        "</head>\n" + "<BODY>\n" + "<TABLE class=\"data-table\" WIDTH=\"100%\">\n" +
"\n" + "<TR><TD>\n" + "<H1>Test Diff Report</H1>\n" +
"</TD></TR>\n");

// output all tests that are new
writer.write("<TR><TD>\n" +
"<H2>New Tests:</H2>\n" +
"<table cellpadding=\"4\" cellspacing=\"1\" width=\"100%\">\n" +
"<TH>Suite</TH>\n" + "<TH>Test</TH>\n");
itr = newTestMap.keySet().iterator();
while (itr.hasNext()) {
String key = (String) itr.next();
TestInstance newTest = (TestInstance) newTestMap.get(key);
TestInstance oldTest = (TestInstance) oldTestMap.get(key);
if (newTest != null && oldTest == null) {
writer.write("<TR>");
writer.write("<TD VALIGN=\"top\">" + newTest.suite +
"</TD>");
writer.write(
"<TD VALIGN=\"top\">" + newTest.test + "</TD>");
writer.write("</TR>");
}
}
writer.write("</TABLE>\n" + "<BR/>\n" + "<BR/>\n" + "</TD></TR>");

// output all tests failed this time but succeeded before
writer.write("<TR><TD>\n" +
"<H2>New Failing Tests:</H2>\n" +
"<table cellpadding=\"4\" cellspacing=\"1\" width=\"100%\">\n" +
"<TH>Suite</TH>\n" + "<TH>Test</TH>\n");
itr = newTestMap.keySet().iterator();
while (itr.hasNext()) {
String key = (String) itr.next();
TestInstance newTest = (TestInstance) newTestMap.get(key);
TestInstance oldTest = (TestInstance) oldTestMap.get(key);
if (newTest != null && !newTest.success && (oldTest == null || oldTest.success)) {
writer.write("<TR>");
writer.write("<TD VALIGN=\"top\">" + newTest.suite +
"</TD>");
writer.write(
"<TD VALIGN=\"top\">" + newTest.test + "</TD>");
writer.write("</TR>");
}
}
writer.write("</TABLE>\n" + "<BR/>\n" + "<BR/>\n" + "</TD></TR>");

// output all tests that took more time
writer.write("<TR><TD>\n" +
"<H2>Tests that ran slower:</H2>\n" +
"<table cellpadding=\"4\" cellspacing=\"1\" width=\"100%\">\n" +
"<TH>Suite</TH>\n" + "<TH>Test</TH>\n" +
"<TH>Last Run Duration</TH>\n" +
"<TH>Current Run Duration</TH>\n");
Iterator itr = newTestMap.keySet().iterator();
while (itr.hasNext()) {
String key = (String) itr.next();
TestInstance newTest = (TestInstance) newTestMap.get(key);
TestInstance oldTest = (TestInstance) oldTestMap.get(key);
if (newTest != null && oldTest != null &&
newTest.duration > oldTest.duration*1.1) {
writer.write("<TR>");
writer.write("<TD VALIGN=\"top\">" + newTest.suite +
"</TD>");
writer.write(
"<TD VALIGN=\"top\">" + newTest.test + "</TD>");
writer.write("<TD VALIGN=\"top\" ALIGN=\"center\" >" +
templateHelper.formatNumber(
templateHelper.duration(
oldTest.duration), "##0.0000") +
" secs</TD>");
writer.write("<TD VALIGN=\"top\" ALIGN=\"center\" >" +
templateHelper.formatNumber(
templateHelper.duration(
newTest.duration), "##0.0000") +
" secs</TD>");
writer.write("</TR>");
}
}
writer.write("</TABLE>\n" + "<BR/>\n" + "<BR/>\n" + "</TD></TR>");

// output all tests that were fixed or are new and succeede
writer.write("<TR><TD>\n" +
"<H2>New or Newly Fixed Tests:</H2>\n" +
"<table cellpadding=\"4\" cellspacing=\"1\" width=\"100%\">\n" +
"<TH>Suite</TH>\n" + "<TH>Test</TH>\n");
itr = newTestMap.keySet().iterator();
while (itr.hasNext()) {
String key = (String) itr.next();
TestInstance newTest = (TestInstance) newTestMap.get(key);
TestInstance oldTest = (TestInstance) oldTestMap.get(key);
if (newTest != null && newTest.success && (oldTest == null || !oldTest.success)) {
writer.write("<TR>");
writer.write("<TD VALIGN=\"top\">" + newTest.suite +
"</TD>");
writer.write(
"<TD VALIGN=\"top\">" + newTest.test + "</TD>");
writer.write("</TR>");
}
}
writer.write("</TABLE>\n" + "<BR/>\n" + "<BR/>\n" + "</TD></TR>");

writer.write("</TABLE>\n" + "</BODY>\n" + "</HTML>");

writer.flush();
writer.close();
}
}
catch (Exception e) {
e.printStackTrace(commandOutput);
}

Template for adding users to realms

Script Notes:

  • Treat this mostly as a snippet for doing something more interesting with.

AHPSCRIPTS-1

import com.urbancode.anthill3.domain.project.*;
import com.urbancode.anthill3.domain.authentication.*;
import com.urbancode.anthill3.domain.security.*;
import com.urbancode.anthill3.domain.singleton.security.*;

// Lookup Your roles
buildRole = RoleFactory.getInstance().restoreForName("Build Master");
userRole = RoleFactory.getInstance().restoreForName("User");

// Look-up the LDAP realm here
// This is a lookup by name, so insert the name of your LDAP realm.
realm = AuthenticationRealmFactory.getInstance().restore("LDAP");

// Do this for each user:
User user1 = new User(true, realm);

user1.setName("JaneDoe");
user1.setPassword("Bogus");
user1.addRole(userRole);
user1.addRole(buildRole);
user1.store();

Update Environment Properties for All Projects

Here's a modification that runs form within AnthillPro. The environment is selected to be the current running environment and the other values are read out of properties (the environment could come from a property as well).

AHPSCRIPTS-14

import com.urbancode.anthill3.main.client.AnthillClient;
import com.urbancode.anthill3.persistence.UnitOfWork;
import com.urbancode.anthill3.domain.project.*;
import com.urbancode.anthill3.domain.project.envprops.*;
import com.urbancode.anthill3.domain.servergroup.*;
import java.util.*;


variableName = PropertyLookup.get("variableName");
newVariableValue = PropertyLookup.get("variableValue");
boolean isSecure = Boolean.parseBoolean(PropertyLookup.get("isSecure"));
environment = EnvironmentLookup.getCurrent();


// Project
Project[] projects = ProjectFactory.getInstance().restoreAll();

// Loop through projects. If it has environment props for this, find the
// right one and change it as appropriate.
for (int i = 0; i < projects.length; i++) {
  
ProjectEnvironmentProperty[] envPropArray = environment.getEnvironmentPropertiesForProject(projects[i]);
  boolean foundVariable = false;
  for (int j = 0; j < envPropArray.length; j++) {
     if (envPropArray[j].getName().equals(variableName)) {
        foundVariable = true;
        envPropArray[j].setValue(newVariableValue);
        envPropArray[j].store();
     }
  }
  
if (!foundVariable) {
    ProjectEnvironmentProperty newProp = new ProjectEnvironmentProperty(true);
      
newProp.setProject(projects[i]);
    newProp.setServerGroup(environment);
    newProp.setName(variableName);
    newProp.setValue(newVariableValue);
    newProp.setSetAsEnvProp(false);
    newProp.setSecureValue(isSecure);
      
newProp.store();
  }
  
}

Script to Cleanup Job & Workflow Logs from AHP Server

  • You can have an operations project that runs an evaluate script step with the following contents. This is safe to run any time but should only be needed for 3.5/3.6 instances that did not do the cleanup during the upgrade:

AHPSCRIPTS-92

import com.urbancode.anthill3.services.logging.LogNamingHelper; 
 import com.urbancode.anthill3.spring.SpringSupport; 
 import com.urbancode.commons.fileutils.FileUtils; 
 import org.springframework.jdbc.core.JdbcTemplate; 

 import javax.sql.DataSource; 
 import java.io.File; 
 import java.io.FileFilter; 
 import java.io.PrintStream; 
 import java.util.HashSet; 
 import java.util.List; 
 import java.util.Set; 

 int jobCount = 0; 
 int wcCount = 0; 

 void cleanupDirectory(File dir, String baseDirPath, Set idSet, long highestJobId) { 
     if (dir.isDirectory()) { 
         File[] fileArray = dir.listFiles(new FileFilter() { 
             public boolean accept(File pathname) { 
                 return pathname.isDirectory(); 
             } 
         }); 
         for (File file : fileArray) { 
             cleanupDirectory(file, baseDirPath, idSet, highestJobId); 
         } 

         commandOutput.println("\t\tCleaning up: " + dir.getAbsolutePath()); 
         String[] tokens = dir.getAbsolutePath().substring(baseDirPath.length()).split(File.separator); 
         StringBuffer buffer = new StringBuffer(); 
         for (int i = tokens.length - 1; i > -1; i--) { 
             buffer.append(tokens[i]); 
         } 
         long jobId = Long.parseLong(buffer.toString()); 
         if (!idSet.contains(jobId) && jobId < highestJobId) { 
             File[] fileList = dir.listFiles(new FileFilter(){public boolean accept(File pathname) {return !pathname.isDirectory();}}); 
             if (fileList.length > 0) { 
                 commandOutput.println("Found orphaned dir: " + dir.getAbsolutePath()); 
                 jobCount++; 
                 for (File file : fileList) { 
                     file.delete(); 
                 } 
             } 
         } 
         if (dir.list().length == 0) { 
             dir.delete(); 
         } 
     } 
 } 

 void cleanupWcDirectory(File dir, String baseDirPath, Set idSet, long highestWcId) { 
     if (dir.isDirectory()) { 
         File[] fileArray = dir.listFiles(new FileFilter() { 
             public boolean accept(File pathname) { 
                 return pathname.isDirectory(); 
             } 
         }); 
         commandOutput.println("\t\tCleaning up: " + dir.getAbsolutePath()); 
         for (File file : fileArray) { 
             if (Character.isDigit(file.getName().charAt(0))) { 
                 cleanupWcDirectory(file, baseDirPath, idSet, highestWcId); 
             } 
         } 

         String[] tokens = dir.getAbsolutePath().substring(baseDirPath.length()).split(File.separator); 
         StringBuffer buffer = new StringBuffer(); 
         for (int i = tokens.length - 1; i > -1; i--) { 
             buffer.append(tokens[i]); 
         } 
         long wcId = Long.parseLong(buffer.toString()); 
         if (!idSet.contains(wcId) && wcId < highestWcId) { File[] fileList = dir.listFiles(new FileFilter(){ 
                     public boolean accept(File pathname) { 
                         return !pathname.isDirectory() || pathname.getName().equals("wf"); 
                     } 
                 }); 
             if (fileList.length > 0) { 
                 commandOutput.println("Found orphaned dir: " + dir.getAbsolutePath()); 
                 wcCount++; 
                 for (File file : fileList) { 
                     FileUtils.deleteFile(file); 
                 } 
             } 
         } 
         if (dir.list().length == 0) { 
             dir.delete(); 
         } 
     } 
 } 
 try { 
     DataSource ds = (DataSource)SpringSupport.getInstance().getBean("dataSource"); 
     JdbcTemplate jdbcTemplate = new JdbcTemplate(ds); 

     String logsDirString = LogNamingHelper.getInstance().getLogDirPath() + File.separator + "job"; 
     commandOutput.println("Log files located at: " + logsDirString); 
     long highestJobId = jdbcTemplate.queryForLong("SELECT HI_VAL FROM HI_LO_SEQ WHERE SEQ_NAME = 'JOB_TRACE'"); 
     List idList = jdbcTemplate.queryForList("SELECT ID FROM JOB_TRACE", Long.class); 
     Set idSet = new HashSet(); 
     idSet.addAll(idList); 
     commandOutput.println("Found " + idSet.size() + " known jobs - highest job id " + highestJobId); 
     commandOutput.println("Deleting orphaned job log and output files."); 
     commandOutput.println(" This may take a while, please be patient..."); 

     File baseDir = new File(logsDirString); 
     File[] fileArray = baseDir.listFiles(new FileFilter() { 
                     public boolean accept(File pathname) { 
                         return pathname.isDirectory(); 
                     } 
                 }); 
     for (File file : fileArray) { 
         cleanupDirectory(file, logsDirString, idSet, highestJobId); 
     } 

     String wcDirString = LogNamingHelper.getInstance().getLogDirPath() + File.separator + "wf"; 
     commandOutput.println("Log files located at: " + logsDirString); 
     long highestWcId = jdbcTemplate.queryForLong("SELECT HI_VAL FROM HI_LO_SEQ WHERE SEQ_NAME = 'WORKFLOW_CASE'"); 
     idList = jdbcTemplate.queryForList("SELECT ID FROM WORKFLOW_CASE", Long.class); 
     idSet.clear(); 
     idSet.addAll(idList); 
     commandOutput.println("---------------------------------------------------------"); 
     commandOutput.println("Found " + idSet.size() + " known workflow cases - highest workflow case id " + highestWcId); 
     commandOutput.println("Deleting orphaned workflow case log and output files."); 
     commandOutput.println(" This may take a while, please be patient..."); 

     baseDir = new File(wcDirString); 
     fileArray = baseDir.listFiles(new FileFilter() { 
                     public boolean accept(File pathname) { 
                         return pathname.isDirectory(); 
                     } 
                 }); 
     for (File file : fileArray) { 
         cleanupWcDirectory(file, wcDirString, idSet, highestWcId); 
     } 

     commandOutput.println("Cleanup Complete!"); 
     commandOutput.println("Removed " + jobCount + " job and " + wcCount + " workflow case orphaned directories!"); 
 } 
 catch (Exception e) { 
     e.printStackTrace(commandOutput); 
 }