Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 208 additions & 0 deletions Templates/Deploy_Pipeline/Jenkins/Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a previous version the description of the input parms were more details. Can we please add that back in?

string(name: 'application', defaultValue: '', description: 'Application name')
choice(name: 'PackageType', choices: ['build', 'release'], description: 'Package type')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use consistent casing of the variables.

string(name: 'buildId', defaultValue: '', description: 'Build pipeline ID')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we switch the order and have packageReference before the buildId, please?

string(name: 'packageReference', defaultValue: '', description: 'Release version / branch name')
choice(name: 'targetEnvironment', choices: ['integration','acceptance','production'], description: '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] Build ID: ${buildId}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change the order and have Package Reference before the Build ID?

echo "[INFO] Package Reference: ${packageReference}"
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') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thadbeeraf - The stages need a when condition to manage scenarios when a previous stage failed.

Today, they just continue to execute.

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to separate this into two stages:

  1. It's the report of the current deployment (and btw line 152 requires some error handling)
  2. It's storing the the yaml file to the shared evidence folder.


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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please upload the the deployment-report.html. I don't see this happening when testing the template -

It's generated here:
image

But the archive step is not there:
image

I think it needs to use ${uniqueWorkspaceId} instead of ${WORKSPACE}

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)
}
}
}
}
119 changes: 119 additions & 0 deletions Templates/Deploy_Pipeline/Jenkins/README.md
Original file line number Diff line number Diff line change
@@ -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`, `buildId`, `PackageType`) 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.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion Templates/Deploy_Pipeline/README.md
Original file line number Diff line number Diff line change
@@ -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)