How to create a merge request at the end of a successful pipeline in Gitlab?

Another approach it to:

  • not use GitLab API
  • get the patch represented by the code checked out by the pipeline
  • use an email(!), since GitLab 11.5 (Nov. 2018)

Open a merge request with a patch via email

GitLab has supported opening a merge request via email for a long time, but before sending the email the branch must already exist on the server. Now you can open a merge request with only an email by attaching one or more patch files (.patch).

Patch files are the standard for sharing and transmitting changes between systems. In future releases of GitLab we will build on this foundation for distributed merge requests, which will allow merge requests between GitLab instances, and other Git hosting tools too.

See documentation and issue.


Short Answer: Sure - anything's possible. GitLab has a great API (including creating an MR). But I think going that route is bad form. You should utilize GitLab as it's designed. You're starting your Merge Request too late. Start it before you begin any work and your Merge Request will remain open the entire duration of your branch.

Long Answer: This is the ideal GitLab workflow:

  1. Someone creates an ISSUE against a repository. Maybe a feature request, maybe an actual problem, whatever - someone wants something changed, so it's an 'issue'
  2. Developer opens the issue and clicks CREATE MERGE REQUEST
    • This generates an Merge Request (MR), a matching branch, and ties it back to the issue
  3. Developer works the branch, pushing changes as they go
  4. Developer gets a passing pipeline and hits "Resolve WIP" on that merge request page when they're ready for the customer to preview the work and/or another developer to code review.
  5. From here, have that reviewer either click MERGE when done reviewing or even better, turn on APPROVALS in repository settings and set the people or groups of people you want reviews from.
  6. Next to the merge button, be sure to delete the source branch (for sanity), and merged code will automatically close the issue - and link all 3 elements together.

This is fundamentally backward from the way GitHub works (which I came from) where you don't have to tell people what you're working on.

  • Pull Requests on GitHub are created when the work is finished and you want to merge into master.
  • Merge Requests on GitLab are created when the work is beginning and you want to tell the world you're about to embark on working on a feature. This allows for people to do a quick shutdown if it's not needed or prevents multiple devs from duplicating effort.

EDIT: It sounds like you're interested in leveraging the API. There's a python package called 'python-gitlab' actually that works decently http://python-gitlab.readthedocs.io/en/stable/gl_objects/mrs.html

import gitlab
import os

origin = "https://gitlab.example.com"
# Private token is set as an env var
gl = gitlab.Gitlab(origin, private_token, api_version='4')
gl.auth()

def create_merge_request(origin, private_token):
    mr = project.mergerequests.create({'source_branch': 'cool_feature',
                               'target_branch': 'master',
                               'title': 'merge cool feature',
                               'labels': ['label1', 'label2']})
    mr.assignee_id = gl.users.get(2).id # Assign it to coworker

def lookup_last_pipeline(origin, private_token):
    current_pipeline_id = os.environ['CI_PIPELINE_ID']
    pipelines = gl.projects.get(os.environ['CI_PROJECT_ID']).pipelines.list()
    for pipeline in pipelines:
        if pipeline.status == 'success' and pipeline.id == current_pipeline_id:
            create_merge_request()

This is of course an example, you'll have to adapt it to your precise needs.


In order to achieve my simple needs, I simply added a final stage to my pipeline which essentially executes a bash script adapted from this post.

EDIT: As requested by @Yuva

# Create a pull request on pipeline success
create_merge_request:
  stage: createMR
  tags:
    - autoMR
  script:
    - 'echo Merge request opened by $GITLAB_USER_NAME '
    - ~/commit.sh

and in commit.sh

#!/bin/bash
# This script was adapted from:
# https://about.gitlab.com/2017/09/05/how-to-automatically-create-a-new-mr-on-gitlab-with-gitlab-ci/

# TODO determine URL from git repository URL
[[ $HOST =~ ^https?://[^/]+ ]] && HOST="${BASH_REMATCH[0]}/api/v4/projects/"

# The branch which we wish to merge into
TARGET_BRANCH=develop;

# The user's token name so that we can open the merge request as the user
TOKEN_NAME=`echo ${GITLAB_USER_LOGIN}_COMMIT_TOKEN | tr "[a-z]" "[A-Z]"`

# See: http://www.tldp.org/LDP/abs/html/parameter-substitution.html search ${!varprefix*}, ${!varprefix@} section
PRIVATE_TOKEN=`echo ${!TOKEN_NAME}`

# The description of our new MR, we want to remove the branch after the MR has
# been closed
BODY="{
\"project_id\": ${CI_PROJECT_ID},
\"source_branch\": \"${CI_COMMIT_REF_NAME}\",
\"target_branch\": \"${TARGET_BRANCH}\",
\"remove_source_branch\": false,
\"force_remove_source_branch\": false,
\"allow_collaboration\": true,
\"subscribed\" : true,
\"title\": \"${GITLAB_USER_NAME} merge request for: ${CI_COMMIT_REF_SLUG}\"
}";

# Require a list of all the merge request and take a look if there is already
# one with the same source branch
 LISTMR=`curl --silent "${HOST}${CI_PROJECT_ID}/merge_requests?state=opened" --header "PRIVATE-TOKEN:${PRIVATE_TOKEN}"`;
 COUNTBRANCHES=`echo ${LISTMR} | grep -o "\"source_branch\":\"${CI_COMMIT_REF_NAME}\"" | wc -l`;

# No MR found, let's create a new one
if [ ${COUNTBRANCHES} -eq "0" ]; then
    curl -X POST "${HOST}${CI_PROJECT_ID}/merge_requests" \
    --header "PRIVATE-TOKEN:${PRIVATE_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "${BODY}";

    echo "Opened a new merge request: WIP: ${CI_COMMIT_REF_SLUG} for user ${GITLAB_USER_LOGIN}";
    exit;
fi
    echo "No new merge request opened"