原文請猛戳:
http://galoisplusplus.coding.me/blog/2016/03/12/svn-precommit-hook/git
提及折騰svn hook這件事仍是在去年年末。我廠向來木有Code Review等Quality Assurance流程,全賴老司機們各類強力輸出。而當時咱們項目的很多老司機要麼去了其餘部門要麼離職了,新來的小鮮肉碼農們彷佛對Version Control一無所知。別的不說,單是commit不寫comment,便讓你們頭疼不已,每次在merge時都得額外花很多時間來搞清楚commit的具體內容。雖然我自從投奔git
陣營後基本都是用git svn
,對svn
生疏已久,但以爲加個svn
提交限制應非難事,因此便額外花了點時間寫了個pre-commit hook,對commit的comment中的非空白字符作計數,少於必定字數的不讓提交。萬萬沒想到,當時讓SA大大部署上svn
服務器後,就有人commit了一個「再試一下」orz...當時個人心裏是崩潰的...在推上圍脖上吐槽後不久,衆位大神各類支招,例如巨硬的泉哥說再搞個語義分析器666...不過最受用的仍是根爺所提到的用cpplint
檢查代碼是否符合編碼規範、是否可以編譯經過。剛好那段時間小鮮肉們提交了一些帶有語法錯誤的lua代碼,偶們又木有review制度,結果不寫程序的策劃大大們svn up
下來後——「什麼鬼?腫麼不能運行了?!好拙計啊!AAA,快來看bug啊!BBB,SOS!」——致使別人不得不停下手頭的活、額外花時間排查。因此我便在pre-commit hook裏用luac
檢查語法錯誤的代碼,把這種坑隊友的事扼殺在搖籃裏。雖然不及cpplint
那麼強大,但也基本夠用了。最近一次改這個腳本是由於前段時間有個小鮮肉作了一張4096x4096的圖集,而cocos2d-x文檔裏寫得清清楚楚,大多數手機所支持的最大紋理尺寸其實只有2048x2048...臥槽,幹得漂亮啊,一上線就形成了很多crash...木有review制度好可啪,在發現這個問題以前其餘人一直絕不知情...因此我仍是乾脆在svn hook裏再加個限制吧~github
好了,不碎碎唸了,這個gist即是我折騰的svn hook,主要作了這麼幾項功能:apache
commit message非空白長度檢查服務器
lua語法檢查less
禁止添加文件名帶空格的文件運維
禁止被配在PROHIBITED_FILES
的文件被修改ide
確保圖片尺寸小於2048x2048svn
#!/bin/sh # PRE-COMMIT HOOK # # The pre-commit hook is invoked before a Subversion txn is # committed. Subversion runs this hook by invoking a program # (script, executable, binary, etc.) named 'pre-commit' (for which # this file is a template), with the following ordered arguments: # # [1] REPOS-PATH (the path to this repository) # [2] TXN-NAME (the name of the txn about to be committed) # # [STDIN] LOCK-TOKENS ** the lock tokens are passed via STDIN. # # If STDIN contains the line "LOCK-TOKENS:\n" (the "\n" denotes a # single newline), the lines following it are the lock tokens for # this commit. The end of the list is marked by a line containing # only a newline character. # # Each lock token line consists of a URI-escaped path, followed # by the separator character '|', followed by the lock token string, # followed by a newline. # # The default working directory for the invocation is undefined, so # the program should set one explicitly if it cares. # # If the hook program exits with success, the txn is committed; but # if it exits with failure (non-zero), the txn is aborted, no commit # takes place, and STDERR is returned to the client. The hook # program can use the 'svnlook' utility to help it examine the txn. # # On a Unix system, the normal procedure is to have 'pre-commit' # invoke other programs to do the real work, though it may do the # work itself too. # # *** NOTE: THE HOOK PROGRAM MUST NOT MODIFY THE TXN, EXCEPT *** # *** FOR REVISION PROPERTIES (like svn:log or svn:author). *** # # This is why we recommend using the read-only 'svnlook' utility. # In the future, Subversion may enforce the rule that pre-commit # hooks should not modify the versioned data in txns, or else come # up with a mechanism to make it safe to do so (by informing the # committing client of the changes). However, right now neither # mechanism is implemented, so hook writers just have to be careful. # # Note that 'pre-commit' must be executable by the user(s) who will # invoke it (typically the user httpd runs as), and that user must # have filesystem-level permission to access the repository. # # On a Windows system, you should name the hook program # 'pre-commit.bat' or 'pre-commit.exe', # but the basic idea is the same. # # The hook program typically does not inherit the environment of # its parent process. For example, a common problem is for the # PATH environment variable to not be set to its usual value, so # that subprograms fail to launch unless invoked via absolute path. # If you're having unexpected problems with a hook program, the # culprit may be unusual (or missing) environment variables. # # Here is an example hook script, for a Unix /bin/sh interpreter. # For more examples and pre-written hooks, see those in # the Subversion repository at # http://svn.apache.org/repos/asf/subversion/trunk/tools/hook-scripts/ and # http://svn.apache.org/repos/asf/subversion/trunk/contrib/hook-scripts/ LOG="/tmp/svn.log" touch ${LOG} REPOS="$1" TXN="$2" echo "REPOS: $REPOS" > ${LOG} echo "TXN: $TXN" >> ${LOG} SVNLOOK="" # lua compiler LUAC="" # lua file extension LUA_EXT="lua" # png file extension PNG_EXT="png" MSG_MIN_CHAR_NUM=3 MAX_PNG_SIZE=2048 PROHIBITED_FILES=( ) TMP_DIR="/tmp/svn" if [[ -d ${TMP_DIR} ]]; then rm -r ${TMP_DIR} fi mkdir -p ${TMP_DIR} function check_lua_syntax { local lua_file=$1 echo `${LUAC} ${lua_file} 2>&1` } function create_file { local file_name=$1 # Create tmp file and copy content tmp_file="${TMP_DIR}/${file_name}" mkdir -p "$(dirname "${tmp_file}")" && touch "${tmp_file}" ${SVNLOOK} cat -t "${TXN}" "${REPOS}" "${file_name}" > ${tmp_file} } # Make sure that the log message contains some text. commit_msg=`$SVNLOOK log -t "$TXN" "$REPOS" | sed 's/[[:space:]]//g'` echo ${commit_msg} >> ${LOG} if [[ `echo ${commit_msg} | wc -c` -lt ${MSG_MIN_CHAR_NUM} ]]; then echo "Please write a meaningful comment when committing" 1>&2 exit 1 fi changed_info_str=`${SVNLOOK} changed -t "${TXN}" "${REPOS}"` IFS=$'\n' read -rd '' -a changed_infos <<<"${changed_info_str}" lua_error_msg="" png_error_msg="" for changed_info in "${changed_infos[@]}"; do # Prevent commiting file that contains space in its filename echo ${changed_info} >> ${LOG} operation=`echo ${changed_info} | awk '{print $1}'` if [[ ${operation} = "A" ]] && [[ `echo ${changed_info} | awk '{print NF}'` -gt 2 ]]; then echo "Please do not commit file that contains space in its filename!" 1>&2 exit 1 fi file_name=`echo ${changed_info} | awk '{print $2}'` echo "operation: ${operation}, file: ${file_name}, ext: ${ext}" >> ${LOG} # Check prohibit-commit files for prohibited_file in ${PROHIBITED_FILES[@]}; do if [[ ${file_name} = ${prohibited_file} ]]; then echo "${file_name} is not allowed to be changed!" 1>&2 exit 1 fi done ext=`echo ${file_name} | awk -F"." '{print $NF}'` if [[ ${operation} = "U" ]] || [[ ${operation} = "A" ]]; then tmp_file="${TMP_DIR}/${file_name}" # Check lua syntax if [[ ${ext} = ${LUA_EXT} ]]; then echo "Check syntax of ${tmp_file}" >> ${LOG} create_file ${file_name} error_msg=`check_lua_syntax ${tmp_file}` if [[ `echo ${error_msg} | sed 's/\n//g'` != "" ]]; then lua_error_msg="${lua_error_msg}\n${error_msg}" fi fi # Check file size if [[ ${ext} = ${PNG_EXT} ]]; then create_file ${file_name} png_info=`file ${tmp_file} | sed 's/,//g'` png_width=`echo ${png_info} | awk '{print $5}' | bc` png_height=`echo ${png_info} | awk '{print $7}' | bc` if [[ ${png_width} -gt ${MAX_PNG_SIZE} ]] || [[ ${png_height} -gt ${MAX_PNG_SIZE} ]]; then png_error_msg="${png_error_msg}\n${file_name} is too large: ${png_width} x ${png_height}" fi fi fi done rm -r ${TMP_DIR} if [[ ${lua_error_msg} != "" ]] || [[ ${png_error_msg} != "" ]]; then if [[ ${lua_error_msg} != "" ]]; then echo "lua error: ${lua_error_msg}" >> ${LOG} echo "Please fix the error in your lua program:${lua_error_msg}" 1>&2 fi if [[ ${png_error_msg} != "" ]]; then echo "png error: ${png_error_msg}" >> ${LOG} echo "Please do not commit pictures which are larger than 2048 x 2048:${png_error_msg}" 1>&2 fi exit 1 fi # Check that the author of this commit has the rights to perform # the commit on the files and directories being modified. # commit-access-control.pl "$REPOS" "$TXN" commit-access-control.cfg || exit 1 # All checks passed, so allow the commit. exit 0
PS. 聰哥說做爲一位開發去搞svn hook怕被公司的其餘開發噴越權管了運維的事,我廠卻是不存在這種問題的——人少活多時間緊,啥活都得攬啊,例如我一位舍友兼同事的大神之前開發手遊但是客戶端、服務器、策劃、切圖全都一人搞定,就差本身出美術圖和特效了。最近我也在像運維同樣寫腳本自動化處理某些項目文件,發現咱們開發各類混亂啊有木有!例如路徑帶空格,個人一些awk
腳本就血崩了——我在以上的hook
腳本里也有一樣的問題,其實把列計數方式改一下,例如$7
改爲${NF-4}
,能夠避免這種問題——並且還要把帶空格的路徑用sed
替換成轉義後的字符串。不過這種狀況還算好的,還有些人用的單詞有拼寫錯誤,要是全錯了倒也罷了,腳本hold得住,問題是有的對有的錯...偶只能棄療了...this