Pipeline
Git_To_Ispw.Jenkinsfile
The Git_To_Ispw.Jenkinsfile specified as Jenkinsfile when setting up the Multibranch pipeline gets triggered whenever the Multibranch Pipeline detects changes in one of the branches of the source repository. In contrast to the other pipeline scripts used here, it does not take any parameters.
As mentioned before, it uses a Shared Library.
It clears the workspace from previous builds and checks out (clones) the code from the Git repository.
stage ('Checkout') {
dir('./') {
deleteDir()
}
checkout scm
}
Since the following will execute the two scripts for mainframe and Java code in parallel, the content of workspace needs to be made available to the agent workspaces. This requires the use of stash in the calling script and unstash in the called script.
As mentioned above, the two scripts for mainframe build and Java build get executed in parallel.
mfCode: {
node {
Git_MainframeCode_Pipeline()
}
},
javaCode: {
node {
Git_JavaCode_Pipeline()
}
},
failFast: true
)
}
Git_MainframeCode_Pipeline.groovy
Most of the individual steps executed within this script are the same as documented in other locations and contexts already. Therefore, we document only the parts of the script that seem noteworthy.
Method call - main "flow" of the script
As Shared Library script this script implements a call method as primary method. For enhanced readability and to better follow the "flow" of the script, execution of the several stages is being implemented by separate methods within the same script.
executionFlags, a Map of Boolean variables helps to determine if a given stage shall be executed.
The script will execute:
- stage ("Initialize") - This stage will:
- clear the workspace
- unstash the workspace that has been stashed by the calling script, i.e. copy the content of workspace of the main script into its own workspace
- initialize global variables, primarily by processing the two configuration files and by determining the branch it is executing for. During initialization method determinePipelineBehavior sets the flags that determine which stages need to be executed.
- stage('Load code to mainframe') - This stage will synchronize any changes to mainframe code into Code Pipeline.
- If changes were detected the Code Pipeline CLI will create a file called automaticBuildParams.txt, listing information about the modified components. This file will be used by the next stage building the mainframe code. Method checkForBuildParams verifies that this file got created. If it did not created, it means, that no changes to mainframe code were responsible for the execution of the pipeline, and the build and test stages will be skipped.
- stage('Build mainframe code')- If changes to mainframe code were detected, this stage will use the automaticBuildParams.txt to build all components that were changed. "Build" also means that any impacted components will be generated alongside.
- stage('Execute Unit Tests') - If changes to mainframe code were detected and if "unit tests" need to be run for the current branch, this stage will execute any Total Test Virtualized tests that match components that were built by the previous stage.
- stage('Execute Unit Tests') - If changes to mainframe code were detected and if "unit tests" need to be run for the current branch, this stage will execute any Total Test Virtualized tests that match components that were built by the previous stage.
- stage('Execute Module Integration Tests') - If changes to mainframe code were detected and if "integration tests" need to be run for the current branch, this stage will execute any Total Test Virtualized tests that match components that were built by the previous stage.
- If tests were executed, Code Coverage results get retrieved.
- stage("SonarQube Scan") - This stage execute a Sonar Qube scan. This stage is executed in any case.
- stage("Trigger Release") - If the pipeline was triggered by a merge into the main branch, this stage will trigger an XL Release template
stage ('Initialize') {
dir('./') {
deleteDir()
}
unstash name: 'workspace'
initialize(execParms)
}
stage('Load code to mainframe') {
if(executionFlags.mainframeChanges) {
echo "[Info] - Loading code to mainframe level " + ispwTargetLevel + "."
runMainframeLoad()
}
else {
echo skipReason + "\n[Info] - No code will be loaded to the mainframe."
}
}
checkForBuildParams(synchConfig.ispw.automaticBuildFile)
stage('Build mainframe code') {
if(executionFlags.mainframeChanges){
echo "[Info] - Building code at mainframe level " + ispwTargetLevel + "."
runMainframeBuild()
}
else{
echo skipReason + "\n[Info] - Skipping Mainframe Build."
}
}
if(executionFlags.executeVt){
stage('Execute Unit Tests') {
runUnitTests()
}
}
if(executionFlags.executeNvt){
stage('Execute Module Integration Tests') {
runIntegrationTests()
}
}
if(executionFlags.mainframeChanges){
getCocoResults()
}
stage("SonarQube Scan") {
runSonarScan()
}
if(executionFlags.executeXlr){
stage("Trigger Release") {
triggerXlRelease()
}
}
}
Configuration files
As mentioned before, this script will use two .yml files as primary source for configuration settings.
ispwconfig.yml contains the Code Pipeline stream and application name
synchconfig.yml contains all other settings, many of which correspond to the parameters that are used by the other pipelines script example shared here.
Branch mapping
Worth mentioning is the branchInfo of the synchconfig.yml file. This is used to determine the branchMapping parameter for the Git to Code Pipeline synchronization:
Each entry corresponds to a certain branch name or branch name pattern and lists
- the target level in the Code Pipeline life cycle to use.
- and the rule to use for creating assignments for the corresponding branch.
Method processBranchInfo is used to match the current branch to any of the entries and build the value for the branchMapping parameter. If a branch cannot be mapped, execution of the script will be aborted.
Method determinePipelineBehavior
This method, initially, determines which stages gets executed based on the current situation:
- If this is the first build for the corresponding branch, only the Sonar scan will be executed to build a "baseline" for "new" code
- For feature branches mainframe changes may have to by synchronized and built, and "unit tests" will be executed
- For bugfix branches mainframe changes may have to by synchronized and built, and "unit tests" will be executed
- For the development branch mainframe changes may have to by synchronized and built, "unit tests" and "integration tests" will be executed
- For the main branch mainframe changes may have to by synchronized and built, "integration tests" will be executed, and an XL Release template will be triggered
if (buildNumber == "1") {
executionFlags.mainframeChanges = false
executionFlags.executeVt = false
executionFlags.executeNvt = false
executionFlags.executeXlr = false
}
else if (BRANCH_NAME.contains("feature")) {
executionFlags.mainframeChanges = true
executionFlags.executeVt = true
executionFlags.executeNvt = false
executionFlags.executeXlr = false
}
else if (BRANCH_NAME.contains("bugfix")) {
executionFlags.mainframeChanges = true
executionFlags.executeVt = true
executionFlags.executeNvt = false
executionFlags.executeXlr = false
}
else if (BRANCH_NAME.contains("development")) {
executionFlags.mainframeChanges = true
executionFlags.executeVt = true
executionFlags.executeNvt = true
executionFlags.executeXlr = false
}
else if (BRANCH_NAME.contains("main")) {
executionFlags.mainframeChanges = true
executionFlags.executeVt = false
executionFlags.executeNvt = true
executionFlags.executeXlr = true
}
}
Method processBranchInfo
branchInfo.each {
branchMappingString = branchMappingString + it.key + '** => ' + it.value.ispwLevel + ',' + it.value.mapRule + '\n'
if(BRANCH_NAME.contains(it.key)) {
ispwTargetLevel = it.value.ispwLevel
}
}
}