DEV Community

Cover image for Solved: GitLab CI/CD: Trigger Jenkins Jobs via Webhook on Merge Request
Darian Vance
Darian Vance

Posted on • Originally published at wp.me

Solved: GitLab CI/CD: Trigger Jenkins Jobs via Webhook on Merge Request

🚀 Executive Summary

TL;DR: This guide addresses the problem of manual Jenkins job triggering from GitLab Merge Requests, which creates bottlenecks and errors in CI/CD pipelines. It provides a solution to automate Jenkins job execution via a webhook from GitLab CI/CD whenever a merge request is opened or updated, ensuring immediate feedback on code changes.

🎯 Key Takeaways

  • Jenkins jobs must be configured to ‘Trigger builds remotely’ with a unique ‘Authentication Token’ and can accept ‘String Parameter’ types for GitLab MR details like MR_ID, COMMIT_SHA, and SOURCE_BRANCH.
  • Sensitive Jenkins credentials, such as JENKINS_JOB_AUTH_TOKEN and JENKINS_URL, should be securely stored as masked and protected GitLab CI/CD variables.
  • A GitLab CI/CD job in .gitlab-ci.yml uses ‘curl -X POST’ to send a request to the Jenkins ‘buildWithParameters’ endpoint, including the authentication token and GitLab predefined variables, with ‘rules’ to ensure execution only on merge request pipelines.

GitLab CI/CD: Trigger Jenkins Jobs via Webhook on Merge Request

As DevOps engineers, we constantly seek to automate, streamline, and integrate our toolchains for maximum efficiency. One common scenario involves leveraging GitLab for source code management and merge request workflows, while relying on Jenkins for its powerful build, test, and deployment capabilities.

The problem? Often, a developer creates a merge request in GitLab, and someone manually has to log into Jenkins to trigger a specific integration or deployment job. This manual intervention is not only tedious and error-prone but also creates a bottleneck in the feedback loop, slowing down development cycles. This siloed approach reduces the benefits of an integrated CI/CD pipeline.

At TechResolve, we believe in seamless automation. This tutorial will guide you through integrating GitLab CI/CD with Jenkins, allowing your Jenkins jobs to be automatically triggered via a webhook whenever a merge request is opened or updated in GitLab. This integration ensures that your critical Jenkins pipelines run precisely when needed, providing immediate feedback on code changes and accelerating your delivery process.

Prerequisites

Before we dive into the integration, ensure you have the following in place:

  • An active GitLab instance (SaaS or self-hosted) with a project where you have Maintainer or Owner permissions.
  • An active Jenkins instance that is network-accessible from your GitLab CI/CD runners.
  • A pre-configured Jenkins job that you wish to trigger.
  • Basic understanding of GitLab CI/CD .gitlab-ci.yml configuration.
  • Basic understanding of Jenkins job configuration.
  • Necessary administrative access to both GitLab and Jenkins to configure variables and jobs.

Step-by-Step Guide

Step 1: Configure Your Jenkins Job for Remote Triggering

The first step is to prepare your Jenkins job to accept remote triggers. This involves enabling a specific option within the job configuration and defining a unique authentication token.

  1. Log in to your Jenkins instance.
  2. Navigate to the Jenkins job you want to trigger.
  3. Click on “Configure” in the left-hand menu.
  4. In the “Build Triggers” section, check the box labeled “Trigger builds remotely (e.g., from scripts)”.
  5. A new field, “Authentication Token”, will appear. Enter a strong, unique token here (e.g., a UUID or a complex alphanumeric string). Remember this token; we will use it in GitLab. For example, superSecretJenkinsToken123.
  6. If your Jenkins job needs parameters from the GitLab Merge Request (e.g., MR ID, commit SHA, source branch), go to the “General” section and check “This project is parameterized”. Add parameters like MR_ID, COMMIT_SHA, and SOURCE_BRANCH as “String Parameter” types.
  7. Save your Jenkins job configuration.

Jenkins will now be ready to receive POST requests with the specified token to trigger the job.

Step 2: Securely Store Jenkins Credentials in GitLab CI/CD Variables

Hardcoding sensitive information like API tokens directly into your .gitlab-ci.yml is a security anti-pattern. GitLab CI/CD provides a secure way to store such variables.

  1. In your GitLab project, navigate to “Settings” > “CI/CD”.
  2. Expand the “Variables” section.
  3. Click “Add variable”.
  4. For “Key”, enter JENKINS_JOB_AUTH_TOKEN.
  5. For “Value”, paste the authentication token you defined in your Jenkins job (e.g., superSecretJenkinsToken123).
  6. Ensure “Protect variable” is checked if this token should only be available in protected branches/tags.
  7. Ensure “Mask variable” is checked. This prevents the token from being exposed in job logs.
  8. Click “Add variable”.
  9. Repeat this process for your Jenkins URL, if it’s not publicly known or if you prefer to manage it as a variable. Use a key like JENKINS_URL and its value (e.g., http://your-jenkins-instance.com). This variable does not need to be masked or protected unless it contains sensitive information beyond the URL itself.

These variables will now be securely available to your GitLab CI/CD pipelines.

Step 3: Develop the GitLab CI/CD Pipeline to Trigger Jenkins

Now, let’s create or update your .gitlab-ci.yml file to include a job that triggers Jenkins specifically on merge request events.

Add a new stage and job to your .gitlab-ci.yml:

<!--
  This is a simplified example.
  Replace 'your-jenkins-instance.com', 'your-integration-job', and the
  JENKINS_JOB_AUTH_TOKEN with your actual values.
-->
stages:
  - build
  - test
  - trigger_jenkins # Add a new stage for triggering Jenkins

trigger_jenkins_on_mr:
  stage: trigger_jenkins
  image: curlimages/curl:latest # Use a lightweight image that includes curl
  script:
    - echo "GitLab CI detected a merge request (!${CI_MERGE_REQUEST_IID}). Triggering Jenkins job..."
    - >
      curl -X POST
      --fail
      --show-error
      --silent
      "${JENKINS_URL}/job/${JENKINS_JOB_NAME}/buildWithParameters?token=${JENKINS_JOB_AUTH_TOKEN}&MR_ID=${CI_MERGE_REQUEST_IID}&COMMIT_SHA=${CI_COMMIT_SHA}&SOURCE_BRANCH=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}"
  variables:
    # Ensure these match your Jenkins URL and job name
    JENKINS_URL: "http://your-jenkins-instance.com"
    JENKINS_JOB_NAME: "your-integration-job"
  rules:
    # This rule ensures the job only runs for merge request pipelines
    - if: '$CI_MERGE_REQUEST_IID'
      when: on_success # Only trigger if previous stages (build, test) pass
Enter fullscreen mode Exit fullscreen mode

Explanation of the Code:

  • stages: – trigger_jenkins: We define a new stage in our pipeline. You can place this stage anywhere appropriate in your workflow, typically after build and test stages.
  • trigger_jenkins_on_mr: This is the name of our GitLab CI/CD job.
  • image: curlimages/curl:latest: We use a Docker image that comes pre-installed with curl, which is essential for making HTTP requests.
  • script:: This section contains the commands to execute.
    • The echo command provides clarity in the pipeline logs.
    • The curl -X POST … command is the core of the integration.
    • -X POST: Specifies that this is a POST request.
    • –fail: Makes curl exit with an error code if the HTTP request fails (e.g., 4xx or 5xx status).
    • –show-error: Displays an error message if curl fails.
    • –silent: Suppresses progress meter and error messages (unless –show-error is also used).
    • “${JENKINS_URL}/job/${JENKINS_JOB_NAME}/buildWithParameters?token=${JENKINS_JOB_AUTH_TOKEN}&MR_ID=${CI_MERGE_REQUEST_IID}&COMMIT_SHA=${CI_COMMIT_SHA}&SOURCE_BRANCH=${CI_MERGE_REQUEST_SOURCE_NAME}”: This is the Jenkins API endpoint.
      • JENKINS_URL and JENKINS_JOB_NAME are derived from our job-level variables.
      • token=${JENKINS_JOB_AUTH_TOKEN}: This passes the authentication token required by Jenkins for remote triggering.
      • MR_ID=${CI_MERGE_REQUEST_IID}, COMMIT_SHA=${CI_COMMIT_SHA}, SOURCE_BRANCH=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}: These are examples of GitLab predefined CI/CD variables passed as parameters to the Jenkins job. Ensure your Jenkins job is configured to accept these parameters (as mentioned in Step 1).
  • rules: – if: ‘$CI_MERGE_REQUEST_IID’ when: on_success: This crucial rule ensures that this job only executes when the pipeline is associated with a merge request (identified by the presence of CI_MERGE_REQUEST_IID) and only if all preceding jobs in the pipeline (in earlier stages) have succeeded.

Commit this .gitlab-ci.yml file to your repository.

Step 4: Test the Integration

With everything configured, it’s time to test your automated trigger:

  1. Create a new branch in your GitLab project.
  2. Make a small change to a file (e.g., add a comment) and commit it to this new branch.
  3. Push the branch to GitLab.
  4. Create a new merge request from this branch to your default branch (e.g., main or master).
  5. Observe the pipeline running in GitLab for your merge request. After the build and test stages complete successfully, the trigger_jenkins_on_mr job should execute.
  6. Immediately check your Jenkins instance. You should see your configured job being triggered, with a new build appearing in its build history. If you passed parameters, check the build parameters in Jenkins to ensure they were received correctly.

Common Pitfalls

Even with careful configuration, integrations can sometimes be tricky. Here are a couple of common issues you might encounter:

  • Network Connectivity Issues: The GitLab CI runner needs to be able to reach your Jenkins instance. If Jenkins is behind a firewall or in a private network, ensure that the GitLab runner’s IP addresses or network range are whitelisted. You can debug this by adding a simple ping jenkins-host.com or curl –head http://your-jenkins-instance.com command to a temporary GitLab CI job to confirm network access.
  • Authentication Token Mismatch or Permissions: If the Jenkins job isn’t triggering, double-check that the JENKINS_JOB_AUTH_TOKEN in your GitLab CI/CD variables exactly matches the “Authentication Token” in your Jenkins job configuration. Also, ensure the Jenkins job is configured to allow remote triggers. In some Jenkins setups, you might need a dedicated Jenkins user’s API token (and use –user “username:apitoken” with curl) if the simple remote build trigger isn’t sufficient due to global security settings.
  • Incorrect Jenkins URL or Job Name: A common typo can lead to a 404 or connection refused error. Verify the JENKINS_URL and JENKINS_JOB_NAME variables carefully. The job name in the URL is typically the “Full project name” shown in the Jenkins job’s configuration page, often without spaces (or with URL-encoded spaces like %20, though it’s best to avoid spaces).

Conclusion

By following these steps, you’ve successfully integrated GitLab CI/CD with Jenkins, enabling automated job triggering upon merge request activity. This crucial automation eliminates manual steps, reduces human error, and dramatically speeds up the feedback loop for developers. Your Jenkins pipelines can now instantly react to code changes, running necessary checks, builds, or deployments much earlier in the development process.

What’s next? Consider enhancing this integration further:

  • Configure your Jenkins job to fully utilize the MR_ID, COMMIT_SHA, and SOURCE_BRANCH parameters for more targeted builds or reports.
  • Explore bidirectional communication: Have your Jenkins job update the GitLab Merge Request status (e.g., “Build successful” or “Deployment failed”) using the GitLab API to provide a comprehensive view directly within GitLab.
  • For more complex interactions with Jenkins, explore using dedicated Jenkins API client libraries (e.g., Python’s python-jenkins) if simple curl commands become insufficient.

Embrace the power of integrated automation to build faster, more reliably, and with greater confidence!


Darian Vance

👉 Read the original article on TechResolve.blog


☕ Support my work

If this article helped you, you can buy me a coffee:

👉 https://buymeacoffee.com/darianvance

Top comments (0)