> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/ai-sre/ai-sre-for-administrators/set-up-change-management/sources/jenkins.md).

# Configure Jenkins for Deploy Change Investigator

Configure Jenkins pipelines to send build and deployment data to the [Deploy Change Investigator](/ai-sre/ai-sre-for-administrators/set-up-change-management/deploy-change-investigator.md) using shell scripts.

### Before you begin <a href="#before-you-begin" id="before-you-begin"></a>

* **Deploy Change Investigator setup:** Create build and deploy webhook integrations in AI SRE. Go to [Deploy Change Investigator](/ai-sre/ai-sre-for-administrators/set-up-change-management/deploy-change-investigator.md) to set up the integrations.
* **Jenkins pipeline access:** Permission to edit the Jenkinsfile or add build steps.
* **Webhook URLs:** Copy the build and deploy webhook URLs from your AI SRE integrations.
* **Git plugin:** Ensure the Jenkins Git plugin is installed for commit SHA access.

{% hint style="info" %}
**WHY JENKINS NEEDS SCRIPTS**

Jenkins does not have native webhook notification support like GitHub Actions or GitLab CI. Use shell scripts with `curl` to send webhook POST requests at the end of build and deploy stages.
{% endhint %}

***

### Configure build webhooks <a href="#configure-build-webhooks" id="configure-build-webhooks"></a>

Add a shell script step to your Jenkins build pipeline that runs **after** the artifact is published.

#### Declarative pipeline <a href="#declarative-pipeline" id="declarative-pipeline"></a>

Add this step to your `post` section or as the last step in your build stage:

```groovy
pipeline {
    agent any
    
    environment {
        BUILD_WEBHOOK_URL = credentials('aisre-build-webhook-url')
        ARTIFACT_REGISTRY = 'docker.example.com'
        SERVICE_NAME = 'myapp'
    }
    
    stages {
        stage('Build') {
            steps {
                // Your build steps here
                sh 'docker build -t ${ARTIFACT_REGISTRY}/${SERVICE_NAME}:${BUILD_NUMBER} .'
                sh 'docker push ${ARTIFACT_REGISTRY}/${SERVICE_NAME}:${BUILD_NUMBER}'
            }
        }
    }
    
    post {
        success {
            script {
                sh '''#!/bin/bash
                    json_payload="{\
                    \\"artifact\\": {\\"name\\": \\"${ARTIFACT_REGISTRY}/${SERVICE_NAME}\\", \\"version\\": \\"${BUILD_NUMBER}\\"},\
                    \\"source\\": {\
                    \\"commitSha\\": \\"${GIT_COMMIT}\\",\
                    \\"kind\\": \\"branch\\",\
                    \\"value\\": \\"${GIT_BRANCH}\\",\
                    \\"repository_url\\": \\"${GIT_URL}\\"},\
                    \\"service\\": {\\"name\\": \\"${SERVICE_NAME}\\", \\"version\\": \\"${BUILD_NUMBER}\\"},\
                    \\"buildId\\": \\"${BUILD_ID}\\"}"
                    
                    curl "${BUILD_WEBHOOK_URL}" \\
                      -s \\
                      -H "Content-Type: application/json" \\
                      -d "${json_payload}"
                '''
            }
        }
    }
}
```

#### Scripted pipeline <a href="#scripted-pipeline" id="scripted-pipeline"></a>

```groovy
node {
    def artifactRegistry = 'docker.example.com'
    def serviceName = 'myapp'
    def buildWebhookUrl = env.BUILD_WEBHOOK_URL
    
    stage('Build') {
        // Your build steps
        sh "docker build -t ${artifactRegistry}/${serviceName}:${BUILD_NUMBER} ."
        sh "docker push ${artifactRegistry}/${serviceName}:${BUILD_NUMBER}"
    }
    
    stage('Notify Build Complete') {
        sh """#!/bin/bash
            json_payload="{\
            \\"artifact\\": {\\"name\\": \\"${artifactRegistry}/${serviceName}\\", \\"version\\": \\"${BUILD_NUMBER}\\"},\
            \\"source\\": {\
            \\"commitSha\\": \\"${GIT_COMMIT}\\",\
            \\"kind\\": \\"branch\\",\
            \\"value\\": \\"${GIT_BRANCH}\\",\
            \\"repository_url\\": \\"${GIT_URL}\\"},\
            \\"service\\": {\\"name\\": \\"${serviceName}\\", \\"version\\": \\"${BUILD_NUMBER}\\"},\
            \\"buildId\\": \\"${BUILD_ID}\\"}"
            
            curl "${buildWebhookUrl}" \\
              -s \\
              -H "Content-Type: application/json" \\
              -d "\${json_payload}"
        """
    }
}
```

#### Environment variables reference <a href="#environment-variables-reference" id="environment-variables-reference"></a>

Jenkins provides these environment variables automatically:

* **GIT\_COMMIT:** Full SHA of the commit being built.
* **GIT\_BRANCH:** Branch name (for example, `origin/main`).
* **GIT\_URL:** Git repository URL.
* **BUILD\_ID:** Unique Jenkins build ID.
* **BUILD\_NUMBER:** Sequential build number.

**Custom variables to set:**

* **BUILD\_WEBHOOK\_URL:** Store as a Jenkins credential (Secret text).
* **ARTIFACT\_REGISTRY:** Your Docker or artifact registry URL.
* **SERVICE\_NAME:** Service identifier.

***

### Configure deploy webhooks <a href="#configure-deploy-webhooks" id="configure-deploy-webhooks"></a>

Add a shell script step to your Jenkins deployment pipeline that runs **after** the deployment completes.

#### Declarative pipeline <a href="#declarative-pipeline" id="declarative-pipeline"></a>

```groovy
pipeline {
    agent any
    
    environment {
        DEPLOY_WEBHOOK_URL = credentials('aisre-deploy-webhook-url')
        SERVICE_NAME = 'myapp'
        SERVICE_VERSION = '1.2.3'  // Pass from build job
        DEPLOY_ENV = 'production'
    }
    
    stages {
        stage('Deploy') {
            steps {
                // Your deployment steps here
                sh 'kubectl set image deployment/${SERVICE_NAME} ${SERVICE_NAME}=${ARTIFACT_REGISTRY}/${SERVICE_NAME}:${SERVICE_VERSION}'
            }
        }
    }
    
    post {
        success {
            script {
                sh '''#!/bin/bash
                    json_payload="{\
                    \\"services\\": [{\\"service\\": \\"${SERVICE_NAME}\\", \\"version\\": \\"${SERVICE_VERSION}\\"}],\
                    \\"environments\\": [\\"${DEPLOY_ENV}\\"],\
                    \\"changeId\\": \\"${BUILD_ID}\\",\
                    \\"status\\": \\"SUCCESS\\",\
                    \\"deployedBy\\": \\"${BUILD_USER}\\",\
                    \\"deployTimestamp\\": \\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\\"}"
                    
                    curl "${DEPLOY_WEBHOOK_URL}" \\
                      -s \\
                      -H "Content-Type: application/json" \\
                      -d "${json_payload}"
                '''
            }
        }
        failure {
            script {
                sh '''#!/bin/bash
                    json_payload="{\
                    \\"services\\": [{\\"service\\": \\"${SERVICE_NAME}\\", \\"version\\": \\"${SERVICE_VERSION}\\"}],\
                    \\"environments\\": [\\"${DEPLOY_ENV}\\"],\
                    \\"changeId\\": \\"${BUILD_ID}\\",\
                    \\"status\\": \\"FAILURE\\",\
                    \\"deployedBy\\": \\"${BUILD_USER}\\",\
                    \\"deployTimestamp\\": \\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\\"}"
                    
                    curl "${DEPLOY_WEBHOOK_URL}" \\
                      -s \\
                      -H "Content-Type: application/json" \\
                      -d "${json_payload}"
                '''
            }
        }
    }
}
```

{% hint style="info" %}
**DEPLOY STATUS IS RECORDED AS SUCCESS**

The stock Harness Deployment template records every deploy activity as `success`. Sending a `FAILURE` status is accepted but does not create a failed-deployment record. Keep the failure webhook if you want the deploy event captured, but do not rely on the status value to distinguish failed deploys.
{% endhint %}

#### Multi-service deployments <a href="#multi-service-deployments" id="multi-service-deployments"></a>

For deployments that update multiple services:

```groovy
post {
    success {
        script {
            sh '''#!/bin/bash
                json_payload="{\
                \\"services\\": [\
                {\\"service\\": \\"frontend\\", \\"version\\": \\"${FRONTEND_VERSION}\\"},\
                {\\"service\\": \\"backend\\", \\"version\\": \\"${BACKEND_VERSION}\\"},\
                {\\"service\\": \\"worker\\", \\"version\\": \\"${WORKER_VERSION}\\"}\
                ],\
                \\"environments\\": [\\"${DEPLOY_ENV}\\"],\
                \\"changeId\\": \\"${BUILD_ID}\\",\
                \\"status\\": \\"SUCCESS\\",\
                \\"deployedBy\\": \\"${BUILD_USER}\\",\
                \\"deployTimestamp\\": \\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\\"}"
                
                curl "${DEPLOY_WEBHOOK_URL}" \\
                  -s \\
                  -H "Content-Type: application/json" \\
                  -d "${json_payload}"
            '''
        }
    }
}
```

***

### Store webhook URLs as credentials <a href="#store-webhook-urls-as-credentials" id="store-webhook-urls-as-credentials"></a>

Store webhook URLs securely in Jenkins:

1. Navigate to **Manage Jenkins**, then select **Credentials**
2. Select the appropriate domain (usually `(global)`)
3. Click **Add Credentials**
4. Configure the following:
   * **Kind:** Secret text
   * **Secret:** Paste your build or deploy webhook URL
   * **ID:** `aisre-build-webhook-url` or `aisre-deploy-webhook-url`
   * **Description:** "AI SRE Build Webhook URL" or "AI SRE Deploy Webhook URL"
5. Click **OK**

Reference credentials in Jenkinsfile:

```groovy
environment {
    BUILD_WEBHOOK_URL = credentials('aisre-build-webhook-url')
    DEPLOY_WEBHOOK_URL = credentials('aisre-deploy-webhook-url')
}
```

***

### Critical mapping requirements <a href="#critical-mapping-requirements" id="critical-mapping-requirements"></a>

The Deploy Change Investigator requires exact matches between build and deploy data:

| Build webhook field                     | Deploy webhook field | Must match |
| --------------------------------------- | -------------------- | ---------- |
| `service.name`                          | `services[].service` | ✅ Yes      |
| `artifact.version` or `service.version` | `services[].version` | ✅ Yes      |

{% hint style="danger" %}
**COMMON MISTAKES**

* **Version mismatch:** Build sends `1.2.3`, deploy sends `v1.2.3`, so there is no match.
* **Service name mismatch:** Build sends `myapp`, deploy sends `my-app`, so there is no match.
* **Using different identifiers:** Ensure the BUILD\_NUMBER or version tag is consistent across both webhooks.
  {% endhint %}

***

### Testing webhooks <a href="#testing-webhooks" id="testing-webhooks"></a>

#### Test build webhook <a href="#test-build-webhook" id="test-build-webhook"></a>

Trigger a build and confirm the webhook reaches AI SRE:

1. Trigger a Jenkins build that includes the webhook script
2. Check the Jenkins console output for curl command execution
3. Navigate to **AI SRE**, then select **Integrations**
4. Click the **More** icon on the BUILD integration
5. Select **Debug** to view received webhook events

#### Test deploy webhook <a href="#test-deploy-webhook" id="test-deploy-webhook"></a>

Trigger a deployment and confirm the webhook reaches AI SRE:

1. Trigger a deployment pipeline
2. Verify the curl command runs in the console output
3. Navigate to **AI SRE**, select **Integrations**, then select **Debug** on the DEPLOY integration

#### Verify the connection <a href="#verify-the-connection" id="verify-the-connection"></a>

After sending both build and deploy webhooks:

1. Navigate to **AI SRE**, then select **Change Management**
2. You should see deployment records linked to builds
3. Click into a deployment to see the following:
   * Artifact versions
   * Commit SHAs
   * Linked PRs

***

### Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

<details>

<summary>Jenkins build webhook not received in AI SRE</summary>

Confirm the curl command runs in the Jenkins console log, verify the webhook URL credential is correct, ensure Jenkins agents allow outbound HTTPS, and check the JSON payload for syntax errors using the -v flag on curl.

</details>

<details>

<summary>Jenkins deploy webhook received but changes not showing in AI SRE</summary>

Ensure services\[].service in the deploy webhook exactly matches service.name in the build webhook, and services\[].version exactly matches artifact.version or service.version. Confirm both webhooks were sent by checking the Debug view for both integrations.

</details>

<details>

<summary>Getting the BUILD_USER variable in Jenkins for AI SRE deploy webhooks</summary>

Jenkins does not provide BUILD\_USER by default. Install the Build User Vars Plugin to expose BUILD\_USER, BUILD\_USER\_EMAIL, and BUILD\_USER\_ID, or use ${BUILD\_CAUSE} or hardcode a service account name.

</details>

***

### Example complete Jenkins pipeline <a href="#example-complete-jenkins-pipeline" id="example-complete-jenkins-pipeline"></a>

The following is a complete example with both build and deploy webhooks:

```groovy
pipeline {
    agent any
    
    environment {
        BUILD_WEBHOOK_URL = credentials('aisre-build-webhook-url')
        DEPLOY_WEBHOOK_URL = credentials('aisre-deploy-webhook-url')
        ARTIFACT_REGISTRY = 'docker.example.com'
        SERVICE_NAME = 'myapp'
    }
    
    stages {
        stage('Build') {
            steps {
                sh 'docker build -t ${ARTIFACT_REGISTRY}/${SERVICE_NAME}:${BUILD_NUMBER} .'
                sh 'docker push ${ARTIFACT_REGISTRY}/${SERVICE_NAME}:${BUILD_NUMBER}'
            }
            post {
                success {
                    sh '''#!/bin/bash
                        json_payload="{\
                        \\"artifact\\": {\\"name\\": \\"${ARTIFACT_REGISTRY}/${SERVICE_NAME}\\", \\"version\\": \\"${BUILD_NUMBER}\\"},\
                        \\"source\\": {\
                        \\"commitSha\\": \\"${GIT_COMMIT}\\",\
                        \\"kind\\": \\"branch\\",\
                        \\"value\\": \\"${GIT_BRANCH}\\",\
                        \\"repository_url\\": \\"${GIT_URL}\\"},\
                        \\"service\\": {\\"name\\": \\"${SERVICE_NAME}\\", \\"version\\": \\"${BUILD_NUMBER}\\"},\
                        \\"buildId\\": \\"${BUILD_ID}\\"}"
                        
                        curl "${BUILD_WEBHOOK_URL}" -s -H "Content-Type: application/json" -d "${json_payload}"
                    '''
                }
            }
        }
        
        stage('Deploy to Production') {
            when {
                branch 'main'
            }
            steps {
                sh 'kubectl set image deployment/${SERVICE_NAME} ${SERVICE_NAME}=${ARTIFACT_REGISTRY}/${SERVICE_NAME}:${BUILD_NUMBER}'
            }
            post {
                always {
                    script {
                        def status = currentBuild.currentResult == 'SUCCESS' ? 'SUCCESS' : 'FAILURE'
                        sh """#!/bin/bash
                            json_payload="{\
                            \\"services\\": [{\\"service\\": \\"${SERVICE_NAME}\\", \\"version\\": \\"${BUILD_NUMBER}\\"}],\
                            \\"environments\\": [\\"production\\"],\
                            \\"changeId\\": \\"${BUILD_ID}\\",\
                            \\"status\\": \\"${status}\\",\
                            \\"deployedBy\\": \\"jenkins\\",\
                            \\"deployTimestamp\\": \\"\$(date -u +%Y-%m-%dT%H:%M:%SZ)\\"}"
                            
                            curl "${DEPLOY_WEBHOOK_URL}" -s -H "Content-Type: application/json" -d "\${json_payload}"
                        """
                    }
                }
            }
        }
    }
}
```

***

### Next steps <a href="#next-steps" id="next-steps"></a>

* Go to [Deploy Change Investigator](/ai-sre/ai-sre-for-administrators/set-up-change-management/deploy-change-investigator.md) to complete the setup.
* Go to [AI Agent RCA](/ai-sre/ai-sre-for-incident-responders/use-ai-agents/rca-change-agent.md) to understand how change detection works during incidents.
* Go to [Configure GitHub Actions](/ai-sre/ai-sre-for-administrators/set-up-change-management/sources/github-actions.md) to set up webhooks in GitHub Actions workflows.
