2016/05/17

Gitlab merge request from terminal

This is not a fully automated command for making merge request, instead it is tiny helper command that will take you to the right place in the browser to complete your merge request with one click.


BTW, Why not to do everything with Gitlab API?
It is fully possible. Actually I was trying to do so but in the way I realized that is not what I need because in a merge request you want to set a description (writing a description in the terminal is not better than doing it in the browser), you also will want to assign somebody to review your code (searching for other gitlab users in the terminal is not easier than the browser pulldown menu), you probably want to have a milestone, and maybe other details...

If you still want to do it fully programatically I have some hints at the end of this post :p

Script

#!/usr/bin/env bash -e

# Get host, group and repository names
REMOTE_LINE=`git remote get-url --push origin`
if [[ $REMOTE_LINE == "git@"* ]]; then
    # git: git@my.gitlab.host.com:my-group/project.git
    HOST=$(expr "$REMOTE_LINE" : 'git@\(.*\):.*')
    GROUP=$(expr "$REMOTE_LINE" : 'git@.*:\(.*\)\/.*')
    PROJECT_NAME=$(expr "$REMOTE_LINE" : 'git@.*:.*\/\(.*\)\.git')
elif [[ $REMOTE_LINE == "https://"* ]]; then
    # https: https://my.gitlab.host.com/my-group/project.git
    HOST=$(expr "$REMOTE_LINE" : 'https:\/\/\([^\/]*\)\/.*')
    GROUP=$(expr "$REMOTE_LINE" : 'https:\/\/[^\/]*\/\(.*\)\/.*')
    PROJECT_NAME=$(expr "$REMOTE_LINE" : 'https:\/\/.*\/\(.*\)\.git')
else
    echo Unknown protocol from $REMOTE_LINE
    exit 1
fi

# Get current branch name
BRANCH=$(git rev-parse --abbrev-ref HEAD)

# Create new merge request from current branch to default branch
# (Add `-a /Applications/Firefox.app` to open it with a specific browser)
open https://${HOST}/${GROUP}/${PROJECT_NAME}/merge_requests/new?merge_request[source_branch]=${BRANCH}

Setup

Copy above script as git-mr and place it somewhere in the $PATH and make sure it has executable permissions using chmod
chmod +x ~/.bin/git-mr

Usage

git push origin -u feature/myfeature
git mr
Voilà!
(browsers opens and you are just one click away from completing your merge request)

If you still want to do it programatically with Gitlab API, we need a project id an authentication token to be able to call create merge request API.
POST /projects/:id/merge_requests

Get Authentication Token

We can request the user to enter his/her login and password once and store that in the keychain. Below code is how to retrieve a previously stored password from the keychain
# Get credentials
SECOUT=`security 2>&1 find-internet-password -gs ${HOST}`
LOGIN=`expr "$SECOUT" : '.*"acct"="\([^"]*\)"'`
PASSWORD=`expr "$SECOUT" : '.*password: "\([^"]*\)"'`
echo $LOGIN $PASSWORD
With such information we can call session API and get the token for the upcomming requests
#Initialize a session
SESSIONOUT=`curl -X POST "https://${HOST}/api/v3/session?login=${LOGIN}&password=${PASSWORD}"`
TOKEN=`expr "$SESSIONOUT" : '.*"private_token":"\([^"]*\)"'`
echo $TOKEN

Get Project ID

I have tried doing ${GROUP}/${PROJECT_NAME} and ${GROUP}%2F${PROJECT_NAME} without luck so I got the project by using project search API. Unfortunately gitlab search API is not very powerful yet so we need to search results and get the id of the project that exactly matches our project. Here I am using jq
PROJECT_ID=$(curl --header "PRIVATE-TOKEN: ${TOKEN}" 'https://${HOST}/api/v3/projects/?search=${PROJECT_NAME}' | jq '.[] | select( .path_with_namespace == '\"${GROUP}/${PROJECT_NAME}\"' ) | .id')
Now we are almost ready!

Call merge_request API

# Disabled code: Get tracking branch name
#BRANCH=$(git rev-parse --abbrev-ref --symbolic-full-name @{u})
#BRANCH=${TARGET_BRANCH##origin/}

# Get remote target branch
TARGET_BRANCH='develop'

curl --header "PRIVATE-TOKEN: ${TOKEN}" -X POST "https://${HOST}/api/v3/projects/${PROJECT_ID}/merge_requests" --data "source_branch=${BRANCH}" --data "target_branch=${TARGET_BRANCH}" --data "title=Implementation of my feature"
phew...

0 comments :