Skip to content

Adding custom dependencies to source files

Dennis Behm edited this page Nov 17, 2021 · 2 revisions

1. Introduction

The DBB scanners parse the source files to understand their logical dependencies. These dependencies are used by the dependency resolver API to populate the build libraries as well as by the impact resolver for the impact analysis calculation.

However, there are some dependencies which cannot be identified by parsing the build file. Let’s assume the repository manages source code but also db2 bind members containing settings for the db2 bind step, or other members which need to be available in the build process as a dependency within the build libraries. Also, custom preprocessors can utilize custom include macros and externalized code fragments, which cannot be understood as a dependency by the scanners.

In these situations, two problems may occur :

  1. The build framework does not upload these dependent files to the build libraries and the build fails.
  2. Impact builds don’t recognize all impacted files which are expected to be rebuilt.

The following recipe shows how to programmatically create custom dependencies for logical files in the context of zAppBuild.

2. Establish custom dependencies

The below solution will document the necessary modifications and demonstrate how it is possible to create a custom dependency between files to solve the above scenarios.

IBM Dependency Based Build APIs allow to add custom logical dependencies to an existing logicalFile object (*ILogicalFile).

Depending on your scenario, you might just like to leverage the data to populate the build libraries. While in a userBuild scenario, the DependencyResolverAPI runs without a repository client connection to the DBB Webapp, you need to make sure, that the DependencyResolver has the necessary information available.

The extended use case is to store the dependency also on the DBB Webapp to support the impact build scenarios.

To support these scenarios, it requires modifications at several locations in the zAppBuild sample build framework.

2.1. How to configure this solution

2.1.1. Necessary zAppBuild modifications

The following snippets uses Cobol source files as an example and picks the Db2 Bind card member scenario, which is also managed in the repository. But it can be any other dependency, which cannot be obtained from the original source code.

2.1.1.1 Enable DependencyResolver to resolve the dependent file to upload to the build libraries

In our scenario, we have next to the cobol folder a db2bind folder containing the db2bind member, which has the same name as the COBOL source. Please keep these rules and assumptions in mind when reviewing the below changes.

In the Cobol.groovy file add the below code to create a new logical dependency to the logical file, which allows the dependency resolver to resolve the EPSNBRVL.db2bind file.

Adapt the change to your groovy script (here Cobol.groovy) :

	// DependencyResolver and member
	String rules = props.getFileProperty('cobol_resolutionRules', buildFile)
	DependencyResolver dependencyResolver = buildUtils.createDependencyResolver(buildFile, rules)
	LogicalFile logicalFile = dependencyResolver.getLogicalFile()
	String member = CopyToPDS.createMemberName(buildFile)
	
	// add custom dependency
	println "${props.workspace}/${props.application}/db2bind/${member}.db2bind"
	File db2BindFile = new File("${props.workspace}/${props.application}/db2bind/${member}.db2bind")
	//if the file exists
	if(db2BindFile.exists()){
		logicalFile.addLogicalDependency(new LogicalDependency(member, "META", "DB2BINDMEMBER"))
		println logicalFile
	}
	
	// copy build file and dependency files to data sets
	if(isZUnitTestCase){
		buildUtils.copySourceFiles(buildFile, props.cobol_testcase_srcPDS, null, null)
	}else{
		buildUtils.copySourceFiles(buildFile, props.cobol_srcPDS, props.cobol_cpyPDS, dependencyResolver)
	}

Please be aware that the snippet is added before the invocation of buildUtils.copySourceFiles method, which is the method that resolves the logical dependencies to physical dependencies and upload the files to the build libraries.

For this sample, the member name is calculated before defining the additional dependency. Please remember that the createMemberName method returns the String in upper case - Upper/Lower case matters. The above code will automatically add the dependency and allow the dependency resolver API along with the correct dependency resolution rules to resolve the physical file and upload it to the build datasets.

2.1.1.2 Enable ImpactResolver to support impact builds when changing the dependency

To enable the impact build scenario, a code change is required in the section of zAppBuild which scans files and stores the metadata in the DBB Webapp. This section is located within the ImpactUtilities.groovy file during the update of the collections. It needs a similar code snippet like above to store the additional dependency.

Refer to https://github.com/IBM/dbb-zappbuild/blob/development/utilities/ImpactUtilities.groovy#L500

Adapt the change to your ImpactUtilities.groovy in the method updateCollectionscript :

//Code to create the dependency between the built file and the Db2bind file
String member = CopyToPDS.createMemberName(file)
String db2BildFileLoc = "${props.workspace}/${props.application}/db2bind/${member}.db2bind"
File db2BindFile = new File(db2BildFileLoc)
println "++ " + db2BindFile
String db2FileMember= CopyToPDS.createMemberName(db2BildFileLoc)
if(db2BindFile.exists()){
   logicalFile.addLogicalDependency(new LogicalDependency(db2FileMember, “META”, “DB2BINDMEMBER”))
}

2.1.2. Configure the search path rules for the dependency and impact calculation

In the file myApplication/application-conf/application.properties, a new rule needs to be added. For this example we will call it db2BindDependencyRule.

Copy/Paste this code:

## custom dependency rule
db2BindDependencyRule = {"library": "META", \
					"searchPath": [ \
                    {"sourceDir": "${workspace}", "directory": "${application}/db2bind"} \
                 ] \
               }

To enable the DependencyResolver scenario, please add it to the cobol_resolutionRules within the application-conf/Cobol.properties file.

Refer to https://github.com/IBM/dbb-zappbuild/blob/development/samples/application-conf/Cobol.properties#L11

Copy/Paste this code:

# 
# COBOL dependency resolution rules
# Rules defined in application.properties
cobol_resolutionRules=[${copybookRule},${db2BindDependencyRule}]

To enable the impact resolver add the db2BindDependencyRule to the impactResolutionRules in application.properties

Copy/Paste this code:

# Impact analysis resolution rules (JSON format)
impactResolutionRules=[${copybookRule},${bmsRule},${linkRule},${propertyRule},${db2BindDependencyRule}]

2.2 Sample invocation

2.2.1 Run a User Build to demo the new dependency

The above changes will add a new dependency, which can be displayed printing the logicalFile :

The DependencyResolver is now able to resolve the db2bind file and will upload it into the dependency dataset.

2.2.2 Pipeline builds

When scanning the application repository, you will see, that the logicalFile epsnbrvl.cbl now contains a new logical dependency to the db2bindmember :

When the db2bind member is changed, the impactBuild functionality in zAppBuild will detect the program and will rebuild it.

3. Conclusion

This recipe shows how zAppBuild can be adapted to manage new custom dependencies which the scanners do not detect. Depending on your scenario, it will probably be more complex. The dependency creation between files may be more specific and may require several dependency links.