eclipsegitlabmylyn

is there a mylyn connector for Gitlab?


I worked with bugzilla and Eclipse, and I used Mylyn to manage issues though Eclipse.

Now I use Gitlab and gitlab issues, I wonder if there is a mylyn connector for Gitlab ?

I knwow that there is this one : gitlab connector , but it is no more usable and I did not found another one.

Did someone face with the same problem and did find a solution ?


Solution

  • After a while I can share my solution, maybe it will help others.

    There is no Mylin connector for Gitlab that runs correctly. A solution could be to debug the buggy one but in fact Gitlab is not a powerfull tool to manage issues.

    I chose to use Bugzilla at least for three points :

    The first step is to define Bugzilla as the issues management tool, this is done through Gitlab UI and the documentation is here.

    For me, if an external tool is used, the best is to desactivate Gitlab issues tracking. On your project, go to Settings->General->Visibility, project features and desactivate Issues.

    Note: if Bugzilla and Gitlab are deployed on the same host, you have to accept request to localhost. On Gitlab administration, go to Settings->Network->Outbound requests, select the two options about local network.

    After that, you can comment your commits with a message containing Ref #id where id is a bug id in Bugzilla. As with Gitlab issue, the commit will contain an hyperlink to the issue but the hyperlink will open Bugzilla bug page.

    If you do not go further, you will lost a Gitlab feature : Gitlab issue references all commits related to it.

    A solution to have a similar feature with Bugzilla is to add to bug a comment with an hyperlink to commits.

    This could be achieve with a server hook, this is described here.

    Note : each time you change the gitlab.rb file, do no forget to execute gitlab-ctl reconfigure.

    The hook has to manage "standard" commit and merge commits.

    The following python code could be seen as a starting point for a such hook. It assumes that development are done on branches named feature/id nd that commits comments contains a string Ref #id. Id is a bug id.

    It could be improve:

    #!/usr/bin/env python3
    
    import sys
    import os
    import fileinput
    import glob
    import subprocess
    import requests
    
    #
    # Constants
    #
    G__GIT_CMD      =["git","rev-list","--pretty"]
    G__SEP          ="commit "
    G__NL           ='\n'
    G__AUTHOR       ='Author'
    G__AUTHOR_R     ='Author: '
    G__DATE         ='Date'
    G__DATE_R       ='Date:   '
    G__C_MSG        ='message'
    G__URL_S        ='https://<<gitlab server url>>/<<project>>/-/commit/'
    G__MERGE_S      ='Merge: '
    G__MERGE        ='Merge'
    G__URL          ='URL'
    G__BUGZ_URL     ='http://<<bugzilla url>>/rest/bug/{}/comment'
    G__HEADERS      = {'Content-type': 'application/json'}
    G__JSON         = {"Bugzilla_login":"<<bugzilla user>>","Bugzilla_password":"<<password>>","comment": "{}"}
    G__JSON_MR      = {"Bugzilla_login":"<<bugzilla user>>","Bugzilla_password":"<<password>>","comment": "Merge request {}"}
    G__COMMENT_ELEM = 'comment'
    G__MSG_REF      ="Ref #"
    G__MSG_REF_MR   ="feature/"
    G__WHITE        =" "
    G__APOS         ="'"
    
    #
    # Filters some parts of message that are empty
    #
    def filter_message_elements(message_elements):
        flag=False
        for message_element in message_elements:
            if len(message_element)!=0:
                flag=True
                
        return flag
    
    #
    # Add an element in commit dictionary.
    #
    # If this is a commit for a merge, an element is added.
    #    
    def add_commit_in_dict(commits_dict, temp_list, flag_merge):
        url = G__URL_S+temp_list[0]
    
        commits_dict[temp_list[0]]={}    
        commits_dict[temp_list[0]][G__URL]=url 
            
        if False==flag_merge:
            commits_dict[temp_list[0]][G__AUTHOR]=temp_list[1].replace(G__AUTHOR_R,'')
            commits_dict[temp_list[0]][G__DATE]=temp_list[2].replace(G__DATE_R,'')
            commits_dict[temp_list[0]][G__C_MSG]=temp_list[3] 
        else:
            commits_dict[temp_list[0]][G__MERGE]=temp_list[1]
            commits_dict[temp_list[0]][G__AUTHOR]=temp_list[2].replace(G__AUTHOR_R,'')
            commits_dict[temp_list[0]][G__DATE]=temp_list[3].replace(G__DATE_R,'')
            commits_dict[temp_list[0]][G__C_MSG]=temp_list[4]    
    
    #
    # Fill commits data
    #
    def fills_commit_data(commits_dict, fileinput_line):
        params=fileinput_line[:-1].split()
        
        try:
            # Git command to get commits list
            cmd=G__GIT_CMD+[params[1],"^"+params[0]]
            rev_message = subprocess.run(cmd,stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
            
            # loop on commits
            messages_list=rev_message.stdout.split(G__SEP)        
            for message in messages_list:
                if len(message)==0:
                    continue           
                message_elements = message.split(G__NL)  
                # filters empty message
                flag=filter_message_elements(message_elements)
                if not flag:
                    continue
                    
                # Extracts commit data and detects merge commit
                temp_list=[]
                flag_merge=False
                for message_element in message_elements: 
                    text = message_element.strip()
                    if 0!=len(text):
                        temp_list.append(text)
                        if -1!=text.find(G__MERGE):
                            flag_merge=True
                # adds the commit in commits dictionary
                add_commit_in_dict(commits_dict, temp_list, flag_merge)
              
        except Exception as inst:
            sys.exit(1)
    
    #
    # Extract the bug id from the commit message
    #
    def find_bug_id(message):
        issue_int=-1
        pos=message.find(G__MSG_REF)
    
        if pos==-1:
            sys.exit(1)
            
        issue_nb=message[pos+len(G__MSG_REF):]
        pos2=issue_nb.find(G__WHITE)
        issue_nb=issue_nb[:pos2]
        try:
            issue_int=int(issue_nb)
        except ValueError:
            sys.exit(1)
        
        return(issue_int)
    #
    # Extract the bug id from the commit message
    # in case of merge request
    #
    def find_bug_id_mr(message):
        issue_int=-1
        pos=message.find(G__MSG_REF_MR)    
    
        if pos==-1:
            sys.exit(1)
            
        issue_nb=message[pos+len(G__MSG_REF_MR):]
        pos2=issue_nb.find(G__APOS)
        issue_nb=issue_nb[:pos2]
        try:
            issue_int=int(issue_nb)
        except ValueError:
            sys.exit(1)
        
        return(issue_int)
        
    #
    # Checks if the commit list contains a merge request commit
    #    
    def is_merge_request(commits_dict):
        flag=False
        
        for key in commits_dict:
            if G__MERGE in commits_dict[key]:
                flag=True
                break
                
        return flag
    
    #
    # Add a comment to a bug
    #
    def add_comment_to_bug( commit_data):
    
        bug_id = find_bug_id(commit_data[G__C_MSG])
        
        url = G__BUGZ_URL.format(str(bug_id))
        
        G__JSON[G__COMMENT_ELEM] = G__JSON[G__COMMENT_ELEM].format(commit_data[G__URL])
        response = requests.post(url, json=G__JSON, headers=G__HEADERS)
    
    #
    # add a comment in case of merge request
    #
    def add_mr_comment_to_bug(commits_dict):
        
        commit_data=None
        for key in commits_dict:
            if G__MERGE in commits_dict[key]:
                commit_data=commits_dict[key]
                break
       
        bug_id = find_bug_id_mr(commit_data[G__C_MSG])
    
        url = G__BUGZ_URL.format(str(bug_id))    
    
        G__JSON_MR[G__COMMENT_ELEM] = G__JSON_MR[G__COMMENT_ELEM].format(commit_data[G__URL])
        response = requests.post(url, json=G__JSON_MR, headers=G__HEADERS)
       
    #
    # Main program
    #            
    def main():
    
        # dictionary containing all commits
        commits_dict={}
        
        # loop on inputs referencing data changes
        for fileinput_line in sys.stdin:
            fills_commit_data(commits_dict, fileinput_line)
        
        # find if this is merge request or not
        flag_merge_request = is_merge_request(commits_dict)
        
        if False==flag_merge_request:
            # loop on commit to add comments to bugs
            for key in commits_dict.keys():
                add_comment_to_bug(commits_dict[key])
        else:
            # in case of merge request, only the merge commit has to be added
            # others commits have been processed before
            add_mr_comment_to_bug(commits_dict) 
             
    
    if __name__ == "__main__":
        main()