A simple build chaining example

Imagine the case where your mainframe application is not purely COBOL, but also leverages Java, web services, etc. In this scenario, you will not be able to build with dependency build alone. What can you do to coordinate the build of your entire application? In this post, we’ll look at a simple way to coordinate the builds of a COBOL application and a Java application, such that they run one after the other.

We will build our example into Money that Matters, so you can easily try it out too. Out of the box, Money that Matters has a Java build (jke.dev) and a COBOL dependency build (mortgage.dev). Let’s chain those two together.

First, we will create a third parent build definition to control the two child builds. It’s possible instead to add the request for the Java build directly to the end of the COBOL dependency build, but with the parent-child approach you can easily add more children and also easily run the children on their own. Our third build will be an Ant – Jazz Build Engine build, and we’ll call it crossplatform.dev. You will need to use the Jazz Source Control Pre-Build option if you want to store your build script in the repository. Otherwise, you can maintain it on the system where crossplatform.dev will execute and reference it directly in the build definition. This build definition will simply invoke the Ant script, build.xml:

The build script will simply request the mortgage.dev build, wait for it to complete, and then request and wait for the jke.dev build. This is done using Ant tasks included with the build system toolkit, described here. It will look something like the following:

<?xml version="1.0" encoding="UTF-8"?>
<project default="all" name="Cross platform build">
	<property name="userId" value="builder2" />
	<property name="password" value="rtc9fun" />
	<taskdef name="requestTeamBuild" classname="com.ibm.team.build.ant.task.RequestBuildTask" />
	<taskdef name="startBuildActivity" classname="com.ibm.team.build.ant.task.StartBuildActivityTask" />
	<taskdef name="waitForTeamBuild" classname="com.ibm.team.build.ant.task.WaitForTeamBuildTask" />
	<taskdef name="buildResultRetriever" classname="com.ibm.team.build.ant.task.BuildResultRetrieverTask" />
	<taskdef name="linkPublisher" classname="com.ibm.team.build.ant.task.LinkPublisherTask" />
	<target description="Trigger build and wait" name="trigger_build">
		<startBuildActivity autoComplete="true" buildResultUUID="${buildResultUUID}" label="Requesting ${chainedBuildDefinitionId} build" password="${password}" repositoryAddress="${repositoryAddress}" userId="${userId}" />
		<!--request the child build-->
		<requestTeamBuild buildDefinitionId="${chainedBuildDefinitionId}" requestUUIDProperty="buildRequestUUID" resultUUIDProperty="childBuildResultUUID" failOnError="true" password="${password}" repositoryAddress="${repositoryAddress}" userId="${userId}" />
		<startBuildActivity autoComplete="true" buildResultUUID="${buildResultUUID}" label="Waiting for ${chainedBuildDefinitionId} build" password="${password}" repositoryAddress="${repositoryAddress}" userId="${userId}" />
		<!--wait for the child build-->
		<waitForTeamBuild repositoryAddress="${repositoryAddress}" userId="${userId}" password="${password}" requestUUID="${buildRequestUUID}" statesToWaitFor="COMPLETED,CANCELED,INCOMPLETE" buildStatusProperty="buildStatus" verbose="true" interval="5" />
		<!--retrieve the label for the child build-->
		<buildResultRetriever repositoryAddress="${repositoryAddress}" userId="${userId}" password="${password}" buildResultUUID="${childBuildResultUUID}" labelProperty="childBuildLabel" failonerror="false" />
		<!--publish link to child build result in parent-->
		<linkPublisher label="${chainedBuildDefinitionId}:  ${childBuildLabel}" url="${repositoryAddress}/resource/itemOid/com.ibm.team.build.BuildResult/${childBuildResultUUID}" buildResultUUID="${buildResultUUID}" repositoryAddress="${repositoryAddress}" userId="${userId}" password="${password}" failOnError="false" />
		<echo message="${chainedBuildDefinitionId} build status: ${mortgageBuildStatus}" />
		<fail message="${chainedBuildDefinitionId} failed. Exiting.">
				<equals arg1="${buildStatus}" arg2="ERROR" />
	<target description="Trigger the mortgage.dev build" name="build_mortgage">
		<antcall target="trigger_build">
			<param name="chainedBuildDefinitionId" value="mortgage.dev" />
	<target description="Trigger the jke.dev build" name="build_jke">
		<antcall target="trigger_build">
			<param name="chainedBuildDefinitionId" value="jke.dev" />
	<target depends="build_mortgage,build_jke" description="Cross-platform build" name="all" />

Notice the use of the buildResultRetriever and linkPublisher tasks to include labeled links to your child builds in the parent build result.

The jke.dev build is supported by a Jazz Build Engine called jke.dev.engine, likely running on a distributed platform, while the mortgage.dev build is supported by a Rational Build Agent called jke.rba.engine.dev running on the mainframe. We need to add a second Jazz Build Engine to support the crossplatform.dev build. We can’t reuse jke.dev.engine since we need it available to service the request for jke.dev while crossplatform.dev is still running. Simply create a new Jazz Build Engine and configure it to support crossplatform.dev:

Now, building your COBOL assets and your Java assets in order is simply a matter of requesting your crossplatform.dev build. A more complicated scenario might require the use of an additional tool, such as Rational Build Forge, to orchestrate the build.

This entry was posted in Enterprise Extensions, Rational Team Concert, System z. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s