Getting Started

What is Ant?

Ant is a build tool that is implemented as a scripting language, which is based on the Java platform. Using Java as its platform allows Ant to be run on any system that supports Java in a variety of ways. Ant can be run via the command line, from a shell script or batch job, or from other applications like Eclipse, a Jazz Build Engine (JBE), or a Rational Build Forge Agent (BFA). Ant scripts can be written such that they can be run in multiple environments without alteration or they can be written and customized for a specific target environment. Engineering Workflow Management (EWM) builds use Ant as the basic build tool. The flexibility of Ant allows you to customize how the EWM build is processed and how it is integrated into your software development workflow.

The scripting language implementation allows Ant to be extended to provide services beyond a simple build. In the case of EWM, Ant has been extended to allow for process automation - updating work items, checking work item conditions, triggering process actions based on build results - source control automation - updating files, delivering changes, flowing changes downstream, promoting changes from test to production - deployment automation - packaging build artifacts, deploying packages to other systems - and more.

Ant scripts are written in XML in a pseudo-programming language format. Each Ant script starts with an XML project element. The project element contains a top-level section, which is always executed when the script begins, and 0-n target elements, which can be required or optional, that are executed in a user-defined order. In a well-designed script a target will accomplish a defined unit of work: fetch files for a build; compile source files into an executable; publish the build results.

The basic building blocks used to complete a unit of work in an Ant build script target element are tasks. Each Ant task performs a specific function and is referenced by a unique name: copy to copy a file; delete to delete a file; and so on. There is an extensive list of built-in Ant tasks, and an even more extensive collection of tasks that have been contributed to Ant including those provided by the EWM.

The Engineering Workflow Management Ant tasks offer a variety of services that can be included in a build:

To use the EWM Ant tasks a general understanding of the Ant build environment and Ant build scripts is needed. For a general overview and introduction to Ant refer to the Apache Ant Manual that is appropriate for the version of Ant that you are running. The "Introduction", "Using Apache Ant", and "Running Apache Ant" sections provide an excellent overview. Refer to the "Ant Tasks" and "Concepts and Types" sections for more in-depth reference material.

Ant build environment

Ant runs in a Java JVM. It can be started from the command line via the ant command or directly using Java with one of the following Java command argument sequences:

java -Dant.home=c:\ant org.apache.tools.ant.Main [options] [target]
                              -or-
java -Dant.home=c:\ant org.apache.tools.ant.launch.Launcher [options] [target]
    

For more information on running Ant from either the command line or directly using Java, see Running Apache Ant. This documentation also provides a full list of arguments and options for the Ant application. Also note that the EWM extensions to Ant can be included in a stand-alone environment like this by including the "-lib /path_to_Build_Toolkit" option on the Java command.

Under Eclipse, Ant can be invoked by right-clicking on an Ant script file and choosing the "Run As -> Ant Build" option. Numerous extensions to Ant are available under Eclipse including those provided by the EWM.

A JBE or RBA build invokes Ant via Java. The EWM extensions to Ant are identified by a -lib argument on the Java command that points to the Build Toolkit folder where all the EWM extensions to Ant are housed.

Ant build scripts

In all environments, the primary argument for Ant is a path to the build script (-f), the script to run for the invocation, which defaults to the build.xml file in the current directory. The build script describes a list of steps to perform, called targets, and the order in which they should be performed. The format of an Ant build script is an XML document that is bounded by a project element containing top-level tasks and typically at least one target element.1 A target element consists of a set of Ant tasks that are executed sequentially to perform a unit of work.

For example, the following excerpt defines a target named "compile" which creates an output directory, compiles a set of Java source code, and creates a jar from the compiled output (the details for each of the following Ant tasks have been omitted for clarity):

<target name="compile">
    <mkdir> - create a directory
    <javac> - compile Java code
    <jar>   - create a jar file
</target>
    

1Note: A build script can consist of just the top-level area of the project element. This is a common format for imported definition files for macros, tasks, and types, but an uncommon format for a typical build script.

Example script

The following is an example build script.

Example script

Ant tasks and types

Ant tasks perform the actions to complete a unit of work. Each task is identified by a unique element name, which usually describes the action the task performs. Attributes specified on the task element provide the information necessary for the task to perform the action; a path to a file to copy, the name of the directory to make, the ID of the work item to fetch, and so on. Ant types are used to provide extended information to a task when a single attribute is insufficient; a list of file paths to include in a jar, a list of work item properties to fetch, conditions when an action should be taken, and so on.

In the following example a target named "main" is defined. Within the main target a deleteBuildResults task is defined with attributes that specify the EWM repository URL, the userid and password to use to login to the server, and the ID of the build whose results should be processed. In the example the actual values for the attributes are held in properties - ${propertyName} - that will be resolved before being passed to the deleteBuildResults task. Within the deleteBuildResults task element an includeResult type is defined which limits the results to be deleted to personal builds older than 2 days.

Ant Tasks and Types

Using EWM tasks and types

To start working with the EWM Ant tasks you must first define the tasks and types to Ant. Unlike the built-in tasks described in the Ant documentation, Ant Tasks, the EWM tasks are contributions to the Ant platform and need to be identified to be used. There are numerous ways to define the tasks to Ant, here we will discuss the six most common in order of preference:

  1. Define an antlib namespace in the project element.
  2. Use the loadBuildExtensions task to identify additional participating tasks.
  3. Use the taskdef and typedef resource attribute and the built-in property files.
  4. Run the build script under the EWM Eclipse client where all tasks and types have been identified.
  5. Run the supplied Ant script which includes a taskdef for each task and typedef for each type.
  6. Code individual taskdef and typedef tasks for the tasks/types needed in the top-level section of your script.

The following table describes the support that each toolkit provides for each of the task definition methods. Any column marked with a "•" signifies that that toolkit supports that definition method.

Toolkit Support for Task/Type Definition Methods
Toolkit name Toolkit jar file antlib load
build
extensions
property
files
Eclipse
plugin
Supplied
script
taskdef
typedef
Build Toolkit com.ibm.team.build.toolkit
Build Extensions Toolkit com.ibm.team.build.extensions.toolkit
Enterprise Build Toolkit com.ibm.team.enterprise.build.ant [3] [3] [3] [3] [3]
Enterprise Build Toolkit - IBMi com.ibm.teamp.build.ant 5 [2]
Enterprise Build Toolkit - z/OS com.ibm.team.enterprise.zos.build.ant 6 [1]
Enterprise Build Toolkit - z/OS original com.ibm.teamz.build.ant [1]
Enterprise Build Extensions Toolkit com.ibm.team.enterprise.build.extensions.toolkit
Enterprise SMP/E Toolkit com.ibm.team.enterprise.smpe.toolkit
Enterprise System Definition Toolkit com.ibm.team.enterprise.systemdefinition.toolkit [4] [4] [4] [4] [4]
Enterprise System Definition Toolkit - IBMi com.ibm.team.enterprise.ibmi.systemdefinition.toolkit 5 7
Enterprise System Definition Toolkit - z/OS com.ibm.team.enterprise.zos.systemdefinition.toolkit 6
Enterprise Deployment Toolkit - IBMi com.ibm.teamp.ibmi.deployment.toolkit [2]
Enterprise Deployment Toolkit - z/OS com.ibm.team.enterprise.deployment.toolkit [1]
Enterprise Packaging Toolkit - IBMi com.ibm.teamp.ibmi.packaging.toolkit [2]
Enterprise Packaging Toolkit - z/OS com.ibm.team.enterprise.packaging.toolkit [1]
Enterprise Promotion Toolkit - IBMi com.ibm.teamp.ibmi.promotion.toolkit [2]
[1] z/OS environment only
[2] IBMi environment only
[3] Code shared between z/OS and IBMi environments and included in system-specific Enterprise Build Toolkits
[4] Code shared between z/OS and IBMi environments and included in system-specific Enterprise System Definition Toolkits
[5] These tasks are accessible using the Load Build Extensions methodology when the iItems="true" is specified when loadBuildExtensions is invoked
[6] These tasks are accessible using the Load Build Extensions methodology when the zItems="true" is specified when loadBuildExtensions is invoked
[7] Due to naming conflicts between z/OS and IBMi tasks and Eclipse limitations, some IBMi tasks names have been prefixed with "ibmi."

The following toolkits include common tasks and types from the Enterprise Build Toolkit (com.ibm.team.enterprise.build.ant):

The following toolkits include common tasks and types from the Enterprise System Definition Toolkit (com.ibm.team.enterprise.systemdefinition.toolkit):

Due to naming conflicts between z/OS and IBMi tasks, the following IBMi tasks have been prefaced with "ibmi.".

For example, the export task for IBMi system definitions is ibmi.export. This only affects access to these tasks using the Eclipse plugin methodology. All other methods use the standard names for these tasks.

Antlib namespace

The antlib namespace is the easiest, and thus most preferred, method for defining contributed tasks to Ant. It is a built-in feature of XML parsers and fully supported by Ant. This method uses an attribute of the project element, xmlns, to signal Ant and its XML parsing routines to define all of the tasks and types defined in the antlib.xml file in the top-level directory of the specified jar. For example, the following project element defines two antlib namespaces, one for the AntContrib tasks and one for the Build Extensions tasks:

<project
    basedir="."
    default="all"
    name="FindWorkItemIdForWorkItemType"
    xmlns:ac="antlib:net.sf.antcontrib"
    xmlns:xt="antlib:com.ibm.team.build.extensions.toolkit">
    

In the example, the first xmlns defines the "ac" namespace - xmlns:ac - to the tasks and types defined in the antlib.xml file in the primary, or top-level, package of the AntContrib jar you are using: net.sf.antcontrib. At this point all of the AntContrib tasks are accessible to the script by prefacing the task element name with "ac:" as in the following AntContrib switch clause example (notice that both tasks, switch, and types, case and default, are prefaced with the "ac:" namespace:

<ac:switch value="${tmp.authenticationPolicy}">
    <ac:case value="CERTIFICATEFILE">
        <startBuildActivity
                repositoryAddress="@{repositoryAddress}"
                userId="@{userId}"
                certificateFile="@{certificateFile}"
                autoComplete="true"
                buildResultUUID="@{buildResultUUID}"
                label="@{label}"/>
    </ac:case>
    <ac:case value="INTEGRATEDWINDOWS">
        <startBuildActivity
                repositoryAddress="@{repositoryAddress}"
                integratedWindows="@{integratedWindows}"
                autoComplete="true"
                buildResultUUID="@{buildResultUUID}"
                label="@{label}"/>
    </ac:case>
    <ac:default>
        <startBuildActivity
                repositoryAddress="@{repositoryAddress}"
                userId="@{userId}"
                password="@{password}"
                autoComplete="true"
                buildResultUUID="@{buildResultUUID}"
                label="@{label}"/>
    </ac:default>
</ac:switch>
    

The second xmlns defines the "xt" namespace to the tasks and types defined in the antlib.xml file in the primary, or top-level, package in the Build Extensions jar you are using: com.ibm.team.build.extensions.toolkit. Notice that the version information in the jar file name is not a factor when using this method; any version of the jar file will satisfy this namespace definition. At this point, all of the Build Extensions tasks are accessible to the script by prefacing the task element name with "xt:" as in the following example:

<xt:deleteBuildResults
    repositoryAddress="${repositoryAddress}"
    userId="${userId}"
    password="${password}"
    buildId="${buildDefinition}">
    
    <xt:includeResult>
        <xt:buildProperty name="buildDefinitionId" value="${buildDefinition}"/>
    </xt:includeResult>
    
</xt:deleteBuildResults>
    

The namespace value can be anything that you choose, but it is always best to choose something short, descriptive, and memorable. One more word to the wise, once you have decided on a namespace value, be consistent and use the same value in all of your Ant scripts. For more information on Ant namespace support, refer to XML Namespace Support.

Load build extensions task

The loadBuildExtensions task is used to register participating EWM and Enterprise Extensions Ant tasks and types under the Build Extensions toolkit namespace. This function allows all participating tasks and types to be referenced by a common namespace. The idea behind this task is to make referencing the various Ant tasks spread across the numerous jars described above easier by using a single namespace, that of the Build Extensions tasks, instead of a namespace for each individual jar. See the loadBuildExtensions documentation for more information on the task.

There are two requirements to use this method for defining contributed tasks to Ant. First, you must include a namespace definition for the Build Extensions toolkit. Second, you must include the loadBuildExtensions task in the script. The most common location for the task is in the top-level section of the script as in the following example:

Load Build Extensions

Immediately following the loadBuildExtensions task all tasks and types from all participating jars are accessible using the namespace defined for the Build Extensions toolkit, "xt" in the example.

Property files

Another way to define contributed tasks to Ant is with a property file included in the jar. The AntContrib toolkit and the EWM toolkits identified in the Toolkit Support for Task/Type Definition Methods support this method. To use this method you include a taskdef task in the top-level section of the build script that identifies the path to the properties file in the appropriate jar and a path to the jar. Any of the following examples can be used as a template for the taskdef task:

Note that the EWM toolkits have two properties files, "antTasks.properties" for tasks and "antTypes.properties" for types, and that each needs to be identified to define all the pieces in that toolkit. Also note that the jar file name for EWM toolkits will include version information, and therefore, the jar file names will change with new releases. It is recommended to use the more generic method for an unknown jar file name so that code need not be updated when a new version of EWM is installed.

Immediately following the taskdef task all tasks and types from the jars are accessible using just the name of the task. The following example assumes that the AntContrib tasks have been defined as above. Note that the AntContrib propertyregex task is not prefaced by a namespace, but instead identified by just its name:

<macrodef name="GetExportCreateBuild">
    <attribute name="property"/>
    <attribute name="testcase"/>
    <sequential>
        <local name="lcl.buildType"/>
        <propertyregex
            property="lcl.buildType"
            input="@{testcase}"
            regexp="^ExportBuildDefinition(.*)"
            select="\1" override="true"/>
        <property name="@{property}"
            value="CreateBuildDefinition${lcl.buildType}.xml"/>
        <echo>createBuild: ${@{property}}</echo>
    </sequential>
</macrodef>
    

Eclipse plugin

The fourth way to define contributed tasks to Ant is supplied by EWM when definitions for the tasks and types are included in the toolkit’s plugin definition. The Toolkit Support for Task/Type Definition Methods table identifies which toolkits support this method. To run one of the EWM Ant tasks identified in this manner, run the build script under Eclipse and specify just the name of the task in the script. The tasks are automatically available in the Ant environment created by Eclipse to run the script. The following explains how to run an Ant script under Eclipse:

Run as Ant Build



Same JRE as Workspace



Supplied script

Some of the EWM toolkits described above supply a pre-written Ant script that uses the taskdef and typedef tasks described below to define contributed tasks to Ant. The Toolkit Support for Task/Type Definition Methods table identifies which toolkits support this method. To use this method in your script you simply import the script in the top-level section of your script. It has no targets, just a top-level section of its own that contains only taskdef and typedef statements. The following is an example of the code you will need:

<project>
    <import file="/path_to_file/BuildToolkitTaskDefs.xml"/>
    ...
</project>
    

The preferred method for importing the supplied scripts is shown in the following example. With this method the need to maintain the path to the supplied script is avoided thereby reducing maintenance activity when EWM is upgraded:

<import>
    <javaresource name="scripts/imports/BuildExtensionsToolkitTaskDefs.xml"/>
</import>
    
Supplied script locations

The following table can be used as a reference for the name and location of the supplied scripts for the EWM toolkits:

Supplied script locations
Toolkit name Script location Script name
Build Toolkit BuildToolkitTaskDefs.xml[1] BuildToolkitTaskDefs.xml
Build Extensions Toolkit scripts/imports/BuildExtensionsToolkitTaskDefs.xml[1] BuildExtensionsToolkitTaskDefs.xml
Enterprise Build Toolkit - -
Enterprise Build Toolkit - IBMi scripts/imports/iEnterpriseBuildToolkitTaskDefs.xml iEnterpriseBuildToolkitTaskDefs.xml
Enterprise Build Toolkit - z/OS scripts/imports/zEnterpriseBuildToolkitTaskDefs.xml zEnterpriseBuildToolkitTaskDefs.xml
Enterprise Build Toolkit - z/OS original scripts/imports/AntzToolkitTaskDefs.xml AntzToolkitTaskDefs.xml
Enterprise Build Extensions Toolkit scripts/imports/EnterpriseBuildExtensionsToolkitTaskDefs.xml[1] EnterpriseBuildExtensionsToolkitTaskDefs.xml
Enterprise SMP/E Toolkit scripts/imports/EnterpriseSmpeToolkitTaskDefs.xml[1] EnterpriseSmpeToolkitTaskDefs.xml
Enterprise System Definition Toolkit - -
Enterprise System Definition Toolkit - IBMi scripts/imports/iEnterpriseSystemDefinitionToolkitTaskDefs.xml[1] iEnterpriseSystemDefinitionToolkitTaskDefs.xml
Enterprise System Definition Toolkit - z/OS scripts/imports/zEnterpriseSystemDefinitionToolkitTaskDefs.xml[1] zEnterpriseSystemDefinitionToolkitTaskDefs.xml
Enterprise Deployment Toolkit - IBMi
Enterprise Deployment Toolkit - z/OS
Enterprise Packaging Toolkit - IBMi
Enterprise Packaging Toolkit - z/OS
Enterprise promotion toolkit - IBMi
[1] This file will also be found in on the build engine system in the path "/install_directory_path/buildsystem/buildtoolkit" in the location described above.

Taskdef and Typedef

The most basic means of defining contributed tasks to Ant is to include a taskdef task for each task that will be used by a script and a typedef task for all of the types that are used by the identified task. Using this method produces the most efficient code; no processing time is wasted defining tasks and types that will not be used by the script. The tradeoff for this efficiency is that it may take more effort to maintain the script as time passes and newer versions of underlying software are installed. All toolkits support this method.

To define a task using the taskdef task include a taskdef statement specifying the name and classname for the required Ant task. A taskdef statement is typically located in the top-level section of the Ant script, but may appear elsewhere if needed. For example:

<taskdef name="artifactFilePublisher" classname="com.ibm.team.build.ant.task.ArtifactFilePublisherTask"/>
    

Task names can be found in EWM documentation. You may actually use any name you choose, but it may make code maintenance difficult if different names are used for the same task in a large library of code. Classnames can be found within the target jar file by converting the path to the executable class to the classname format. For example:

/com/ibm/team/build/extensions/toolkit/ant/builddefinition/task/CreateBuildDefinitionTask.class

becomes

com.ibm.team.build.extensions.toolkit.ant.builddefinition.task.CreateBuildDefinitionTask
    

For more information and a completed description refer to the Taskdef and Typedef Ant documentation.

Examples

Pre-Build script to check approvals

The goal of this Ant script is to ensure that all "Code review" approvals have been completed before a build is processed. This means that the build workspace contains change sets to be built, that the change sets have been associated with, or linked to, one or more work items, that the work items have a "Code review" approval defined, and that the "Code review" must be approved before the build can proceed.

Workspace

The build workspace, "Test Workspace", contains change sets to be built and the change sets have been associated with work items, "7,8":

Pre-Build Exit to Check Approvals - Workspace

Work items

The work items have a "Code review" approval defined which must be approved before the build can proceed:

Pre-Build Exit to Check Approvals - Workitem 7

Pre-Build Exit to Check Approvals - Workitem 8

CheckApprovals script

The CheckApprovals Ant script satisfies the requirements described above assuming that the workspace and work items have been set up as described. A simplified version of the script is included below to illustrate the details of how the script accomplishes its task. The following discussion describes the meaning of critical aspects of the code using line number references:

Line: Description:
14 Defines the "ac" namespace for the AntContrib tasks.
15 Defines the "xt" namespace for the Build Extensions tasks.
18 Loads a properties file which contains login information: repository address, userid, and password. Note that the tasks and macros described below support all of the Team Build login methods. The userid/password method is used for simplicity’s sake.
20-22 This import task loads the supplied WorkItemMacros Ant script from the Build Extensions jar. The WorkItemMacros Ant script contains Ant macros and JavaScript definitions that facilitate working with EWM work items in an Ant script. In this example we will use the CheckForApprovals macro, and it in turn will use the CheckForApprovalsScript script, both of which are provided by the WorkItemMacros Ant script. See CheckForApprovals Macro for more information on the CheckApprovals macro.
24 Begins the main target which does all of the work in this example. The main target ends on line 58.
26-32 The getChangeSetWorkItems task is called to find the work items linked to the change sets in the specified workspace. The task first identifies all of the outgoing change sets for all of the components defined to the specified workspace. It then finds all of the work items linked to each of those change sets, and finally, retrieves the ids for all the work items found which are returned as a comma-separated list in the specified property. At the end of the task the property, workItems, will contain a comma-separated list of work item IDs linked to the change sets for the build.
35 Here we begin a for loop where each work item in the workItems property will be processed individually. The for task is part of AntContrib. The individual work item IDs are identified by splitting the workItems string into an array using a comma as the delimiter. Each work item ID that is processed within the loop is identified by @{workItem} based on the param attribute on the for task.
36 The sequential task is required by the for task.
37 The "approved" property is defined as local, by the local task, so that it can be reused for each iteration.
39-46 The CheckForApprovals macro retrieves approvals information for the specified work item and searches for a "Code review" approval. If the approval is found, and if it has a cumulative state of "Approved", the "approved" property will be set to true.
48-54 The fail task checks the value of the "approved" property, and if it is not true, the build is failed with message: Build failed: Code review approvals are not complete.
Pre-Build Exit to Check Approvals - CheckApprovals Script
CheckApprovals build Log

The following is a typical build log for the CheckApprovals Ant script with debugging information enabled. It shows the work items found when examining the workspace - 7,8 - the raw JSON output - one JSON array entry for each approval and five JSON object name-value pairs for the information associated with the approval - that the "cumstate" of the approval is "Approved" and that the "approvals" property was set to true:

Pre-Build Exit to Check Approvals - CheckApprovals Build Log
CheckApprovals implementation

The CheckApprovals Ant script is supplied with EWM. A copy of it is located in the install_location/buildsystem/buildtoolkit/examples/build folder. You can use this example as is or modify it to suit your needs. If you modify the example it is highly recommended that you copy it to another location so that your modifications are not overlaid when applying maintenance. To implement the script, update your Enterprise Extensions Dependency Build definition and specify the path to the script in the "Pre-build script" field on the Dependency Build tab. To implement the script for a simple Jazz Build Engine Ant build, insert a call to the script at the beginning of your existing build script.

CheckApprovals.xml Source

The following is the source for the CheckApprovals.xml Ant script which can be downloaded here:

<?xml version="1.0" encoding="UTF-8"?>
<!--
    Licensed Materials - Property of IBM
    (c) Copyright IBM Corporation 2021. All Rights Reserved.
    
    Note to U.S. Government Users Restricted Rights:
    Use, duplication or disclosure restricted by GSA ADP Schedule
    Contract with IBM Corp.
-->
<project
    basedir="."
    default="all"
    name="CheckApprovals"
    xmlns:ac="antlib:net.sf.antcontrib"
    xmlns:xt="antlib:com.ibm.team.build.extensions.toolkit">
    <description>CheckApprovals</description>
    
    <loadproperties srcFile="login.properties"/>
    
    <import>
        <javaresource name="scripts/extensions/imports/WorkItemMacros.xml"/>
    </import>
    
    <!-- - - - - - - - - - - - - - - - - - - *
    *  CheckApprovals init                   *
    *- - - - - - - - - - - - - - - - - - - -->
    <target name="init" description="init"/>
    
    <!-- - - - - - - - - - - - - - - - - - - *
    *  CheckApprovals main                   *
    *- - - - - - - - - - - - - - - - - - - -->
    <target name="main" description="main">
        
        <xt:getchangesetworkitems
            repositoryAddress="${repositoryAddress}"
            userId="${userId}"
            password="${password}"
            workspaceUUID="${workspaceUUID}"
            property="workItems"
        />
        <echo>${workItems}</echo>
        
        <ac:for list="${workItems}" param="workItem" delimiter="," trim="true">
            <sequential>
                <local name="approved"/>
                
                <CheckForApprovals
                    repositoryAddress="${repositoryAddress}"
                    userId="${userId}"
                    password="${password}"
                    approval="Code review"
                    property="approved"
                    workItemId="@{workItem}"
                />
                <echo>${approved}</echo>
                
                <fail message="Build failed: Code review approvals are not complete">
                    <condition>
                        <not>
                            <istrue value="${approved}"/>
                        </not>
                    </condition>
                </fail>
            </sequential>
        </ac:for>
        
    </target>
    
    <!-- - - - - - - - - - - - - - - - - - - *
    *  CheckApprovals term                   *
    *- - - - - - - - - - - - - - - - - - - -->
    <target name="term" description="term"/>
    
    <target depends="init,main,term" description="all" name="all"/>
</project>
    

CheckForApprovals Ant Macro

The CheckForApprovals macro is supplied with EWM. You do not need to install, duplicate, or update this macro. It is made available by the import task described previously. It is presented here for information purposes only. If you wish to copy and modify this macro for your own purposes in your own locally maintained source, feel free to do so.

The CheckForApprovals macro retrieves approvals information for the specified work item in JSON format. It calls the CheckForApprovalsScript script which searches for the specified approval. The following discussion describes the meaning of critical aspects of the code using line number references:

Line: Description:
46-58 These attributes support the Team Build login options.
59-62 These attributes support the CheckForApprovals macro. The approval attribute specifies the text of the approval to search for; "Code review" in this example. The property attribute specifies the name of the property to create with the result. The workItemId attribute specifies the ID of the work item to retrieve.
66-68 The addReference task is used to identify the task that the TeamTask macro is to invoke, in our case the getWorkItem task. The TeamTask macro is a wrapper for calling tasks that support all Team Build login options; it handles all login option processing as well as all task-specific needs. The TeamTask macro greatly reduces the volume of code needed to support all of the login options. The reference ID supplied by addReference allows the TeamTask macro to support Ant tasks that are referenced by namespaces.
70-89 The TeamTask macro is used to call the getWorkItem task, which is provided a work item ID to fetch (line 85) and the data to retrieve (line 87) - approvals in JSON format. The information retrieved will be stored in the "lcl.approvals" local property. The TeamTask macro is part of the Enterprise Extensions SMP/E Common Macros and is included in WorkItemMacros.xml using the following Ant snippet:
<import>
    <javaresource name="scripts/smpe/imports/$common.xml"/>
</import>
            
91 The CheckForApprovalsScript script is used to parse the JSON output from the getWorkItem task to search for the approval. See CheckForApprovalsScript script for more information on the CheckForApprovalsScript script.
Pre-Build Exit to Check Approvals - CheckForApprovals Macro

CheckForApprovals macro

The following is the source for the CheckForApprovals macro which can be downloaded here:

<!-- CheckForApprovals -->
<macrodef name="CheckForApprovals">
    <!-- TeamTask common -->
    <attribute name="repositoryAddress" default="${repositoryAddress}"/>
    <attribute name="userId" default="${userId}"/>
    <attribute name="password" default="${password}"/>
    <attribute name="certificateFile" default=""/>
    <attribute name="integratedWindows" default=""/>
    <attribute name="kerberos" default=""/>
    <attribute name="passwordFile" default="${valueFor:passwordFile}"/>
    <attribute name="repositoriesFile" default=""/>
    <attribute name="smartCard" default=""/>
    <attribute name="failOnError" default="true"/>
    <attribute name="reuseLoginOption" default="true"/>
    <attribute name="verbose" default="false"/>
    <!-- Macro specifics -->
    <attribute name="approval"/>
    <attribute name="property"/>
    <attribute name="workItemId"/>
    <sequential>
        <local name="lcl.approvals"/>
        
        <xt:addReference>
            <xt:getWorkItem id="getWorkItemTaskReference"/>
        </xt:addReference>
        
        <TeamTask
                refid="getWorkItemTaskReference"
                repositoryAddress="@{repositoryAddress}"
                userId="@{userId}"
                password="@{password}"
                certificateFile="@{certificateFile}"
                integratedWindows="@{integratedWindows}"
                kerberos="@{kerberos}"
                passwordFile="@{passwordFile}"
                repositoriesFile="@{repositoriesFile}"
                smartCard="@{smartCard}"
                failOnError="@{failOnError}"
                reuseLoginOption="@{reuseLoginOption}"
                verbose="@{verbose}"
            >
            <taskAttribute name="workItemId" value="@{workItemId}"/>
            <taskElement>
                <xt:fetch name="approvals" property="lcl.approvals" ApprovalsJson="true"/>
            </taskElement>
        </TeamTask>
        
        <CheckForApprovalsScript approval="@{approval}" input="${lcl.approvals}" property="@{property}"/>
    </sequential>
</macrodef>
    

CheckForApprovalsScript script

The CheckForApprovalsScript script is supplied with the EWM. You do not need to install, duplicate, or update this script. It is made available by the import tasks described previously. It is presented here for information purposes only. If you wish to copy and modify this script for your own purposes in your own locally maintained source, feel free to do so.

The CheckForApprovalsScript script is written in JavaScript which has better facilities for parsing the getWorkItem JSON output. This script searches the JSON output for the specified approval. If the approval is found, and if it has a cumulative state of "Approved", the "approved" property will be set to true. The following discussion describes the meaning of critical aspects of the code using line number references:

Line: Description:
97-99 These attributes are passed from the CheckForApprovals macro. The approval attribute specifies the text of the approval to search for; "Code review" in this example. The input attribute passes the JSON output for the work item. The property attribute specifies the name of the property to create with the result.
125-149 The traverse() function parses the JSON output which is a JSON array of JSON objects; one array entry for each approval and one object in each array entry for each approval name-value pair.
143-145 When the target array entry is processed and the target approval name-value pair is encountered, if the "cumstate" is set to "Approved" the result is set to true.
162 The specified property is set to the result of the search.
Pre-Build Exit to Check Approvals - CheckForApprovalsScript JavaScript

CheckForApprovalsScript source

The following is the source for the CheckForApprovalsScript script which can be downloaded here:

<!-- CheckForApprovalsScript -->
<scriptdef name="CheckForApprovalsScript" language="javascript">
    <attribute name="approval"/>
    <attribute name="input"/>
    <attribute name="property"/>
    
    <![CDATA[
    // Get input attributes
    var approval  = attributes.get("approval");
    var input     = attributes.get("input");
    var property  = attributes.get("property");
    
    // Get debug attributes
    var debugOn   = project.getProperty("debugOn");
    var debug     = project.getProperty("debug");
    
    // Set global variables
    var approved = "false";
    
    // Echo task for debugging
    echo = project.createTask("echo");
    function debugMsg(msg) {
        if (debugOn == "true" && debug == "true") {
            echo.setMessage(msg);
            echo.perform();
        }
    }
    
    // Function to traverse JSON
    var json = eval("(" + input + ")");
    function traverse(obj,lastkey) {
        var type = typeof obj;
        if (type == "object") {
            for (var key in obj) {
                var type = typeof obj[key];
                
                if (lastkey === undefined || lastkey == "" || lastkey == key) {
                    newkey = key;
                } else {
                    newkey = lastkey + ’.’ + key;
                }
                if (type == "object") {
                    traverse(obj[key],newkey);
                } else {
                    // Complete value
                    debugMsg("key=" + newkey + " " + "value=" + obj[key]);
                    
                    // Check approvals
                    if (newkey.indexOf(approval) != -1 && newkey.indexOf("cumstate") != -1 && obj[key] == "Approved") {
                        approved = "true";
                    }
                }
            }
        }
    }
    
    // Debug messages
    debugMsg("approval=" + approval);
    debugMsg("input=" + input);
    
    // Main Processing
    traverse(json);
    
    // Debug messages
    debugMsg("property=" + property);
    debugMsg("approved=" + approved);
    
    project.setProperty(property,approved);
    ]]>
</scriptdef>