Active Directoryと連携して、svn:authorに氏名を表示する(Windows)

属性を変更できるようにする

デフォルトでは、svn:logをはじめとした属性を後から変えることはできないようになっているので、まずここを変更する。
Subversionサーバのリポジトリの実体があるディレクトリに、hooksディレクトリがあるので、その中のpre-revprop-change.batを作成する。

rem  [1] REPOS-PATH   (the path to this repository)
rem  [2] REVISION     (the revision being tweaked)
rem  [3] USER         (the username of the person tweaking the property)
rem  [4] PROPNAME     (the property being set on the revision)
rem  [STDIN] PROPVAL  ** the property value is passed via STDIN.
if "%4"=="svn:author" (
    exit 0
)
exit 1

フックスクリプト(post-commit)で変更する

下記は、perlで行う場合の例。まずバッチファイルでperlスクリプトをキックする。

rem  [1] REPOS-PATH   (the path to this repository)
rem  [2] REVISION     (the revision being tweaked)

set REPOS=%1
set REV=%2

C:\Perl\bin\perl D:\testrepository\hooks\ldap.pl %REPOS% %REV%

exit 0

rem http://subversion.apache.org/faq.ja.html#hook-debugging
rem Subversion はフックスクリプトを起動する前に、全ての環境変数を取り除く。
rem その中には、Unixでは $PATHが、Windows では %PATH% が含まれる。
rem 結果、スクリプトでは、絶対パス名の記述された他のプログラムだけを実行可能だ。

フックで呼び出されたら、実際の処理を行う。

実際の処理部分は、下記の通り。
おおざっぱに言うと、svnlookコマンドでsvn:authorの値を取り出して、Active DirectoryLDAPで問い合わせをして、氏名を割り出し、svn propsetで当該のリビジョンに埋め込んでいる。

use strict;
use warnings;

use Encode;
use Net::LDAP;

my ($repos, $rev)       = @ARGV;

my $cn                  = "--USERNAME--";                                                       # LDAPアクセス用ID
my $pass                = "--PASSWORD--";                                               # LDAPアクセス用パスワード
my $ldap_server = 'example.com';                        # LDAPサーバー
my $ldap_base   = 'DC=example,DC=com';
my $ldap_bind   = "CN=$cn,OU=users,$ldap_base";
my $displayname;
my $url                 = 'http://example.com/svn/';    # SubversionリポジトリのURL

open my $file, '>', "logs/ldap_pl$rev.txt" or die $!;   # ログ記録開始

print $file '$repos: ' . "$repos\n";
print $file '$rev  : ' . "$rev\n";

my $command     = "svnlook author $repos -r $rev";
open my $dir, '-|', $command or die $!;
my $author_id;
while(my $line = <$dir>){
        chomp $line;
        $author_id = $line;
}
close($dir);

print $file '$author_id: ' . "$author_id\n";

my $ldap = Net::LDAP->new($ldap_server,);       #サーバー名

print $file "ldap: $ldap\n";

my $msg = $ldap->bind(
        $ldap_bind,
        password => $pass,
);      #ユーザ名とパスワードで認証

my $filter = "cn=$author_id";

print $file encode('cp932', decode('utf8', __LINE__ . ": " . "LDAP接続結果 = " . $msg->error . "\n"));      #ここまでのerrorログを取得
$msg = $ldap->search(
        base            => $ldap_base,
        filter          => $filter,
        attribute       => 'cn=lang-ja'
);      #search処理

for my $entry ($msg->all_entries) {
        $displayname = $entry->get_value('displayname');
}

print $file encode('cp932', decode('utf8', "$displayname\n"));
Encode::from_to($displayname, 'utf8', 'cp932');

$command        = "svn propset svn:author --revprop -r $rev $displayname($author_id) $url --username $cn --password $pass";
print $file "$command\n";
close $file;
system($command);