How to Configure GitLab Webhooks to Trigger Jenkins Merge Request Builds with Parameter Mapping


4 views

When integrating GitLab merge request webhooks with Jenkins, we frequently encounter parameter naming mismatches. While GitLab sends payload with keys like id, target_branch and source_branch, Jenkins' GitLab Merge Request Builder plugin expects gitlabMergeRequestId, gitlabTargetBranch and gitlabSourceBranch.

Here are three practical approaches to bridge this parameter gap:

// Option 1: Using a proxy script (Python example)
import requests
import json
from flask import Flask, request

app = Flask(__name__)

@app.route('/gitlab-webhook', methods=['POST'])
def transform_hook():
    data = request.json
    transformed = {
        'gitlabMergeRequestId': data['id'],
        'gitlabTargetBranch': data['target_branch'],
        'gitlabSourceBranch': data['source_branch']
    }
    jenkins_url = "http://jenkins.example.com/job/your-job/buildWithParameters"
    response = requests.post(jenkins_url, data=transformed)
    return response.text

if __name__ == '__main__':
    app.run(port=5000)

For Jenkins Pipeline users, we can handle the raw webhook payload directly:

pipeline {
    agent any
    triggers {
        GenericTrigger(
            genericVariables: [
                [key: 'id', value: '$.id'],
                [key: 'target_branch', value: '$.target_branch'],
                [key: 'source_branch', value: '$.source_branch']
            ],
            causeString: 'GitLab Merge Request Trigger',
            token: 'SECRET_TOKEN',
            printContributedVariables: true,
            printPostContent: true
        )
    }
    stages {
        stage('Build MR') {
            steps {
                script {
                    // Use the parameters directly
                    echo "Building MR ${id} from ${source_branch} to ${target_branch}"
                    // Your build steps here
                }
            }
        }
    }
}

The most maintainable solution involves creating a custom parameter mapping in Jenkins:

  1. Install the Parameterized Trigger plugin
  2. Create an intermediate job that receives the raw GitLab webhook
  3. Configure parameter mapping in the downstream job trigger

When implementing webhook solutions:

  • Always validate webhook origin using GitLab's secret token
  • Consider rate limiting to prevent abuse
  • Log webhook payloads for debugging but sanitize sensitive data

When integrating GitLab merge request webhooks with Jenkins, we frequently encounter parameter naming mismatches between what GitLab sends and what Jenkins plugins expect. The GitLab webhook payload contains merge request data under keys like id, target_branch, and source_branch, while the Jenkins GitLab Merge Request Builder plugin specifically looks for gitlabMergeRequestId, gitlabTargetBranch, and gitlabSourceBranch.

Here are three practical approaches to bridge this parameter gap:

1. Using Jenkins Parameterized Build

Create a parameterized Jenkins job with these parameters:

Name: gitlabMergeRequestId
Default Value: ${id}

Name: gitlabTargetBranch 
Default Value: ${target_branch}

Name: gitlabSourceBranch
Default Value: ${source_branch}

Then configure your GitLab webhook to trigger this parameterized build.

2. Webhook Proxy Solution

Create a simple middleware script (Node.js example) to transform the payload:

const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');

const app = express();
app.use(bodyParser.json());

app.post('/gitlab-webhook', (req, res) => {
  const { id, target_branch, source_branch } = req.body.object_attributes;
  
  const jenkinsParams = new URLSearchParams();
  jenkinsParams.append('gitlabMergeRequestId', id);
  jenkinsParams.append('gitlabTargetBranch', target_branch);
  jenkinsParams.append('gitlabSourceBranch', source_branch);

  axios.post('http://jenkins/job/your-job/buildWithParameters', jenkinsParams)
    .then(() => res.sendStatus(200))
    .catch(err => res.status(500).send(err.message));
});

app.listen(3000);

3. Custom Jenkins Plugin Modification

If you need a more permanent solution, consider modifying the plugin source to accept both parameter naming conventions. The key class to modify would be the one handling parameter parsing in the GitLab Merge Request Builder plugin.

For Jenkins Pipeline jobs, you can process the raw payload directly:

properties([
  parameters([
    string(name: 'gitlabMergeRequestId', defaultValue: ''),
    string(name: 'gitlabTargetBranch', defaultValue: ''),
    string(name: 'gitlabSourceBranch', defaultValue: '')
  ])
])

node {
  stage('Process MR') {
    script {
      def payload = readJSON text: params.payload
      env.gitlabMergeRequestId = payload.object_attributes.id
      env.gitlabTargetBranch = payload.object_attributes.target_branch
      env.gitlabSourceBranch = payload.object_attributes.source_branch
    }
  }
}

For most teams, the webhook proxy solution (option 2) provides the best balance between maintainability and functionality. It keeps your Jenkins configuration clean while providing flexibility to handle future API changes from GitLab.

Remember to secure your webhook endpoint with validation tokens and consider implementing retry logic for failed builds. The GitLab API also provides additional merge request context that you might want to capture, such as the commit SHA or author information, which can be valuable for your build process.