Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release zAppBuild 3.7.0 #483

Merged
merged 8 commits into from
Mar 7, 2024
8 changes: 7 additions & 1 deletion build-conf/build.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@
# These properties files expect to contain centrally managed defaults
# such as system datasets, language script specific settings
#
buildPropFiles=datasets.properties,dependencyReport.properties,Assembler.properties,BMS.properties,\
buildPropFiles=${systemDatasets},dependencyReport.properties,Assembler.properties,BMS.properties,\
MFS.properties,PSBgen.properties,DBDgen.properties,ACBgen.properties,Cobol.properties,\
LinkEdit.properties,PLI.properties,REXX.properties,ZunitConfig.properties,Transfer.properties,\
CRB.properties,zCEE3.properties,zCEE2.properties

#
# Comma separated list of property files defining system datasets
# This property is validated during the initialization process of zAppBuild
#
systemDatasets=datasets.properties

#
# Comma separated list of default application configuration property files to load
# Supports both relative path (to zAppBuild/build-conf/) and absolute path
Expand Down
3 changes: 2 additions & 1 deletion build-conf/zCEE2.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#
# Comma separated list of required build properties for zCEE3.groovy
zcee2_requiredBuildProperties=zcee2_zconbtPath,zcee2_JAVA_HOME
zcee2_requiredBuildProperties=zcee2_zconbtPath

#
# Absolute path to zconbt executable on z/OS UNIX System Services
Expand All @@ -12,6 +12,7 @@ zcee2_zconbtPath=
#
# Java installation used by the zconbt utility
# for instance: /usr/lpp/java/J8.0_64
# if not set, the value of the JAVA_HOME environment variable will be used
zcee2_JAVA_HOME=

#
Expand Down
26 changes: 25 additions & 1 deletion build.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import groovy.cli.commons.*
@Field def reportingUtils= loadScript(new File("utilities/ReportingUtilities.groovy"))
@Field def filePropUtils= loadScript(new File("utilities/FilePropUtilities.groovy"))
@Field def dependencyScannerUtils= loadScript(new File("utilities/DependencyScannerUtilities.groovy"))
@Field def validationUtils= loadScript(new File("utilities/DatasetValidationUtilities.groovy"))
@Field String hashPrefix = ':githash:'
@Field String giturlPrefix = ':giturl:'
@Field String gitchangedfilesPrefix = ':gitchangedfiles:'
Expand Down Expand Up @@ -268,14 +269,15 @@ options:
cli.r(longOpt:'reset', 'Deletes the dependency collections and build result group from the MetadataStore')
cli.v(longOpt:'verbose', 'Flag to turn on script trace')
cli.pv(longOpt:'preview', 'Supplemental flag indicating to run build in preview mode without processing the execute commands')
cli.cd(longOpt:'checkDatasets', 'Optional flag to validate the presense of the defined system datasets. ')

// scan options
cli.s(longOpt:'scanOnly', 'Flag indicating to only scan source files for application without building anything (deprecated use --scanSource)')
cli.ss(longOpt:'scanSource', 'Flag indicating to only scan source files for application without building anything')
cli.sl(longOpt:'scanLoad', 'Flag indicating to only scan load modules for application without building anything')
cli.sa(longOpt:'scanAll', 'Flag indicating to scan both source files and load modules for application without building anything')

// web application credentials (overrides properties in build.properties)
// DBB metadatastore credentials (overrides properties in build.properties)
cli.url(longOpt:'url', args:1, 'Db2 JDBC URL for the MetadataStore. Example: jdbc:db2:<Db2 server location>')
cli.id(longOpt:'id', args:1, 'Db2 user id for the MetadataStore')
cli.pw(longOpt:'pw', args:1, 'Db2 password (encrypted with DBB Password Utility) for the MetadataStore')
Expand Down Expand Up @@ -352,6 +354,18 @@ def populateBuildProperties(def opts) {
// assert workspace
buildUtils.assertBuildProperties('workspace,outDir')

// Validate that workspace exists
if (!(new File (props.workspace).exists())) {
println "!! The specified workspace folder ${props.workspace} does not exist. Build exits."
System.exit(1)
}

// Check read/write permission of specified out/log dir if already existing
if (new File (props.outDir).exists() && !(new File(props.outDir).canWrite())) {
println "!! User does not have WRITE permission to work output directory ${props.outDir}. Build exits."
System.exit(1)
}

// load build.properties
def buildConf = "${zAppBuildDir}/build-conf"
if (opts.v) println "** Loading property file ${buildConf}/build.properties"
Expand Down Expand Up @@ -456,6 +470,7 @@ def populateBuildProperties(def opts) {
if (opts.b) props.baselineRef = opts.b
if (opts.m) props.mergeBuild = 'true'
if (opts.pv) props.preview = 'true'
if (opts.cd) props.checkDatasets = 'true'

// scan options
if (opts.s) props.scanOnly = 'true'
Expand Down Expand Up @@ -528,6 +543,9 @@ def populateBuildProperties(def opts) {
if(props.reportExternalImpactsAnalysisDepths) assert (props.reportExternalImpactsAnalysisDepths == 'simple' || props.reportExternalImpactsAnalysisDepths == 'deep' ) : "*! Build Property props.reportExternalImpactsAnalysisDepths has an invalid value"
if(props.baselineRef) assert (props.impactBuild) : "*! Build Property props.baselineRef is exclusive to an impactBuild scenario"

// Validate system datasets
if (props.checkDatasets && props.systemDatasets) validationUtils.validateSystemDatasets(props.systemDatasets, props.verbose)

// Print all build properties + some envionment variables
if (props.verbose) {
println("java.version="+System.getProperty("java.runtime.version"))
Expand Down Expand Up @@ -793,7 +811,13 @@ def finalizeBuildProcess(Map args) {
println("** Build State : $state")
if (props.preview) println("** Build ran in preview mode.")
println("** Total files processed : ${args.count}")
if (props.errorSummary) {
println("** Summary of error messages")
println("${props.errorSummary}")
}
println("** Total build time : $duration\n")



// if error occurred signal process error
if (props.error)
Expand Down
75 changes: 74 additions & 1 deletion docs/BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ build options:
-cco,--cccOptions Headless Code Coverage Collector Options

-re,--reportExternalImpacts Flag to activate analysis and report of external impacted files within DBB collections

-cd,--checkDatasets Flag to enable validation of the defined system dataset definitions.

Db2 MetadataStore configuration options
-url,--url <arg> Db2 JDBC URL for the MetadataStore.
Expand Down Expand Up @@ -256,6 +256,7 @@ utility options
- [Perform a Scan Source build](#perform-a-scan-source-build)
- [Perform a Scan Source + Outputs build](#perform-a-scan-source--outputs-build)
- [Dynamically Overwrite build properties](#dynamically-overwrite-build-properties)
- [Validate System Datasets](#validate-system-datasets)

<!-- /TOC -->
### Build a Single Program
Expand Down Expand Up @@ -2094,3 +2095,75 @@ required props = linkedit_srcPDS,linkedit_objPDS,linkedit_loadPDS,linkedit_linkE
</details>


### Validate System Datasets

During the initialization phase of the build, a validation of the defined system datasets can be performed. The system datasets are configured with the build property `systemDatasets` in [build-conf/build.properties](../build-conf/build.properties), which contains one or multiple references to build property files defining key-value pairs listing the system datasets. In zAppBuild the default file is called [datasets.properties](../build-conf/datasets.properties) managed in the `build-conf` folder.

To enable validation of system datasets specify the option `--checkDatasets`. It is available in any build scenario. Be aware that this functionality is also available as a stand-alone script and find the instructions [here](../utilities/README.md#dataset-validation-utilities)

```
groovyz dbb-zappbuild/build.groovy \
--workspace /var/dbb/dbb-zappbuild/samples \
--hlq DBB.ZAPP.CLEAN.MASTER \
--workDir /var/dbb/out/MortgageApplication \
--application MortgageApplication \
--logEncoding UTF-8 \
--impactBuild \
--verbose \
--checkDatasets
```
<details>
<summary>Build log</summary>

```
** Build start at 20210622.082942.029
** Input args = /var/dbb/dbb-zappbuild/samples --hlq DBB.ZAPP.CLEAN.MASTER --workDir /var/dbb/out/MortgageApplication --application MortgageApplication --logEncoding UTF-8 --impactBuild --verbose --propOverwrite mainBuildBranch=develop
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/datasets.properties
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/Assembler.properties
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/BMS.properties
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/MFS.properties
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/PSBgen.properties
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/DBDgen.properties
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/ACBgen.properties
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/Cobol.properties
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/LinkEdit.properties
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/PLI.properties
** Loading property file /ZT01/var/dbb/dbb-zappbuild/build-conf/ZunitConfig.properties
** appConf = /var/dbb/dbb-zappbuild/samples/MortgageApplication/application-conf
** Loading property file /var/dbb/dbb-zappbuild/samples/MortgageApplication/application-conf/file.properties
** Loading property file /var/dbb/dbb-zappbuild/samples/MortgageApplication/application-conf/BMS.properties
** Loading property file /var/dbb/dbb-zappbuild/samples/MortgageApplication/application-conf/Cobol.properties
** Loading property file /var/dbb/dbb-zappbuild/samples/MortgageApplication/application-conf/LinkEdit.properties
** Overwriting build property mainBuildBranch from cli argument --propOverwrite with value develop
** The dataset PLI.V5R2.SIBMZCMP referenced for property IBMZPLI_V52 was found.
*! No dataset defined for property IBMZPLI_V51 specified in /ZT01/var/dbb/dbb-zappbuild/build-conf/datasets.properties.
** The dataset WMQ.V9R2M4.SCSQPLIC referenced for property SCSQPLIC was found.
** The dataset COBOL.V6R1.SIGYCOMP referenced for property SIGYCOMP_V6 was found.
** The dataset CICSTS.V5R4.CICS.SDFHCOB referenced for property SDFHCOB was found.
*! No dataset defined for property SIGYCOMP_V4 specified in /ZT01/var/dbb/dbb-zappbuild/build-conf/datasets.properties.
** The dataset HLASM.SASMMOD1 referenced for property SASMMOD1 was found.
** The dataset SYS1.MACLIB referenced for property MACLIB was found.
** The dataset PDTCC.V1R8.SIPVMODA referenced for property PDTCCMOD was found.
** The dataset CICSTS.V5R4.CICS.SDFHLOAD referenced for property SDFHLOAD was found.
** The dataset CICSTS.V5R4.CICS.SDFHMAC referenced for property SDFHMAC was found.
** The dataset CEE.SCEEMAC referenced for property SCEEMAC was found.
** The dataset WMQ.V9R2M4.SCSQCOBC referenced for property SCSQCOBC was found.
** The dataset IMS.V15R1.SDFSMAC referenced for property SDFSMAC was found.
** The dataset RDZ.V14R1.SFELLOAD referenced for property SFELLOAD was found.
** The dataset DBC0CFG.DB2.V12.SDSNLOAD referenced for property SDSNLOAD was found.
** The dataset CICSTS.V5R4.CICS.SDFHPL1 referenced for property SDFHPL1 was found.
** The dataset WMQ.V9R2M4.SCSQLOAD referenced for property SCSQLOAD was found.
** The dataset IMSCFG.IMSC.REFERAL referenced for property REFERAL was found.
** The dataset DEBUG.V14R1.SEQAMOD referenced for property SEQAMOD was found.
** The dataset DBC0CFG.SDSNEXIT referenced for property SDSNEXIT was found.
** The dataset IMS.V15R1.SDFSRESL referenced for property SDFSRESL was found.
** The dataset RATCFG.ZUNIT.SBZUSAMP referenced for property SBZUSAMP was found.
** The dataset CEE.SCEELKED referenced for property SCEELKED was found.
..... // lists of all build properties
...
...
```

</details>


23 changes: 13 additions & 10 deletions languages/zCEE2.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import java.nio.file.*;
buildUtils.assertBuildProperties(props.zcee2_requiredBuildProperties)

// create updated build map, removing duplicates in case of PROJECT input Type
HashMap<String, String> updatedBuildMap = new HashMap<String, String>()
HashMap<String, String> updatedBuildList = new HashMap<String, String>()

println("** Streamlining the build list to remove duplicates")
argMap.buildList.each { buildFile ->
Expand All @@ -36,27 +36,27 @@ argMap.buildList.each { buildFile ->
}
}
if (projectDirFound) {
updatedBuildMap.put(projectDir.getPath(), "PROJECT")
updatedBuildList.putIfAbsent(projectDir.getPath(), "PROJECT")
} else {
if (props.verbose) println("!* No project directory found for file '${buildFile}'. Skipping...")
}
} else {
updatedBuildMap.put(buildFile, inputType);
updatedBuildList.put(buildFile, inputType);
}
} else {
println("!* No Input Type mapping for file ${buildFile}, skipping it...")
}
}

println("** Building ${updatedBuildMap.size()} API ${updatedBuildMap.size() == 1 ? 'definition' : 'definitions'} mapped to ${this.class.getName()}.groovy script")
println("** Building ${updatedBuildList.size()} API ${updatedBuildList.size() == 1 ? 'definition' : 'definitions'} mapped to ${this.class.getName()}.groovy script")
// sort the build list based on build file rank if provided
HashMap<String, String> sortedMap = buildUtils.sortBuildMap(updatedBuildMap, 'zcee2_fileBuildRank')
HashMap<String, String> sortedList = buildUtils.sortBuildListAsMap(updatedBuildList, 'zcee2_fileBuildRank')

int currentBuildFileNumber = 1

// iterate through build list
sortedMap.each { buildFile, inputType ->
println "*** (${currentBuildFileNumber++}/${sortedMap.size()}) Building ${inputType == "PROJECT" ? 'project' : 'properties file'} $buildFile"
sortedList.each { buildFile, inputType ->
println "*** (${currentBuildFileNumber++}/${sortedList.size()}) Building ${inputType == "PROJECT" ? 'project' : 'properties file'} $buildFile"

String parameters = ""
String outputDir = ""
Expand Down Expand Up @@ -122,12 +122,15 @@ sortedMap.each { buildFile, inputType ->
StringBuffer shellOutput = new StringBuffer()
StringBuffer shellError = new StringBuffer()

String JAVA_HOME = props.getFileProperty('zcee2_JAVA_HOME', buildFile)
String javaHome = props.getFileProperty('zcee2_JAVA_HOME', buildFile)
if (!javaHome) {
javaHome = System.getenv("JAVA_HOME")
}

ProcessBuilder cmd = new ProcessBuilder(zconbtPath, parameters);
Map<String, String> env = cmd.environment();
env.put("JAVA_HOME", JAVA_HOME);
env.put("PATH", JAVA_HOME + "/bin" + ";" + env.get("PATH"))
env.put("JAVA_HOME", javaHome);
env.put("PATH", javaHome + "/bin" + ":" + env.get("PATH"))
Process process = cmd.start()
process.consumeProcessOutput(shellOutput, shellError)
process.waitFor()
Expand Down
1 change: 1 addition & 0 deletions test/testScripts/resetBuild.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.ibm.dbb.*
import com.ibm.dbb.build.*

@Field BuildProperties props = BuildProperties.getInstance()
@Field def assertionList = []

println "\n**************************************************************"
println "** Executing test script ${this.class.getName()}.groovy"
Expand Down
50 changes: 46 additions & 4 deletions utilities/BuildUtilities.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,43 @@ def sortBuildList(List<String> buildList, String rankPropertyName) {
return sortedList
}

/*
* sortBuildListAsMap - sorts a build List stored as Map by rank property values
*/
def sortBuildListAsMap(HashMap<String, String> buildMap, String rankPropertyName) {
HashMap<String, String> sortedMap = [:]
TreeMap<Integer,HashMap<String, String>> rankings = new TreeMap<Integer,HashMap<String, String>>()
HashMap<String, String> unranked = new HashMap<String, String>()

// sort buildFiles by rank
buildMap.each { buildFile, inputType ->
String rank = props.getFileProperty(rankPropertyName, buildFile)
if (rank) {
Integer rankNum = rank.toInteger()
HashMap<String, String> ranking = rankings.get(rankNum)
if (!ranking) {
ranking = new HashMap<String, String>()
rankings.put(rankNum, ranking)
}
ranking.put(buildFile, inputType)
} else {
unranked.put(buildFile, inputType)
}
}

// loop through rank keys adding sub lists (TreeMap automatically sorts keySet)
rankings.keySet().each { key ->
HashMap<String, String> ranking = rankings.get(key)
if (ranking)
sortedMap.putAll(ranking)
}

// finally add unranked buildFiles
sortedMap.putAll(unranked)

return sortedMap
}

/*
* updateBuildResult - used by language scripts to update the build result after a build step
*/
Expand All @@ -303,7 +340,8 @@ def updateBuildResult(Map args) {
if (args.errorMsg) {
buildResult.setStatus(buildResult.ERROR)
buildResult.addProperty("error", args.errorMsg)

errorSummary = (props.errorSummary) ? "${props.errorSummary} ${args.errorMsg}\n" : " ${args.errorMsg}\n"
props.put("errorSummary", "$errorSummary")
}

// add warning message, but keep result status
Expand Down Expand Up @@ -860,17 +898,21 @@ def generateIdentifyStatement(String buildFile, String dsProperty) {
String shortGitHash = getShortGitHash(buildFile)

if (shortGitHash != null) {

String identifyString = props.application + "/" + shortGitHash
// IDENTIFY EPSCSMRT('MortgageApplication/abcabcabc')
identifyStmt = " " + "IDENTIFY ${member}(\'$identifyString\')"
identifyStmt = " " + "IDENTIFY ${member}(\'$identifyString\')"
if (identifyString.length() > maxRecordLength) {
String errorMsg = "*!* BuildUtilities.generateIdentifyStatement() - Identify string exceeds $maxRecordLength chars: identifyStmt=$identifyStmt"
println(errorMsg)
props.error = "true"
updateBuildResult(errorMsg:errorMsg)
return null
} else {
} else {
if (identifyStmt.length() > 71) { // Split IDENTIFY after col 71
// See syntax rules: https://www.ibm.com/docs/en/zos/3.1.0?topic=reference-identify-statement
identifyStmt = identifyStmt.substring(0,71) + "\n " + identifyStmt.substring(71,identifyStmt.length())
}
// return generated IDENTIFY statement
return identifyStmt
}
} else {
Expand Down
Loading