'2018/05'에 해당되는 글 1건




개요


GitLab 을 위한 Custom Hook은 다음의 3 가지 중 하나로 구현된다(Community Edition 기준).


  • pre-receive: Git 서버가 클라이언트로부터 Push 요청을 받은 즉시 수행되며, 스크립트에서 non-zero 값을 return 하면 Push 요청은 reject 된다. Push 요청에 대한 값은 스크립트 내에서 stdin 스트림 값을 읽어서 사용 가능하다
  • update: pre-receive 와 유사하지만, pre-receive 는 한 번의 Push에 대해 단 한 번 수행되며, update는 각각의 Branch 마다 triggering 되는 점이 다르다. 따라서 여러 Branch에 Push 를 수행하게 되면 특정한 브랜치에 대해서만 reject 되게 처리되게 하고 싶을 떄 사용한다
  • post-receive: Push 에 대한 모든 처리가 완료된 직후에 수행된다. Push 데이터에 대해 stdin 을 참조해서 사용하면 되며,  주로 사용자에게 메일 발송이나 CI 서버로의 triggering 또는 이슈 트래킹 시스템으로 티켓을 업데이트할 때 사용한다


스크립트 pre-receive 구현 및 활용 방법


  • pre-receive-commit-msg-check.py 파일 최종 버전을 GitLab 서버의 /root/custom_hooks_src에 저장해 둔다(백업/확인용, option 사항)
  • pre-receive-commit-msg-check.py 파일 최종 버전을 /root/custom_hooks 에 pre-receive 라는 이름으로 저장하고, chmod a+x pre-receive, chown git.git pre-receive 로 설정한다
  • copy_custom_hooks.sh 스크립트의 target_path_list 에 pre-receive Hook 을 적용할 repository 정보를 등록한다
  • copy_custom_hooks.sh 파일을 적당한 위치에 저장(/root/copy_custom_hooks.sh)해 두고 실행하면 지정된 repository 의 해당 path 로 복사된다(copy_custom_hooks.sh 파일의 내용은 다음과 같다)

    #!/bin/bash
    #
    # * Copies custom_hooks directory to target repo path
    # * $GITREPO path is defined in .bash_profile
    # * Example .bash_profile file(part) for root account of GitLab server
    # *** GITREPO=/var/opt/gitlab/git-data/repositories
    # *** export GITREPO
    #
    # Caution: one item per one line for clarity
    declare -a target_path_list=(
     "Group-or-Account/project-name-1.git"
     "Group-or-Account/project-name-2.git"
     "Project-name/repository-name.git"
     ...
    )
    
    for path in "${target_path_list[@]}"; do
      echo "Copying to: $path"
      cp -arf /root/custom_hooks/ $GITREPO/"$path"/
    done
  • 본 pre-receive 스크립트의 commit 제약 조건은 다음과 같다

Commit message에 issue-123 또는 issue#123 또는 issue-#123 또는 hotfix 또는 force 가 없으면

Remote 에 Push 시에 오류 발생함(대소문자 구분 없음)


  • pre-receive 의 원본에 해당되는 pre-receive-commit-msg-check.py 스크립트의 내용은 다음고 같으며, GitHub 의 여기에 공개되어 있다

#!/usr/bin/env python
#
# Git push checker for pre-receive(Server-side)
# version: v0.9
# * All commit messages should contain messases like
# * issue-123 or ISSUE-#123 or issue#123 or hotfix or forced
# * if push contains tags(like 'git push origin --tags'), it's ok(It skips tags)
#
import sys
import re
import subprocess

#Format:
# "oldref newref branch"
# "oldref newref branch"
# ...

input_lines = sys.stdin.readlines()

#print "Content"
#print input_lines
#print "X"

# Check all commits, skiping tags
all_ok = True

for each_line in input_lines:
    if each_line:
        #print "Content: " + each_line
        (base, commit, ref) = each_line.strip().split()
        valid_commit_msg = False

        if ref[:9] == "refs/tags": # Skip tags
            all_ok = True
            continue

        new_br_push = re.match(r'[^1-9]+', base) #handles new branches being pushed
        if new_br_push:
            all_ok = True
            continue

        revs = base + "..." + commit
        proc = subprocess.Popen(['git', 'rev-list','--oneline','--first-parent', revs], stdout=subprocess.PIPE)
        lines = proc.stdout.readlines()
        if lines:
            for line in lines:
                item = str(line)
                idx = item.index(' ')
                rev = item.split()[0]
                rest = item.split()[1:]
                #tracing
                # remote: Item: 7946999, The rest: ['test', 'msg', 'fixed', 'issue-1']
                print "Debug in pre-receive ... Item: %s, Check these messages: %s" % (rev, rest)
    
                merged = ""
                for word in rest:
                    merged += word

                # Regular Expression - Ignore case and multiline option
                match_any = re.search(r'issue-[0-9]{1,12}|issue#[0-9]{1,12}|issue-#[0-9]{1,12}|hotfix|force', merged, re.I|re.MULTILINE)
                if match_any is not None:
                    valid_commit_msg = True

        #print "\n", valid_commit_msg, new_branch_push, branch_deleted, "\n"

        if valid_commit_msg:
            all_ok = True
            continue
        else:
            all_ok = False
            break

if all_ok: #or new_branch_push or branch_deleted:
    exit(0)
else:
    print "[From the GitLab master] Commit message *MUST* contain one of these pattern: issue-123 or ISSUE-#123 or issue#123 or hotfix or forced"
    exit(1)



- Barracuda -





블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들