2017-02-09 8 views
0

リモートのマスターブランチからチェックアウトや更新を行うDevOpsプロセスがあり、マスターから新しいローカル作業ブランチを作成し、ローカルブランチで作業を開始します。リモートへのgit pushを検証するためにGitlabフックを設定する方法

1)私は、人々が遠隔のマスターブランチに直接まっすぐ押し込まないように制限する必要があります。代わりに、ローカルブランチの変更をリモートの同じブランチにプッシュする必要があります。その後、管理者またはコードレビュー担当者はリモートのマスターにマージします。

2)フォームに有効なGitlabチケットまたは発行番号があることを確認するフックが必要です(たとえば、#PROJECTNAME123など)。プッシュをリモートブランチに進める前に行う必要があります(コードレビューやマージ前リモートマスター)。さらに、チケットが存在しないか、まだ開かれていない場合は、プッシュできないようにする必要があります。

私は、次のウェブサイトの両方の情報を使用してBash事前受信フックを作成しましたが、呼び出されますが、Gitlabチケット/発行番号を渡さなくてもgit pushがサーバーに到達できるようにします。

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

https://github.com/Praqma/git-hooks/commit/2aa087fada0b0da51724f37a902362ddd78e168fは、事前に受信スクリプトとそれが呼び出すbashの機能スクリプトです。私は(私はGitのバッシュからプッシュしていますプッシュしようとするとき

前受け取る(拡張子なし)

#!/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 


} 

次のように出力されますGitlabがインストールされFedora Coreの24のWindows 8.1)上のシェル:

[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とその依存関係、Gを含みます同じFedora Core 24 Linuxシステムにインストールされています。

私はこれを過ぎるのを素早く助けることができます。ご協力いただきありがとうございます。

答えて

1

1)既定では、新しいプロジェクトやgit repoのデフォルトの制限付きブランチごとに制限が既に用意されています。これらの制限は、Gitlabの非管理者および非rootユーザーに適用されます。

2)Gitlab APIを呼び出したJavaのSpringブートCommandLineRunnerアプリケーションを作成して、開発者が開発ポリシーとプロセスに準拠していることを確認するためのルールを実装しました。このアプリケーションはjarファイルとしてパッケージ化されています。

gitコミットメッセージの一部として開発者が有効なチケット番号を持っていることを確認してから、作業現場のリモートカウンターパートに正常にプッシュできるようにしました。この有効なチケットは、彼に割り当てられ、有効なマイルストーンを持ち、プッシュが成功するために選択された正しいラベル(新機能、バグ、タスクなどのいずれか)を持たなければなりません。

jitファイルを実行し、Javaアプリケーションからの出力に基づいてプッシュリクエストを許可または拒否するbashシェルスクリプトを使用して、Gitlabサーバー上のgitフックと統合しました。このシェル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)問題の一部ではないが、PMDジェンキンスプラグインを使用せずにサーバ側でPMDチェックを統合、必要PMD実行可能ファイルの起動依存関係のダウンロード、Pythonスクリプト内からのPMDの実行、開発者がgitサーバ(Gitlabサーバ)にプッシュしているソースファイルを静的に解析します。 PMDをブートストラップするpythonスクリプトは、上記のbashシェルスクリプトに簡単に統合できます。 http://bluec0re.blogspot.com.ng/2012/05/git-pre-receive-hook-with-checkstyle.htmlの順応であるpythonスクリプトは、以下にあります。

#!/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) 
関連する問題