Subversionのpre-commitフックを強化
前に”コミットに制約を設ける”と題してpre-commitのスクリプトを作成したが、不完全だったので作り直してみた。
コミットに制約を設ける(強化版)
制約内容:
- 参照用(refs)のチケット番号が指定されていて、そのチケットがRedmimeに存在すること。
- 完了用(fixes)のチケット番号が指定されていた場合は、そのチケットがRedmineに存在して、かつ、完了していないこと。
- 修正したpre-commit
#!/usr/bin/env ruby #REPOS="$1" #TXN="$2" # Make sure that the log message contains some text. #SVNLOOK=/usr/bin/svnlook #$SVNLOOK log -t "$TXN" "$REPOS" | \ # grep "[a-zA-Z0-9]" > /dev/null || exit 1 # 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 #---------------------------------- #デバッグ出力と標準エラー出力の関数 #---------------------------------- def dbg(format, *arg) f = open("/tmp/pre-commit.log", "a") printf(f, format, *arg) f.close printf(STDERR, format, *arg) end #-------------------------------- #指定チケットの進捗率を求める関数 #-------------------------------- def getTicketRatio(ticketNo) redmine = <<-`__REDMINE__` #{MYSQL} -s -u root redmine <<__SQL__ select issues.done_ratio from issues where issues.id = #{ticketNo} ; __SQL__ __REDMINE__ #数値でない場合は nil を返す if redmine.chomp.strip =~ /^[0-9]+$/ then return redmine.chomp.strip.to_i else return nil end end #引数セット REPOS = ARGV[0] TXN = ARGV[1] #外部プログラムのパスを設定 SVNLOOK = "/usr/bin/svnlook" MYSQL = "/usr/bin/mysql" #デバッグ dbg("--- %s ---\n", Time.now) dbg("REPOS=[%s], TXN=[%s]\n", REPOS, TXN) #チェック用変数初期化 refsCnt = 0 errCnt = 0 #コミットログを取得 log = `#{SVNLOOK} log -t #{TXN} #{REPOS}` log.each do |item| #ログを加工 item.chomp! #改行コードを取り除く item.strip! #前後の空白を取り除く item.downcase! #小文字に変換 item.gsub!("references", "refs") #参照用キーワードを統一 item.gsub!("IssueID", "refs") #参照用キーワードを統一 item.gsub!("closes", "fixes") #修正用キーワードを統一 #参照用チケットをチェック refs = item.scan(/refs[ ]*[#|0-9| |,]+/) refs.each do |ref| tickets = ref.scan(/#[0-9]+/) tickets.each do |ticket| #進捗率が求めれない場合はエラー if getTicketRatio(ticket.gsub("#", "")).nil? then dbg("Ticket %s is nothing.\n", ticket) errCnt += 1 else dbg("Ticket %s is validity.\n", ticket) refsCnt += 1 end end end #修正用チケットをチェック fixes = item.scan(/fixes[ ]*[#|0-9| |,]+/) fixes.each do |fix| tickets = fix.scan(/#[0-9]+/) tickets.each do |ticket| #進捗率が求めれない場合はエラー #進捗率が100%の場合はエラー if getTicketRatio(ticket.gsub("#", "")).nil? then dbg("Ticket %s is nothing.\n", ticket) errCnt += 1 elsif 100 == getTicketRatio(ticket.gsub("#", "")) then dbg("Ticket %s is complite.\n", ticket) errCnt += 1 else dbg("Ticket %s is validity.\n", ticket) end end end end #参照用チケットがない場合はエラー if 0 == refsCnt then dbg("No refs ticket.(refs #)\n") errCnt += 1 end #エラーがある場合は exit 1 で終了 if 0 < errCnt then dbg("--- NG %s ---\n", Time.now) exit 1 end # All checks passed, so allow the commit. dbg("--- OK %s ---\n", Time.now) exit 0