RedmineとSubversionの連携を強制的に行う

Redmineの機能の1つとしてSubversionとの連携があります。リポジトリコミット時にチケット番号を入れることでコミットとチケットを1対1で関連付けられてとても便利です。
しかし、Redmineは(おそらく)チームで使うものです。自分は正しく入力していても他のメンバーが入力を怠っていたらせっかくの機能が無駄になってしまいます。
なんとか入力を習慣づけてもらうために策を講じました。普通は運用ルールを作って守ってもらうのがよいと思いますが、そうは言ってもこちらが意図したとおりの操作を行ってくれるのは少ないものです。
ぼくはこういうのでとてもイライラしてしまう性質なので、コンピュータ側で入力を強制してもらうようにしています。(この場合、周りのメンバーとよく話をしろ、というのは別の話にしてください)

コミットメッセージにチケット番号が入っているかチェックする

単純にコミットメッセージをチェックするシンプルな方法です。
Redmineはコミットメッセージから"refs xxx"などのキーワードを読み取って関連付けするので、Subversionのフック機構を使ってメッセージをチェックします。
こんなスクリプトです。
※c:\Program FilesにVisualSVN Serverをインストール(リポジトリはc:\Repositories)している前提です。ご自分の環境に適宜読み替えてください。
pre-commit.bat

@echo off
set APR_ICONV_PATH=C:\Program Files\Subversion\iconv
cd C:\Repositories\hook_scripts
CScript //Nologo C:\Repositories\hook_scripts\commit_block.vbs %1 %2

c:\Respositories\hook_scripts\commit_block.vbs

set objArgs = WScript.Arguments
strRepoPath = objArgs(0) 'リポジトリパス
strTransaction = objArgs(1) 'トランザクション
Dim strMessage

Set objShell = WScript.CreateObject("WScript.Shell")

' ログメッセージの取得
Set objExec = objShell.Exec("c:\Program Files\VisualSVN Server\bin\svnlook.exe log " + strRepoPath + " -t " + strTransaction)
strMessage = objExec.StdOut.ReadLine

Dim objRE
Set objRE = new RegExp
objRE.pattern = ".+ refs ([0-9]+)"

If objRE.Test(strMessage) = False Then
	WScript.StdErr.WriteLine("エラー:" & strMessage)
	WScript.StdErr.WriteLine("ログメッセージの1行目にrefsキーワードが入っていません。チケット番号と共に追記をお願いします。")
	WScript.StdErr.WriteLine("チケット番号が存在しない場合は新しくチケットを発行してからコミットしてください。")
	WScript.StdErr.WriteLine("わからないことは…、わかりそうな人に確認してください。")

	WScript.Quit(1)
End If

これでコメントに"refs xxx"を入力しないとコミットできなくなります。これだけでもそれなりに効果がありますが、これだけだと、適当に番号さえ入れればコミットできてしまうので、効果は限定的です。

コミット時にチケット番号が正しいかをRedmineに問い合わせる

もう少しスマートにRedmineにチケット番号を問い合わせてみましょう。今度はRedmine側の修正も必要です。
※もしもRedmineの修正がなくても大丈夫そうなら教えてください!

まずは先ほどのcommit_block.vbsに下記を追加します。

Set matchs = objRE.Execute(strMessage)
Set sc = CreateObject("ScriptControl")
sc.Language = "JScript"
Set js = sc.CodeObject

On Error Resume Next

  issues_id = matchs(0).SubMatches(0)

  Set http = CreateObject("MSXML2.ServerXMLHTTP")
  url = "http://[サーバ]/issues/" & issues_id & "/confirm_repository_path?path=/" & js.encodeURI(strDirsChanged)
  http.open "GET", url, False
  http.send

  result = http.responseText
  Set http = Nothing
  
  WScript.StdErr.WriteLine(result)

  If result <> "true" Then
        WScript.StdErr.WriteLine("チケットが所属するプロジェクトのリポジトリの設定が正しくありません。")
      WScript.StdErr.WriteLine("コミット対象のフォルダとRedmineのプロジェクトの設定を見直してください。")
      WScript.StdErr.WriteLine("チケット番号:" & issues_id)
      WScript.StdErr.WriteLine("リポジトリパス:" & strDirsChanged)
	  WScript.Quit(1)
  End If

If Err.Number <> 0 Then

  WScript.StdErr.WriteLine(Err.Description)
  WScript.StdErr.WriteLine(Err.Source)
  WScript.Quit(1)
End If

ここからはRedmine側を修正します。まずはクライアントからの問い合わせを受けるアクション用のルートを作ってあげます。
config\route.rbの125行目くらいに追加

issues_views.connect 'issues/:id/confirm_repository_path', :action => 'confirm_repository_path', :id => /\d+/

app\controllers\issues_controller
before_filter :find_issueとbefore_filter :authorizeに:confirm_repository_pathを追加
confirm_repository_pathアクションを作成

before_filter :find_issue, :only => [:show, :edit, :reply, :confirm_repository_path]
before_filter :authorize, :except => [:index, :changes, :gantt, :calendar, :preview, :update_form, :context_menu, :confirm_repository_path]

  def confirm_repository_path
    repo = @project.repository
    if repo and params[:path]
      repo_path = repo.url[repo.root_url.length .. -1]
      repo_path = URI.decode(repo_path)
      result = params[:path].include?(repo_path)
    else
      result = false
    end
    render :text => result
  end

これでぼくの環境ではコミット時にチケットが所属するプロジェクトのリポジトリ設定が正しくないとコミットできないようになりました。
興味があったら試してみてください。