2017-02-09 2 views
0

У нас есть процесс DevOps, где люди проверяют или обновляют с удаленного ведущего филиала, создают новую локальную рабочую ветвь от мастера и начинают работу в локальной ветке.Как настроить Gitlab-крючок для проверки нажатия git на удаленный

1) Мне нужно ввести ограничения, которые позволят людям напрямую нажимать прямо на удаленную ведущую ветку. Вместо этого люди должны вносить изменения в свои локальные ветви в одну ветку на удаленном компьютере, после чего администратор или обозреватель кода объединит ее в удаленный мастер.

2) Мне нужен крючок, который гарантирует, что в форме есть действительный билет или номер выпуска Gitlab, например, # PROJECTNAME123, прежде чем разрешить их толчок для перехода к их удаленным филиалам (до проверки кода и слияния в удаленный мастер). Кроме того, они не могут проталкиваться, если билет не существует или еще не открыт.

Я уже создал крюк pre-receive Bash, используя информацию с обоих следующих веб-сайтов, но они вызываются, но все же позволяют git push добраться до сервера, даже если я не передаю номер/номер выпуска Gitlab.

https://github.com/Praqma/git-hooks/commit/2aa087fada0b0da51724f37a902362ddd78e168f

http://blog.hgomez.net/2015/03/02/Gitlab-custom-hooks-Bash-Way.html

Ниже приведен сценарий предварительно получить и функцию Баш скрипт, который он вызывает.

предварительно не получить (нет расширения)

#!/usr/bin/env bash 
# 

source /var/opt/gitlab/git-data/repositories/Product-common/ProductCommonParent.git/custom_hooks/pre-receive-functions.sh 

# enforced custom commit message format 
while read old_revision new_revision refname ; do 
     process_revision 
done 

exit 0 

pre-receive-functions.sh

#!/usr/bin/env bash 
# 


regexp="#[0-9]\+" 

grep_msg() 
{ 
     grepped=$(echo $message | grep -i $regexp) 
} 

process_revision() 
{ 
    #revisions=$(git rev-list $old_revision..$new_revision) 
echo "In pre-receive hook. Just before retrieving the revisions" 
if [ "$old_revision" -eq 0 ]; then 
    # list everything reachable from new_revision but not any heads 
    revisions=$(git rev-list $(git for-each-ref --format='%(refname)' refs/heads/* | sed 's/^/\^/') $new_revision) 
else 
    revisions=$(git rev-list $old_revision..$new_revision) 
fi 

echo "In pre-receive hook. Just before IFS" 
    IFS='\n' read -ra array <<< "$revisions" 
    for rid in "${!array[@]}"; do 
     revision=${array[rid]} 
    message=$(git cat-file commit $revision | sed '1,/^$/d') 
     grepped=$(echo $message | grep -i "#[0-9]\+") 
    grep_msg() 
    if [ -z "$grepped" ] ; then 
       grepped_none=$(echo $message | grep -i "#none") 
       if [ -n "$grepped_none" ] ; then 
         echo "Warning, you are committing without a ticket reference" >&1 
       else 
         echo "You have not included a ticket reference" >&2 
         exit 1 
       fi 
    fi 
    done 


} 

Ниже выходной, когда я пытаюсь нажать (Я толкаю из Git Bash оболочки на Windows, 8.1 в Fedora Core 24, имеющий установленный Gitlab):

[email protected] MINGW64 ~/Documents/DevOps Re-Engineering/ProductCommonParent (ProductCommonParent002) 
$ git push 
Counting objects: 3, done. 
Delta compression using up to 8 threads. 
Compressing objects: 100% (3/3), done. 
Writing objects: 100% (3/3), 369 bytes | 0 bytes/s, done. 
Total 3 (delta 2), reused 0 (delta 0) 
remote: In pre-receive hook. Just before retrieving the revisions 
remote: In pre-receive hook. Just before IFS 
remote: 
remote: To create a merge request for ProductCommonParent002, visit: 
remote: http://localhost/Product-common/ProductCommonParent/merge_requests/new?merge_request%5Bsource_branch%5D=ProductCommonParent002 
remote: 
To http://192.168.56.101/Product-common/ProductCommonParent.git 
* [new branch]  ProductCommonParent002 -> ProductCommonParent002 

Примечание: Gitlab и его зависимости, в том числе г он установлен на той же Fedora Core 24 Linux System.

Буду признателен за быструю помощь в преодолении этого. Заранее благодарю вас за помощь.

ответ

1

1) Ограничения уже доступны по умолчанию для каждой ограниченной по умолчанию ограниченной ветви любого нового проекта или git repo. Эти ограничения распространяются на пользователей, не являющихся администраторами и не root, из Gitlab.

2) Мы внедрили правила для проверки того, что наши разработчики соответствуют нашим политикам и процессам разработки, написав приложение SpringLine Spring Spring Spring, которое называется Gitlab API. Это приложение было упаковано как файл jar.

Мы гарантировали, что разработчик должен иметь действительный номер билета в качестве части сообщения git commit, прежде чем он сможет успешно нажать удаленный экземпляр своей рабочей ветки. Этот действительный билет должен быть присвоен ему, иметь действительную веху и иметь правильную метку (либо НОВАЯ ФУНКЦИЯ, БУГ, ЗАДАЧА и т. Д.), Выбранная для того, чтобы толчок был успешным.

Мы интегрировали с git-крючками на сервере Gitlab с помощью сценария оболочки bash, который выполнил файл jar и разрешил или не смог выполнить запрос push на основе вывода из приложения java.Этот сценарий оболочки, который является адаптацией http://blog.hgomez.net/2015/03/02/Gitlab-custom-hooks-Bash-Way.html, можно найти ниже:

#!/bin/bash 
# 
# pre-receive hook for Commit Check 
# 
COMPANY_EMAIL="mycorp.org" 

readonly PROGNAME=$(basename $0) 
readonly PROGDIR=$(readlink -m $(dirname $0)) 
IS_MERGE=0 

check_single_commit() 
{ 
    COMMIT_CHECK_STATUS=1 
    echo "Repo >> $REPOSITORY_BASENAME" 

    if [[ "$COMMIT_MESSAGE" == "Merge branch"* ]]; then 
     COMMIT_CHECK_STATUS=0 
     IS_MERGE=1 
    else 
    workFlowResult=`java -jar -Dspring.config.location=/home/gitlab/gitlab_custom_hooks/application.properties /home/gitlab/gitlab_custom_hooks/gitlab-tool.jar -prercv "$COMMIT_AUTHOR" "$COMMIT_MESSAGE" "$REPOSITORY_BASENAME"` 
    echo "COMMIT_AUTHOR=$COMMIT_AUTHOR, COMMIT_MESSAGE=$COMMIT_MESSAGE, REPOSITORY_BASE=$REPOSITORY_BASENAME" 

     echo " >>>>>>>>>>>>>>>>> $workFlowResult >>>>>>>>>>>>>>>>>" >&2 
    if [[ "$workFlowResult" == *"PRE_RECEIVE_OK"* ]]; then 
     echo " >>>>>>>>>>>>>>>>> $workFlowResult >>>>>>>>>>>>>>>>>" >&2 
     COMMIT_CHECK_STATUS=0 
    fi 

    fi 
} 

check_all_commits() 
{ 
    REVISIONS=$(git rev-list $OLD_REVISION..$NEW_REVISION) 
    IFS='\n' read -ra LIST_OF_REVISIONS <<< "$REVISIONS" 
if [ $(git rev-parse --is-bare-repository) = true ] 
then 
    REPOSITORY_BASENAME=$(basename "$PWD") 
else 
    REPOSITORY_BASENAME=$(basename $(readlink -nf "$PWD"/..)) 
fi 
    echo REPOSITORY_BASENAME is $REPOSITORY_BASENAME 
    REPOSITORY_BASENAME=$(basename "$PWD") 
    REPOSITORY_BASENAME=${REPOSITORY_BASENAME%.git} 

    for rid in "${!LIST_OF_REVISIONS[@]}"; do 
    REVISION=${LIST_OF_REVISIONS[rid]} 
    COMMIT_MESSAGE=$(git cat-file commit $REVISION | sed '1,/^$/d') 
    COMMIT_AUTHOR=$(git cat-file commit $REVISION | grep committer | sed 's/^.* \([^@ ]\[email protected][^ ]\+\) \?.*$/\1/' | sed 's/<//' | sed 's/>//' | sed 's/@$COMPANY_EMAIL//') 
    check_single_commit 

    if [ "$COMMIT_CHECK_STATUS" != "0" ]; then 
     echo "Commit validation failed for commit $REVISION" >&2 
     exit 1 
    fi 

    done 
} 





# Get custom commit message format 
while read OLD_REVISION NEW_REVISION REFNAME ; do 
    check_all_commits 
done 

exit 0 

3) Хотя это и не часть вопроса, интеграции ПМД проверки на стороне сервера без использования плагинов ПМД Jenkins, требуется загрузка исполняемых загрузочных зависимостей PMD, выполнение PMD из сценария python для статического анализа исходных файлов, которые выталкиваются разработчиками на сервер git (сервер Gitlab). Сценарий python, который загружает PMD, может быть легко интегрирован в вышеупомянутый сценарий оболочки bash. Сценарий python, который является адаптацией http://bluec0re.blogspot.com.ng/2012/05/git-pre-receive-hook-with-checkstyle.html, можно найти ниже:

#!/usr/bin/env python 

import subprocess 
import sys 
import tempfile 
import shutil 
import os 
import errno 

# variables for checkstyle 
#checkstyle = '/var/opt/gitlab/git-data/repositories/product-common/ProductCommonParent.git/custom_hooks/checkstyle-7.5.1-all.jar' 
#checkstyle_config = '/var/opt/gitlab/git-data/repositories/product-common/ProductCommonParent.git/custom_hooks/sun_checks.xml' 
pmd = '/home/gitlab/gitlab_custom_hooks/pmd-bin-5.5.4/bin/run.sh' 

# implementing check_output for python < 2.7 
if not hasattr(subprocess, 'check_output'): 
    def check_output(*popenargs, **kwargs): 
     if 'stdout' in kwargs: 
      raise ValueError('stdout argument not allowed, it will be overridden.') 
     process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) 
     output, unused_err = process.communicate() 
     retcode = process.poll() 
     if retcode: 
      cmd = kwargs.get("args") 
      if cmd is None: 
       cmd = popenargs[0] 
      er = subprocess.CalledProcessError(retcode, cmd) 
      er.output = output 
      raise er 
     return output 
    subprocess.check_output = check_output 


# helper for calling executables 
def call(*args, **kwargs): 
    return subprocess.check_output(*args, **kwargs).strip() 


# helper for calling git 
def call_git(cmd, *args, **kwargs): 
    return call(['git'] + cmd, *args, **kwargs) 


# get all new commits from stdin 
def get_commits(): 
    commits = {} 
    for line in sys.stdin: 
     old, new, ref = line.strip().split(' ') 
     if old == '0000000000000000000000000000000000000000': 
      old = '4b825dc642cb6eb9a060e54bf8d69288fbee4904' 

     if ref not in commits: 
      commits[ref] = [] 
     commits[ref].append({ 
      'old': old, 
      'new': new, 
      'files': get_changed_files(old, new) 
      }) 

    return commits 


# get a list of changed files between to commits 
def get_changed_files(old, new): 
    return call_git(['diff', '--name-only', old, new]).split('\n') 


# get filemode, object type (blob,tree,commit), hash for the given file at the 
# given commit 
def get_change_type(commit, filename): 
    return call_git(['ls-tree', commit, filename]).split('\t')[0].split(' ') 


commits = get_commits() 

# use the latest file commit only 
print "Cleaning up file list..." 

files = {} 
count = 0 
for ref, data in commits.iteritems(): 
    files[ref] = {} 
    for commit in data: 
     for filename in commit['files']: 
      if not filename.lower().endswith('.java'): continue 
      files[ref][filename] = get_change_type(commit['new'], filename) 
    count += len(files[ref]) 

print "%d Files to check in %d branches" % (count, len(files)) 

# create temporary dir and save a copy of the new files 
tempdir = tempfile.mkdtemp('git_hook') 
for ref, files in files.iteritems(): 
    for filename, data in files.iteritems(): 
     dname = os.path.dirname(filename) 
     bname = os.path.basename(filename) 
     try: 
      os.makedirs(os.path.join(tempdir, dname)) 
     except OSError, exc: 
      if exc.errno == errno.EEXIST: # directory exists already 
       pass 
      else: 
       raise 

     with open(os.path.join(tempdir, dname, bname), 'w') as fp: 
      fp.write(call_git(['cat-file', data[1], data[2]])) 

try: 
    # call checkstyle and/or pmd and print output 
    # print call(['java', '-jar', checkstyle, '-c', checkstyle_config, tempdir]) 
    # print call(['java', '-jar', '/var/opt/gitlab/git-data/repositories/product-common/ProductCommonParent.git/custom_hooks/hooks-0.0.1-SNAPSHOT.jar', '-prercv', '79', 'developer-email-id', "I am now done with issue #500 #501 #502"]) 
    print call([pmd, 'pmd', '-d', tempdir, '-f', 'text', '-R', 'rulesets/java/basic.xml,rulesets/java/unusedcode.xml,rulesets/java/imports.xml,rulesets/java/strings.xml,rulesets/java/braces.xml,rulesets/java/clone.xml,rulesets/java/design.xml,rulesets/java/clone.xml,rulesets/java/finalizers.xml,rulesets/java/junit.xml,rulesets/java/migrating.xml,rulesets/java/optimizations.xml,rulesets/java/strictexception.xml,rulesets/java/sunsecure.xml,rulesets/java/typeresolution.xml']) 
    print "SUCCESS" 
except subprocess.CalledProcessError, ex: 
    print ex.output # print checkstyle and/or pmd messages 
    exit(1) 
finally: 
    # remove temporary directory 
    shutil.rmtree(tempdir)