コードの管理
Subversionでブランチとトランクのmergeを実行したところ、どうもうまくいかなかったらしい。ブランチの変更がトランクの変更を打ち消してしまっているソースコードがいくつか見つかった。とりあえす手動で直して、原因を突き止めようとしているのだが、まだはっきりとしたところはわからない。
どのツリーへのコミットも全てBTSとメールで記録されているので、毎月のメンテナンスリリース程度ならばSubversionに任せきりではなくこちらでもmergeが確実に実行されているかどうか確認するようにした。運用上のヘマならいいのだが、もっと根深い問題なら困ったものだ。
ソースコードの管理をSubversionに移行してから、CVSよりはるかに簡単な操作で随分と楽をさせてもらっているのだが、やはり複雑に分岐したブランチを取りまとめるのは大変だ。
ふと思ったのだが、Joel on softwareの「ストラテジーレターIV: ブロートウェアと80/20の神話」では触れられていない話があって、市場の拡大による売り上げアップを狙っていわゆる「ライト版」を作るというのは、コードの管理を複雑にしてそのコストを引き上げるので、元のフルバージョンのコストを上げてしまうという弊害もある。開発済みのプログラムから機能を抜くのはときどきかなり面倒くさい作業で、おまけにバージョン毎にちょっとした違いがあったりすると管理コストはさらに跳ね上がる。どうせやるなら、最初から使える機能をコントロールできる機構が組み込まれているようにしないといけない。そうじゃないと、テストのコストだけでも結構なものになるので、ライト版は営業の人たちが思っているほどお安くはならなくなってしまう。おまけに、そんな作業でリリースに失敗したり不具合でも埋め込んでしまっては泣くに泣けない。
Subversionの疑問
Subversionでtrunkの変更をbranchに取り込むと
行方不明の対象ファイルは飛ばしました: path/to/file.sh 行方不明の対象ファイルは飛ばしました: path/to/module/file.php
みたいな文字列がズラズラと表示される。どうやらtrunk側に新規に追加されたファイルを自動的に持ってきてはくれないみたいだ。
$ cd path/to/my-branch $ svn merge --dry-run -r ブランチのリビジョン:HEAD \ file:///path/to/repo/trunk | grep "^[^A-Z]"
これで取り出したファイルを手動でコピーするのがいかにも面倒くさい。この辺りをカバーする機能はあるのかな?
日々雑感
更新が滞っていたが、その間にも近所の新しい分譲住宅地で地主が首を吊ったとか、WordPressのサーバがクラックされて配布中のファイルが書き換えられていたりとか、まあいろいろとあった。あと、誕生日も過ぎた。
今は社内文書、特にPDFの仕様書なんかを溜め込んで全文検索できるようにする作業が進行している。いろいろ試したが、フロントエンドを作りやすいのでSenna + Ludiaで実装している。MySQL自体にパッチを当てるのはいかがなものかと思うので、パッチなしでPostgreSQLと連動するLudiaにした。
Subversionはなんだかんだいいながら影舞と連動して動くようになり、仕事の開発関連の作業は順調。かみさんの日記サイトはいつまでも放置されたままなので閉鎖した。何度作ってもいつもろくに使われないまま消えてしまう。まあ、そんなものなのだろう。
親指がもげてもなんとかなる。それが人生だ。
Subversion試用中
Subversionのpost-commitはこんな風にした。
Subversionは環境変数LANGを与えるとメッセージをUTF-8から変換してくれる。コミットされたファイル毎にBTSに突っ込んだり、追加だったらそれなりの処理をしたりする部分については別途ファイルを分けておいたのでここでは省略。新規に追加された場合は、パーミッションの情報を別途管理するスクリプトに追記するようメールが飛んだりする。原始的だけど、とりあえずこれでやってみよう。
#!/usr/bin/php -q <?php //引数を取得($1がレポジトリ、$2がリビジョン) if(is_array($argv)){ $repo = $argv[1]; $rev = $argv[2]; }elseif(is_array($_SERVER['argv'])){ $repo = $_SERVER['argv'][1]; $rev = $_SERVER['argv'][2]; } if($repo == '' || $rev == ''){ //エラー処理(省略) } //変更者 $author = `svnlook author $repo`; //コメント $comment = `export LANG=ja_JP.eucJP && svnlook info $repo`; //変更されたファイルを取得。複数ある場合はそれぞれに対応 $changed = `svnlook changed $repo`; if($changed != ''){ $changed_ar = split("\n", $changed); } //コミット後の処理(ファイル毎に実行) if(is_array($changed_ar)){ foreach($changed_ar as $v){ $trimed = trim($v); if($trimed){ //メール送信処理(省略) //リリースファイル一覧更新(省略) } } }else{ $notice = 'not array'; } ?>
Subversionの準備
結局、理想的なウェブアプリの開発環境はこんな感じに。
Subversionのレポジトリのディレクトリ構成は、伝統的にこんな風になっている:
$ mkdir OurGreatApp $ mkdir OurGreatApp/trunk $ mkdir OurGreatApp/branch $ mkdir OurGreatApp/tags
名前の通り、trunk(主幹)が現在まさに開発中のセット一式。開発が完了したら、svn copyでtagsディレクトリ以下に収まる。こうするとtagsにはリリース番号が割り当てられたセット一式が入る。OurGreatApp/tags/1.0/とか、OurGreatApp/tags/1.1/とか。branchは適時必要に応じて作られる。カスタマイズ案件があったときや、次期メジャーバージョンの開発など。
hooks用のスクリプトで実装するのは
pre-commit
- コメントの書式チェック
- コミットされたスクリプトの構文チェック
- コーディング規約に則ったチェック
post-commit
- レポジトリのパスに応じてバグトラッカーに変更内容を投稿
- テスト管理プログラムのDBに変更されたスクリプトの内容を投稿
- リリース用ファイルリストに必要に応じて追記
PHPで記述するとこんな感じ。
#!/bin/env php <?php $rev = $argv[2]; //リビジョン $path = $argv[1]; //コミットされたファイルのパス $log = `svnlook log $rev $path`; //コメント(UTF-8) $author = `svnlook author $rev $path`; //コミットした人 $date = `svnlook date $rev $path`; //日時 //do something ?>
post-commitのところは、もっとシンプルにBTSに統合されるといいのだろうけれども、そこまでは手が回っていない。
これで、変更があった場合には記録が全部BTSに入るので、BTSのステータスが完了になるまでリリース出来なくなり、テストが漏れることを防いでくれる。
BTSには影舞を使っている。メンテナンスを考えると、PHPで書かれたフリーのBTSで優秀なのがあればいいのだが、なかなか見当たらない。
Subversionで開発環境を整備
以前、いろんな人たちから強く勧められていたSubversionへの移行が出来ないかとあれこれ調べていた。基本的なコマンドはCVSのものが使えるので、あとは運用方法だ。せっかくなので、trunkとbranchを開発するユーザがいて、trunkの修正をリリースするときにリリース担当チームに修正分と内容がきちんとリストになって渡されて、branchにもmergeされるようにしよう。
複数のユーザで同じレポジトリを使って、権限の問題を発生させないようにするには、コミットするユーザだけ同じにしてあげればいいみたいだ。ドキュメントを参考にしてそのユーザのauthorized_keysをいじるともっといいらしい。
リリース用のリスト作成だが、CVSのloginfoみたいな仕組みがあるか調べたら、レポジトリのhooksディレクトリに実行スクリプトを作ってあげるとcommit時の動作にフックをかませることができるらしい。*.tmplというファイルがすでに作られているが、実際に動作させる場合は.tmplのつかないファイルを置いて、実行権限を付与する。
ただし、hooks用の実行ファイルを作成して、今度から新規に作成されたレポジトリには全てそれを適用させようとしても、現在のところsvnadminにはその機能はない。よって、いちいちコピーするか、スケルトンになるレポジトリからrecoverを使って新規作成するしかない:
$ cp -a template-repos new-repos
$ rm new-repos/db/uuids
$ svnadmin recover new-repos
ちょっと強引なので避けたいところ。2004年の時点での機能追加提案なので、本当に今でもそうなのかはまだわからない。