Writing a custom step task with GitUtilities
In this tutorial, you will create and add a custom step task to the Cobol language task. This step has the following purposes:
- Get additional metadata for the current build file from Git by using the
GitUtilities
class. - Add that metadata to new user-generated context variables.
- Use those variables to pass that metadata to an
IDENTIFY
statement in theLinkEdit
step.
Prerequisites
- Ensure DBB is installed and configured by following the Host Configuration Guide.
- Follow the steps in the zBuilder Getting Started section.
- If you are working from a z/OS UNIX System Services command-line session, ensure your environment is configured for use with Git command line tools. Executing
$DBB_CONF/gitenv.sh
will configure your environment for Git provided through IBM Open Enterprise Foundation for z/OS® by default. - Ensure you have a working zBuilder configuration directory setup. If you do not, follow the steps in the Building the Mortgage Application sample tutorial to set one up.
- Familiarize yourself with the tutorial Creating a custom task.
Estimated time
This tutorial takes about 25 minutes to complete.
Steps
1. Write the Groovy task
This Groovy task will use the GitUtilities
DBB class to get additional metadata about the current build file. It will get the git hash in which the file was last changed and the current git branch. This information will then be
added to new context variables GIT_HASH
and GIT_BRANCH
.
-
Create an
IBM-1047
encoded file calledgitUtilsTask.groovy
in your$DBB_BUILD/groovy
folder. -
Use a
BaseScript
AST transformation to set the base script class toTaskScript
:@groovy.transform.BaseScript com.ibm.dbb.groovy.TaskScript baseScript
This causes the Groovy script to extend
TaskScript
, injecting an SLF4j logger under thelog
variable as well as theBuildContext
objectcontext
andTaskVariables
objectconfig
. -
Import additional classes. This script uses
TaskConstants
to access the names of DBB providedBuildContext
variables, andGitUtilities
to interact with the Git repository:import com.ibm.dbb.task.TaskConstants import com.ibm.dbb.utils.GitUtilities
-
Use the
TaskVariables
objectconfig
to get the path of the current build file that is being processed:File file = new File(config.getStringVariable(TaskConstants.FILE_PATH))
-
Get the full hash of the commit in which the file was most recently updated. To do this, use the
getFileCurrentGitHash(File file, boolean abbrev)
method ofGitUtilities
, passing the build file from the previous step andtrue
to get the abbreviated Git hash:String hash = GitUtilities.getFileCurrentGitHash(file, true)
Create and set the
GIT_HASH
variable ofTaskVariables
, so that its value is accessible in theLanguageTask
configuration:config.setVariable("GIT_HASH", hash)
Add logging to debug the script in the event of an error:
log.debug("HASH: {}", config.getStringVariable("GIT_HASH"))
-
Repeat these steps for the current branch:
String branch = GitUtilities.getCurrentGitBranch(file.getAbsolutePath()) config.setVariable("GIT_BRANCH", branch) log.debug("BRANCH: {}", config.getStringVariable("GIT_BRANCH"))
-
Add a return statement and put it all together:
@groovy.transform.BaseScript com.ibm.dbb.groovy.TaskScript baseScript import com.ibm.dbb.task.TaskConstants import com.ibm.dbb.utils.GitUtilities // Get absolute file path of the current build file File file = new File(config.getStringVariable(TaskConstants.FILE_PATH)) // Get the full hash of the commit in which the file was most recently updated String hash = GitUtilities.getFileCurrentGitHash(file, true) config.setVariable("GIT_HASH", hash) log.debug("HASH: {}", config.getStringVariable("GIT_HASH")) // Get the name of the current git branch String branch = GitUtilities.getCurrentGitBranch(file.getAbsolutePath()) config.setVariable("GIT_BRANCH", branch) log.debug("BRANCH: {}", config.getStringVariable("GIT_BRANCH")) return 0
2. Implement the step in the Cobol.yaml
language task
After writing the Groovy script, it is time to implement it in Cobol.yaml
. For each build file, the script will be called, populating the TaskVariables
object config
with variables to store git metadata.
These variables will then be used within the linkEdit
step to populate the SYSREF
dd with instream metadata.
-
In
Cobol.yaml
, define a step to execute the groovy task:- step: GitUtils type: task name: gitUtilsTask
This step must execute before the
linkEdit
step in which the metadata will be used. Ensure your Groovy script is located in$DBB_BUILD/groovy
. -
Define the
SYSREF
dd within thelinkEdit
step:dds: - { name: "SYSREF", instream: "${instream}", options: "tracks space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" }
The
instream
variable that holds the Git metadata will be defined in the next step. -
Define the
instream
variable within thevariables
section ofCobol.yaml
. The|1
notation is a block scalar in YAML syntax. It defines that line breaks are kept and that the string is to be indented by one space.- name: instream value: |1 INCLUDE SYSLIB(${MEMBER}) IDENTIFY ${MEMBER}('BR:${GIT_BRANCH} SHA:${GIT_HASH}') NAME ${MEMBER}(R)
-
Putting it all together, the
Cobol.groovy
task should now look like this:--- # # Licensed materials - Property of IBM # 5655-AC5 Copyright IBM Corp. 2024, 2025. # All rights reserved # US Government users restricted rights - Use, duplication or # disclosure restricted by GSA ADP schedule contract with IBM Corp. # #################################### # Cobol language configuration #################################### version: 1.0.0 tasks: # Cobol Language task - language: Cobol # source file association patterns sources: - "**/cobol/*.cbl" # overridable variables variables: # conditional variable builds compile parameters i.e CICS,SQL - name: compileParms append: - condition: ${IS_CICS} value: CICS - condition: ${IS_SQL} value: SQL - condition: exists: errPrefix value: ADATA,EX(ADX(ELAXMGUX)) - condition: exists: debug eval: ${debug} value: TEST # flag to perform linkedit - name: doLinkEdit value: true # default link edit parameters - name: linkEditParms value: MAP,RENT,COMPAT(PM5) # default dependency search path for single repository build - name: dependencySearchPath value: search:${WORKSPACE}/?path=${APP_DIR_NAME}/copybook/*.cpy # flag incating to scan the load module for static link dependencies - name: scanLoadModule value: true # Uncomment to resolve logical files using resolveSubsystems # - name: subsystemSearchPath # value: ${dependencySearchPath} - name: instream value: |1 INCLUDE SYSLIB(${MEMBER}) IDENTIFY ${MEMBER}('BR:${GIT_BRANCH} SHA:${GIT_HASH}') NAME ${MEMBER}(R) # datasets that need to be created / validated for this language configuration datasets: - name: ${HLQ}.COBOL options: cyl space(1,1) lrecl(80) dsorg(PO) recfm(F,B) dsntype(library) - name: ${HLQ}.COPY options: cyl space(1,1) lrecl(80) dsorg(PO) recfm(F,B) dsntype(library) - name: ${HLQ}.BMS.COPY options: cyl space(1,1) lrecl(80) dsorg(PO) recfm(F,B) dsntype(library) - name: ${HLQ}.DBRM options: cyl space(1,1) lrecl(80) dsorg(PO) recfm(F,B) dsntype(library) - name: ${HLQ}.OBJ options: cyl space(1,1) lrecl(80) dsorg(PO) recfm(F,B) dsntype(library) - name: ${HLQ}.LOAD options: cyl space(1,1) dsorg(PO) recfm(U) blksize(32760) dsntype(library) # list of steps to execute for each program processed by this language configuration steps: # Copy build file and dependency files to data sets - step: copySrc type: copy source: ${WORKSPACE}/${FILE} target: //'${HLQ}.COBOL(${MEMBER})' dependencyCopy: - search: ${dependencySearchPath} mappings: - source: "**/*" dataset: ${HLQ}.COPY # COBOL compile step - step: compile type: mvs pgm: IGYCRCTL parm: ${compileParms} maxRC: 8 dds: - { name: "SYSIN", dsn: "${HLQ}.COBOL(${MEMBER})", options: "shr", input: true } - { name: "SYSLIN", dsn: "${HLQ}.OBJ(${MEMBER})", options: "shr", output: true } - { name: "TASKLIB", dsn: "${SIGYCOMP}", options: "shr" } - { dsn: "${SDFHLOAD}", condition: "${IS_CICS}", options: "shr" } - { dsn: "${SDSNLOAD}", condition: "${IS_SQL}", options: "shr" } - { dsn: "${SFELLOAD}", condition: { exists: "SFELLOAD" }, options: "shr" } - { name: "SYSPRINT", log: "${LOGS}/${MEMBER}-${STEP}.cbl.log", options: "cyl space(5,5) unit(vio) blksize(133) lrecl(133) recfm(f,b) new" } - { name: "SYSMDECK", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT1", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT2", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT3", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT4", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT5", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT6", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT7", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT8", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new"} - { name: "SYSUT9", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT10", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT11", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT12", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT13", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT14", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT15", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT16", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSUT17", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSLIB", dsn: "${HLQ}.COPY", options: "shr" } - { dsn: "${HLQ}.BMS.COPY", options: "shr" } - { dsn: "${SDFHCOB}", condition: "${IS_CICS}", options: "shr" } - { dsn: "${SCSQCOBC}", condition: "${IS_MQ}", options: "shr" } - { name: "DBRMLIB", dsn: "${HLQ}.DBRM(${MEMBER})", condition: "${IS_SQL}", options: "shr", output: true, deployType: "DBRM" } - { name: "SYSADATA", condition: { exists: "errPrefix" }, options: "DUMMY" } - { name: "SYSXMLSD", condition: { exists: "errPrefix" }, dsn: "${HLQ}.${errPrefix}.SYSXMLSD.XML", options: "tracks space(200,40) dsorg(PS) blksize(27998) lrecl(16383) recfm(v,b) new keep" } # GitUtils Step - step: GitUtils type: task name: gitUtilsTask # Link-Edit step - step: linkEdit type: mvs pgm: IEWBLINK parm: ${linkEditParms} condition: ${doLinkEdit} maxRC: 0 dds: - { name: "SYSREF", instream: "${instream}", options: "tracks space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "SYSLIN", dsn: "${HLQ}.OBJ(${MEMBER})", options: "shr" } - { ref: "SYSREF" } - { name: "SYSLMOD", dsn: "${HLQ}.LOAD(${MEMBER})", options: "shr", output: true, deployType: "LOAD", scan: "${scanLoadModule}" } - { name: "SYSPRINT", log: "${LOGS}/${MEMBER}-${STEP}.cbl.log", options: "cyl space(5,5) unit(vio) blksize(133) lrecl(133) recfm(f,b) new" } - { name: "SYSUT1", options: "cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new" } - { name: "RESLIB", condition: { exists: RESLIB }, options: "shr" } - { name: "SYSLIB", dsn: "${HLQ}.OBJ", options: "shr" } - { dsn: "${SCEELKED}", options: "shr" } - { dsn: "${SDFHLOAD}", condition: "${IS_CICS}", options: "shr" } - { dsn: "${SDSNLOAD}", condition: "${IS_SQL}", options: "shr" }
Next steps
To build an application by using this custom task, ensure the project application is initialized to a valid Git repository. See Building the MortgageApplication sample to learn more about building an application within a Git repository.
After building the application, you can verify the identified metadata easily by reading the log file generated by SYSPRINT
in the LinkEdit
step above. For example, the log file for epscmort.cbl
would be
EPSCMORT-linkEdit.cbl.log
and will include the following content on lines 4-6:
IEW2322I 1220 1 INCLUDE SYSLIB(EPSCMORT)
IEW2322I 1220 2 IDENTIFY EPSCMORT('BR:main SHA:12345678')
IEW2322I 1220 3 NAME EPSCMORT(R)