[转]Subversion 和 Mantis 的整合
http://kheresy.wordpress.com/2007/02/06/subversion-%E5%92%8C-mantis-%E7%9A%84%E6%95%B4%E5%90%88/
- Subversion: http://subversion.tigris.org/
- Mantis: http://www.mantisbt.org/
首先,Subversion(SVN) 是一套版本控制系統,可以用來管理程式的版本;而 Mantis 則是一套 bug tracking system,是用來追蹤、管理程式的 bug 的。而把版本控制和問題追蹤整合到一起的好處,就是可以在更新程式的時候,自動把相關訊息也整合到 bug tracking system 中。
而要做到兩者的整合,主要是透過 Subversion 有個叫做「hooks」的功能。透過這個功能,可以自己寫一些 script,甚至程式,讓 Subversion 在事件觸發時,自動執行指定的動作。而事件,則分為下面九種:
- Pre-commit: Commit之前被執行
- Pre-lock: 檔案鎖定之前被執行
- Pre-revprop-change: 檔案庫被新增、修改或刪除前被執行
- Pre-unlock: 檔案解除鎖定之前被執行
- Post-commit: Commit之後被執行
- Post-lock: 檔案鎖定之後被執行
- Post-revprop-change: 檔案庫被新增、修改或刪除後被執行
- Post-unlock: 檔案解除鎖定之後被執行
詳細說明,可以參考:[SVN] Hook scripts的使用方法。
而 Heresy 是讓 script 在 post-commit 時執行。這樣做的原因,主要是因為在 Subversion 中,commit 時的資料(檔案、註解等等)的取得,似乎都得在 commit 完後,透過 svnlook 這個指令來完成。
先說明一下,Heresy 的環境是在 Linux 上,所以接下來的說明,也都是以 Linux 上的為主。而主要的修改,分成兩個部份:
- post-commit 的編寫
- mantis 的 checkin.php 的修改
post-commit
先講 post-commit 的編寫吧~方法滿簡單的,就是在 svnroot/hooks/ 的目錄下,建立一個檔名叫作「post-commit」的執行檔;這樣,SVN 就會在 commit 後,自動執行這個檔案了。
而 SVN 會給這個程式兩個參數,第一個($1)是 repository,應該算是 SVN 的位置吧~第二個($2)則是 revision,也就是版本。svnlook 這個程式,可以透過這兩個參數來取得大多數的資料。Heresy 所編寫的 post-commit 的檔案內容如下:
#!/bin/sh PHP=/usr/bin/php SCRIPTF=/.../svn2mantis.php MANTIS=/.../mantisbt/core/checkin_svn.php $PHP $SCRIPTF $1 $2 |$PHP $MANTIS其中,第二行到第四行,是在指定檔案的路徑。
- $PHP 變數,是指定 PHP 執行檔的位置。
- $SCRIPTF 是 Heresy 自己額外寫的一個 PHP script,主要是要把由 svnlook 取得的資料,做整理;同時,由於 svnlook 傳回來的中文是以字碼的形式傳回,所以在傳給 mantis 前,也要先做先處理。
- $MANTIS 則是 mantis 提供的介面,檔名應該是叫做 checkin.php。不過由於 Heresy 一直沒辦法搞懂他的參數使用方法,所以後來就以原始版本為基礎,修改了一份。不過,這檔案的內容等第二部分再提了。
而實際執行上,也就只剩一行 $PHP $SCRIPTF $1 $2 |$PHP $MANTIS 了~實際上,就是先執行 PHP svn2mantis.php repository revision,然後再把他輸出到 stdout 的結果,pipe 給 $PHP $MANTIS,也就是 php checkin_svn.php 當成他的 stdin 了。
因此,比較重要的部分,應該就是 svn2mantis.php 的內容,和他輸出的東西了!下面就是他的內容:
<? $REPOS = $argv[1]; $REV = $argv[2]; $rs = shell_exec( "svnlook info -r $REV $REPOS" ); $pat = explode( "n", $rs, 4 ); $author = $pat[0]; $comment = $pat[3]; if( $rsa = explode( "?\", $comment ) ) { $comment = ""; foreach( $rsa as $val ) { if( ereg( "(^[0-9]{3})(.*)", $val, $p ) ) $comment .= chr( $p[1] ) . $p[2]; else $comment .= $val; } } $ra = shell_exec( "svnlook changed -r $REV $REPOS" ); echo "$authorn$commentn---n<b>Modified Files:</b>n$ra" ?>這份程式需要 repository 和 revision 兩個參數,一開始是從 $rs = shell_exec( "svnlook info -r $REV $REPOS" ); 開始;PHP 會去執行 svnlook info -r $REV $REPOS,以取得 SVN 記錄中的資料,他的形式大致像下面一樣:
author 2007-02-05 09:14:58 +0800 (Mon, 05 Feb 2007) 85 issue #1 ?228?184?173?230?150?135?231?154?132?230?184?172?232?169?166第一行是修改者、第二行是時間,第三行的數字 Heresy 不知道是什麼;第四行開始,則就是在 commit 時輸入的註解部分。由於 checkin_svn.php 也有做了些修改,因此第一行必須要是修改者名稱,沒有問題(不過要注意,帳號要和 mantis 的一樣)。但是第二行的日期和第三行的未知欄位,實際上沒有必要也加到 mantis 的 bug 筆記裡;因此,Heresy 決定把他們濾掉。也就是透過 $pat = explode( "n", $rs, 4 ); 這個指令,將 $rs 根據換行符號切割成四部分;如此,第一部分就會是修改者帳號($author = $pat[0]; )、第二部分就會是時間、第三部分就是那個未知欄位、第四部分就是註解($comment = $pat[3];)。
不過,在註解的地方可以看到一些「?/###」形式的資料,其實這些都是中文字被 SVN 轉換成 UTF-8 字碼存下來的結果;如果要輸入到 mantis 中,還需要再重組,才能顯示出來。Heresy 在這裡的做法,是根據「?」來切割字串($rsa = explode( "?\", $comment ));然後再依序檢察每個字串的字首是否為三個數字,如果是,就把他透過 chr() 這個函式轉換回字元,不是的話就直接放回來。如此,就可以將這些字碼,成功的轉回為中文字了~
而在來的 $ra = shell_exec( "svnlook changed -r $REV $REPOS" ); 則是再次呼叫 svnlook 來取得有更動的檔案資料,並一起附加到 mantis 裡面。也就是最後輸出的格式:"$authorn$commentn—n<b>Modified Files:</b>n$ra"。以上面的例子來說,最後的結果會是:
author issue #1 中文的測試 --- <b>Modified Files:</b> U a.cpp而讓他 echo 出來的原因,則是因為 mantis 的 checkin.php 是由 stdin 將資料讀取進去的~所以,這份程式只需要把要給 mantis 的資料,全部用 echo 輸出到 STDOUT 就可以了。
checkin_svn.php
前面已經有提到了,由於 Heresy 搞不定 mantis 原來的 checkin.php 的參數,所以後來決定將 checkin.php 修改為 checkin_svn.php。主要修改的地方呢,就是帳號的取得方法。
首先,checkin.php 本來的帳號取得、確認方法如下:
# Check that the username is set and exists $t_username = config_get( 'source_control_account' ); if ( is_blank( $t_username ) || ( user_get_id_by_name( $t_username ) =$ echo "Invalid source control account ('$t_username').n"; exit( 1 ); }不過由於 Heresy 徹底放棄他的取得方式,因此就要把這部分都 mark 掉(前方加上「#」就可以了)。而修改後的方法,是和註解一樣,由 STDIN 來讀取。Heresy 的作法是把 STDIN 讀進來的第一行當作是帳號,也就是在原本的 while ( ( $t_line = fgets( STDIN, 1024 ) ) ) 前,加上下列程式:
# Check that the username is set and exists $t_username = trim( fgets( STDIN, 1024 ) ); if ( is_blank( $t_username ) || ( user_get_id_by_name( $t_username ) ==$ echo "Invalid source control account ('$t_username').n"; exit( 1 ); }其實呢,也就是將 $t_username = config_get( ‘source_control_account’ ); 改成$t_username = trim( fgets( STDIN, 1024 ) ); 而已;不過由於本來的程式位置有可能還沒定義 STDIN,所以 Heresy 為了保險起見,才把它拉到 while ( ( $t_line = fgets( STDIN, 1024 ) ) ) 的前面。
在完成上面共三個檔案的修改、編寫後,只要將它們放到對應的位置,應該就能正常運作了~post-commit 必須要放在 svnroot/hooks/ 下,而 svn2mantis.php 則沒有限定,不過放一起可能比較方便。checkin_svn.php 則是要放到 mantisbt 的 core 目錄中,和原來的 checkin.php 同一位置(當然,也可以直接修改 checkin.php)。
而實際使用上,在 commit 程式的時候,必須要手動輸入對應到 mantis 的 issue 編號(形式是「issue #1」);這樣,程式就會自動把這份註解附加到 mantis issue#1 的「Bug 筆記」中了~