diff --git a/Templates/Deploy_Pipeline/Jenkins/Jenkinsfile b/Templates/Deploy_Pipeline/Jenkins/Jenkinsfile new file mode 100644 index 00000000..8e9aeab9 --- /dev/null +++ b/Templates/Deploy_Pipeline/Jenkins/Jenkinsfile @@ -0,0 +1,209 @@ +def JenkinsAgent = "ztec-201-STC" +def pipeverbose = true +def MsgHdr = "" // Prefix label for Jenkins summaries + +pipeline { + agent { label JenkinsAgent } + + environment { + GIT_STRATEGY = "none" + GIT_CHECKOUT = "false" + wdEnvironmentFile = "EOLEB7-${application}-${targetEnvironment.capitalize()}.yaml" + wdEvidencePath = "deploy/evidences" + wdEvidencesRoot = "/var/work/wazi_deploy_evidences_jenkins/" + wdEvidencesIndex = "/var/work/wazi_deploy_evidences_jenkins_index/" + uniqueWorkspaceId = "${WORKSPACE}/${application}/deploy-${buildId}" + deployOutputDirectory = "${WORKSPACE}/${application}/DEPLOY-OUTPUT" + } + + parameters { + string(name: 'application', defaultValue: '', description: 'Application name (e.g., retirementCalculator, MortgageApplication)') + choice(name: 'packageType', choices: ['build', 'release'], description: 'Package type: a preliminary build or release candidate') + string(name: 'packageReference', defaultValue: '', description: 'Release version(release pipeline) /branch name(build pipeline) (release eg: rel-1.6.1 )') + string(name: 'buildId', defaultValue: '', description: 'Build pipeline ID (e.g., 00000018)') + choice(name: 'targetEnvironment', choices: ['integration', 'acceptance', 'production'], description: 'Deployment target environment') + + } + + options { + disableConcurrentBuilds() + timestamps() + } + + stages { + + + stage('Validate Parameters') { + steps { + script { + echo "\n===============================" + echo "Deployment Pipeline Parameters" + echo "===============================" + echo "[INFO] Application: ${application}" + echo "[INFO] Package Type: ${packageType}" + echo "[INFO] Package Reference: ${packageReference}" + echo "[INFO] Build ID: ${buildId}" + echo "[INFO] Target Environment: ${targetEnvironment}" + echo "[INFO] Workspace: ${uniqueWorkspaceId}" + echo "===============================\n" + + def errors = [] + if (!application) errors << "application is required" + if (!buildId) errors << "buildId is required" + + if (errors) { + def msg = "Validation failed: ${errors.join(', ')}" + echo "[ERROR] ${msg}" + + addSummary icon: "error", + text: "${MsgHdr} ${msg}", + style: "color: var(--danger-color)" + + addErrorBadge icon: "error", + text: msg + error msg + } + + def msg = "Validation passed" + echo "[INFO] ${msg}" + + addSummary icon: "success.gif", + text: "Validation passed", + style: "color: var(--success-color)" + } + } + } + + + stage('Generate Plan') { + when { expression { currentBuild.result == null || currentBuild.result == "SUCCESS" } } + steps { + script { + echo "[INFO] Generating deployment plan for ${targetEnvironment}" + + def CMD = "wazideploy-generate.sh -w ${uniqueWorkspaceId} -a ${application} -P ${packageType} -R ${packageReference} -I ${buildId}" + echo "[INFO] Executing: ${CMD}" + + def rc = sh(script: CMD, returnStatus: true) + + if (rc == 0) { + def msg = "Deployment plan generation passed (RC=0)" + echo msg + + addSummary icon: "success.gif", + text: "Deployment plan generation passed", + style: "color: var(--success-color)" + } else { + def msg = "Deployment plan generation FAILED (RC=${rc})" + echo "[ERROR] ${msg}" + + addSummary icon: "error", + text: "${MsgHdr} ${msg}", + style: "color: var(--danger-color)" + + addErrorBadge icon: "error", + text: msg + error msg + } + } + } + } + + + stage('Deploy') { + when { expression { currentBuild.result == null || currentBuild.result == "SUCCESS" } } + steps { + script { + echo "[INFO] Deploying to ${targetEnvironment}" + + def CMD = "wazideploy-deploy.sh -w ${uniqueWorkspaceId} -e ${wdEnvironmentFile} -l ${wdEvidencePath}/evidence.yaml < /dev/null" + echo "[INFO] Executing: ${CMD}" + + def rc = sh(script: CMD, returnStatus: true) + + if (rc == 0) { + def msg = "Deployment passed (RC=0)" + echo "[INFO] ${msg}" + + addSummary icon: "success.gif", + text: "Deployment passed", + style: "color: var(--success-color)" + } else { + def msg = "Deployment FAILED (RC=${rc})" + echo "[ERROR] ${msg}" + addSummary icon: "error", + text: "${MsgHdr} ${msg}", + style: "color: var(--danger-color)" + + addErrorBadge icon: "error", + text: msg + error msg + } + } + } + } + + stage('Report') { + when { expression { currentBuild.result == null || currentBuild.result == "SUCCESS" } } + steps { + script { + echo "[INFO] Generating deployment report" + + def evidenceCmd = "wazideploy-evidence.sh -w ${uniqueWorkspaceId} -l ${wdEvidencePath}/evidence.yaml -o deploy/deployment-report.html" + sh evidenceCmd + + sh "mkdir -p ${deployOutputDirectory}" + sh "mkdir -p ${deployOutputDirectory}/deploy-${targetEnvironment}" + + def sourceEvidenceFile = "${uniqueWorkspaceId}/deployPkgDir/deploy/evidences/evidence.yaml" + def wdEvidencesDir = "${wdEvidencesRoot}/${application}/${targetEnvironment}" + + sh "mkdir -p ${wdEvidencesDir} && mkdir -p ${wdEvidencesIndex}" + sh "cp ${sourceEvidenceFile} ${wdEvidencesDir}/evidence-${buildId}.yaml" + + def indexCmd = "wazideploy-evidence --index ${wdEvidencesIndex} --dataFolder ${wdEvidencesRoot} i" + def rc = sh(script: indexCmd, returnStatus: true) + + if (rc == 0) { + def msg = "Deployment report generation passed (RC=0)" + echo "[INFO] ${msg}" + + addSummary icon: "success.gif", + text: " Deployment report generation passed", + style: "color: var(--success-color)" + } else { + def msg = "Deployment report generation FAILED (RC=${rc})" + echo "[ERROR] ${msg}" + + addSummary icon: "error", + text: "${MsgHdr} ${msg}", + style: "color: var(--danger-color)" + + addErrorBadge icon: "error", + text: msg + error msg + } + sourceEvidenceFilePath = "${uniqueWorkspaceId}/deployPkgDir/deploy/evidences" + + } + } + + post { + always { + dir("${uniqueWorkspaceId}/deployPkgDir/deploy/evidences") { + archiveArtifacts allowEmptyArchive: true, artifacts: '*.yaml' + } + dir("${WORKSPACE}/deployPkgDir/deploy") { + archiveArtifacts allowEmptyArchive: true, artifacts: '*.html' + } + } + } + } + + stage('Workspace Cleanup') { + steps { + cleanWs(deleteDirs: true, notFailBuild: true) + } + } + } +} diff --git a/Templates/Deploy_Pipeline/Jenkins/README.md b/Templates/Deploy_Pipeline/Jenkins/README.md new file mode 100644 index 00000000..dc9baac2 --- /dev/null +++ b/Templates/Deploy_Pipeline/Jenkins/README.md @@ -0,0 +1,119 @@ +# Jenkins Deployment Pipeline Template + +This template provides a [Jenkinsfile](Jenkinsfile) to set up a **Deployment pipeline** for applications managed in a Git repository. + +## Overview and Capabilities + +This Jenkins pipeline implements the [Git-based process and branching model for mainframe development](https://ibm.github.io/z-devops-acceleration-program/docs/branching/git-branching-model-for-mainframe-dev) and leverages [Common Backend Scripts](https://github.com/IBM/dbb/blob/main/Templates/Common-Backend-Scripts/README.md) along with **IBM Wazi Deploy** to automate deployments of pre-built application packages from an artifact repository into integration, acceptance, and production environments on z/OS. + +The pipeline supports **manual triggers** and implements the following stages: + +* **Validate Parameters** + - Validates pipeline input parameters passed during manual trigger or via API. + - Determines the appropriate environment configuration file based on the selected target environment. + - Ensures required parameters (e.g., `application`, `packageType`, `buildId`) are defined. + +* **Generate Plan** + - Uses [`wazideploy-generate.sh`](../../Common-Backend-Scripts/wazideploy-generate.sh) to create the deployment plan in z/OS Unix System Services (USS). + - Supports both the deployment of preliminary **build** and **release** packages. + +* **Deploy** + - Executes [`wazideploy-deploy.sh`](../../Common-Backend-Scripts/wazideploy-deploy.sh) to deploy the application to the selected target environment. + - Produces initial evidence files and deployment logs. + - Uses `returnStatus` for robust error handling (`sh(script: ..., returnStatus: true)`). + +* **Report** + - Invokes [`wazideploy-evidence.sh`](../../Common-Backend-Scripts/wazideploy-evidence.sh) to generate deployment reports and evidence summaries. + - Persists evidence files to centralized directories. + - Updates the Wazi Deploy evidence index for traceability. + +* **Workspace Cleanup** + - Cleans up intermediate files and temporary deployment directories +--- + +The pipeline supports controlled deployments to **integration**, **acceptance**, or **production** environments. +It uses Jenkins **stages**, **steps**, and **post conditions** for robust execution and error handling. + +![image.png](./images/image.png) + +--- + +## Prerequisites + +To leverage this Jenkinsfile: + +* A **Jenkins environment** with agents capable of running shell scripts and connecting to the z/OS UNIX System Services (USS) environment. +* Access to **IBM Wazi Deploy** scripts and **Common Backend Scripts** installed on the deployment agent. +* Appropriate workspace permissions for reading/writing deployment directories and evidence files. + +--- + +## Installation and Setup + +* Place the [Jenkinsfile](Jenkinsfile) in the root directory of your project repository. +* Please review the definitions thoroughly with your Jenkins administrator and adjust pipeline environment variables, workspace paths, and script locations according to your environment. + +### Required Parameters + +| Parameter | Description | +| ------------------- | ----------------------------------------------------------------------------------- | +| `application` | Application name to deploy. | +| `buildId` | Build pipeline ID corresponding to the artifact. | +| `packageReference` | Release version (e.g., `rel-2.6.0`) or branch name(e.g., `main`, `feature`). | +| `targetEnvironment` | Deployment target (`integration`, `acceptance`, `production`). | +| `packageType` | Package type: `build` or `release`. | + +--- + +## Pipeline Usage + +This Jenkinsfile can be executed: + +* **Manually** via Jenkins → Build with Parameters + +### Example + +1. Open Jenkins → select the job → **Build with Parameters** +2. Enter values: + Eg: + ``` + application: retirementCalculator + buildId: 12247 + packageReference: rel-1.6.1 + targetEnvironment: integration + packageType: release + + ``` + +3. Click **Build** + +The pipeline will: + +1. Validate input parameters +2. Generate a deployment plan +3. Deploy the application +4. Generate deployment report and evidence +5. Clean up workspace + +--- + +## Error Handling and Return Codes + +* Shell commands are executed with `returnStatus: true` to capture **exit codes** without failing the pipeline immediately. +* Custom logic handles deployment errors, evidence generation failures, and workspace cleanup issues. +* Jenkins `post` blocks ensure **always-run cleanup** and artifact archiving. + +--- + + +## Summary + +This Jenkinsfile provides a **robust deployment CD pipeline** for mainframe applications: + +* Automates deployments of prebuilt packages to multiple environments +* Maintains auditable deployment evidence and reports +* Provides detailed logging and error handling +* Cleans workspace to maintain agent hygiene + +It integrates **Common Backend Scripts** into enterprise Jenkins pipelines for automated, traceable deployment workflows. + diff --git a/Templates/Deploy_Pipeline/Jenkins/images/image.png b/Templates/Deploy_Pipeline/Jenkins/images/image.png new file mode 100644 index 00000000..de87dbbb Binary files /dev/null and b/Templates/Deploy_Pipeline/Jenkins/images/image.png differ diff --git a/Templates/Deploy_Pipeline/README.md b/Templates/Deploy_Pipeline/README.md index 5730eb77..58b86d8d 100644 --- a/Templates/Deploy_Pipeline/README.md +++ b/Templates/Deploy_Pipeline/README.md @@ -1,3 +1,6 @@ This folder contains templates for standalone deployment pipelines. -Refer to [Deploy_Pipeline/REDME.md](../Deploy_Pipeline/README.md) +Documentation: + +- [Gitlab Pipeline Templates](./Gitlab/README.md) +- [Jenkins Pipeline Overview](./Jenkins/README.md)