SW 개발

svn serser hook pre-commit 설정하기 (파이썬예제)

. . . 2022. 8. 18. 16:59
반응형
  • svn server 측의 hook 을 설정한 내용을 정리한다.
  • git 을 쓰는것이 가장좋겠으나, 만약 사정상 svn 을 쓸수밖에없는상황이 있을수있으므로 정리

svn server 설정

여러가지 svn 서버들이 있으나 그냥 가장 간단한 서버는 if.svn 이다. 간단하게 도커로 관리/설정할수있으며, web ui 를 통한 전체적인 권한관리도 가능하니 처음 설치한다면 이것으로 if.svn 으로 세팅하자.

if.svn 의 장점

  1. docker 설정지원
  2. web ui 로 svn 의 전반적인 내용 관리가능
  3. 사용자 삭제추가, 저장소 삭제추가 등등 기본적인 기능들을 webui 에서 직관적으로 설정 할 수 있다.
  4. if.svn docker 설정 : https://github.com/elleFlorio/svn-docker
  5. 국내 설정매뉴얼 : https://ggnote.kr/3

if.svn docker-compose 예제

version: '2'

services:
  web:
    image: elleflorio/svn-server
    container_name: svn-server
    volumes:
      - ./svn_volume/repo:/home/svn
      - ./svn_backup:/home/backup
      - ./svn_volume/svnadmin:/opt/svnadmin
      - ./svn_volume/subversion:/etc/subversion
    ports:
      - "9001:80"
      - "9002:3690"
    stdin_open: true
    tty: true

svn hook 관련사항

svn hook 과 관련한 잡담 (들어가기 앞서...)

svn client 쪽의 hook 은 여러 사용자가 각자 설정해야하는 번거로움등이 있어, server 측에서 hook 을 거는것이 나을것같아서 진행하였다.

정적검증이나, 코드컨벤션등에 대해서 자동화시켜야하는데.. 해당 프로그램이 서버에서 동작할지 검토단계다. 만약 각종 툴들이 리눅스 혹은 pc 기반 라이센스가 걸려있다면 아예 server / client 로 정적검증서버와 통신하여 점검 결과값을 받아올 생각이다. pre-commit 스크립트가 약간 복잡한 동작을 하게 될것같아 python 으로 제작을 하였다.

아무리 봐도... 역시 git 만한게 없긴하다. 하지만 사정상 어쩔수가 없으니 svn ti을..;;

python 설정준비

if.svn docker 는 base kernel 이 alpine linux 로 되어있어 거의 안무런 패키지들이 없다. (심지어 bash 가 아니라 busybox 기반 sh 이 되어있음. 때문에 script 실행시 #!/bin/sh 로 해야한다)

그래서 일단 도커 컨테이너 안에서 다음과 같이 python 을 설치하였다.

apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python

추후엔 dockerfile 을 직접 작성하여 elleflorio/svn-server 기반 이미지를 새로생성하자.

hook 위치

repo 를 설정할때 마다 hook 폴더가 생성된다.

repo 폴더마다 hook 이 있다

위와같이 hook 생성이 되고.. hook 폴더 안에는 다음과같이 되어있다.

post-commit.tmpl
post-lock.tmpl
post-revprop-change.tmpl
post-unlock.tmpl
pre-commit.tmpl
pre-lock.tmpl
pre-revprop-change.tmpl
pre-unlock.tmpl
start-commit.tmpl
  • 각 파일들이 .tmpl 폴더로 되어있다. .tmpl 이 되어있으면, 아무런동작이 되지 않는다.
  • 실제 동작되어야 하는 파일명이 pre-commit / post-commit 과 같이 파일명이 정확하게 맞아야 해당 파일들이 실행된다.

svn pre-commit 일반사항

  • pre-commit 동작을 위한 인터프리터는 따로 정해져있지 않다. 때문에 첫라인에 인터프리터를 작성해주자. 또한 실행권한이 있어야한다.
  • pre-commit hook 에서 인자로 오는것은 svn repo 와 해당 동작의 세션정보(txd) 가 인자로 들어온다.
  • 해당 인자로 들어온 repotxd 를 이용하여 변경사항, 파일내용 등등을 따로 획득해야하며, 이후 획득한 정보를 갖고 사용자의 입맞게 동작시켜야한다.
    • svnlook 명령어를 이용하여 각종정보들을 획득한다.
    • svnlook 명령어 말고도 repo / txd 정보 획득을 위해서 python 의 svn 모듈을 사용해도된다.
  • sterr 로 로그를 찍어야 svn client 쪽에 로그가 보인다.
  • exit() 코드값에 따라서 동작을 제어 할 수 있다.

svn pre-commit hook python 예제파일

해당 repohook 폴더내 pre-commit 파일을 만들고 다음과 같이 내용을 채우면된다.

#!/usr/bin/python

import sys
import os
import re

import subprocess

def _log_print(logs) :
    print(logs, file=sys.stderr)

def run_sub_process(cmd, redirect_stdio=True):
    if redirect_stdio == True:
        ps = subprocess.Popen('%s'%(cmd), shell=True,stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
    else:
        ps = subprocess.Popen('%s'%(cmd), shell=True,universal_newlines=True)

    out, err = ps.communicate()

    res = {}
    res['return_code']  = ps.returncode

    if out is not None :
        res['stdouts'] = out
    if err is not None :
        res['stderrs'] = err

    return res

def get_file_changed_stat(svn_repo, svn_txd) :
    cmd = '/usr/bin/svnlook changed {svn_repo} -t {svn_txd}'.format(svn_repo=svn_repo, svn_txd=svn_txd) 
    resp = run_sub_process(cmd)['stdouts']

    file_chnage_list = []
    for one_line in resp.splitlines() :
        _commit_mod = re.findall("[AUD]\ *", one_line)[0]
        _file_extention = re.findall("([^.]*$)", one_line)[0]

        change_info = {}
        change_info['commit_mod'] = _commit_mod.replace(' ', '')
        change_info['full_file_name'] = one_line.replace(_commit_mod, '')
        change_info['file_extenstion'] = _file_extention

        file_chnage_list.append(change_info)

    return file_chnage_list

def chk_svn_log(svn_repo, svn_txd) :
    cmd = '/usr/bin/svnlook log {svn_repo} -t {svn_txd}'.format(svn_repo=svn_repo, svn_txd=svn_txd) 
    resp = run_sub_process(cmd)['stdouts']
    _log_print('--- svn logs ---')
    _log_print(resp)

def chk_svn_file_contents(svn_repo, svn_txd, file_path) :
    cmd = '/usr/bin/svnlook cat {svn_repo} -t {svn_txd} \"{file_path}\"'.format(svn_repo=svn_repo, svn_txd=svn_txd, file_path=file_path) 
    resp = run_sub_process(cmd)['stdouts']
    _log_print('--- file_contents ---')
    _log_print(resp)

if __name__ == "__main__":
#    print(sys.argv, file=sys.stderr)
    svn_repo = sys.argv[1]
    svn_txd = sys.argv[2]

    # svn log check...
    chk_svn_log(svn_repo, svn_txd)

    # svn changed file list... (per session)
    chnage_file_lists = get_file_changed_stat(svn_repo, svn_txd)
    for target_file in chnage_file_lists :
        _log_print('================================================================')
        _log_print(target_file)
        chk_svn_file_contents(svn_repo, svn_txd, target_file['full_file_name'])

    # exit code : 0 success / another code is fail..
    # exit(0) # this is okay..
    exit(3) # this is not okay... 

...

반응형