モダンPerlの世界へようこそ

第26回 ShipIt:モジュールのリリースをもっと手軽に

この記事を読むのに必要な時間:およそ 5 分

ShipIt

cpan-upload(-http) は単体でも十分有用なスクリプトですし,コマンドラインから離れたがらないコアなモジュール作者たちにとっては生命線ともいえるものですが,ブラッド・フィッツパトリック氏はさらにリリースの手間を軽減するべく,翌2007年にはShipItというアプリケーションをリリースしています。氏は同年のYACP::Asiaにも来日してくれたので当時のブームを覚えている方も少なからずいると思いますが,これを使うと先ほどのリリースの手順はここまで短縮できます。

> cd Your-Distribution-Name
> shipit

ShipItをはじめて利用する場合はそのディストリビューション専用の設定ファイルがないといわれるかもしれません。前回紹介したツールのなかには最初からShipItの設定ファイルを用意してくれるものもありますが,ここでは表示される指示にしたがって「shipit --write-config」を実行しておきましょう。このコマンドを実行すると,このような設定ファイルが自動生成されます。

# auto-generated shipit config file.
steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist

# svn.tagpattern = MyProj-%v
# svn.tagpattern = http://code.example.com/svn/tags/MyProj-%v

# CheckChangeLog.files = ChangeLog, MyProj.CHANGES

この.shipitという設定ファイルは,それぞれの必要に応じて適宜修正を加えてください。標準的にはメインモジュールのバージョンを探して(FindVersion)変更し(ChangeVersion⁠⁠,Changesのような更新履歴の修正が済んでいるか確認し(CheckChangeLog⁠⁠,リリーステストを行い(DistTest⁠⁠,バージョン管理システムにコミットし(Commit⁠⁠,タグを切り(Tag⁠⁠,リリース用のディストリビューションを生成する(MakeDist)という流れになっていますが,CPANにモジュールをアップロードしたい場合はstepsの最後に「, UploadCPAN」を付け加える必要がありますし,⁠git.push_to = origin」という行を追加すればgitのコミット先を指定することもできます。CPANにはTwitterにつぶやいたり,すべてのモジュールのバージョンが一致しているか確認するモジュールも登録されていますし,自分でプラグインを書けば,ShipItと同時に特定のパッケージ管理システムを更新したり,社内向けのIRCにメッセージを飛ばしたり,特定のアプリケーションを再起動したりといった作業も簡単にできます。

たとえば,リリースのときにかならずメールを送りたい相手がいるなら,このようなモジュールを書いておけばよいでしょう。ここでは.shipitで設定した相手に変更履歴の差分を送信していますが,もう少し一般的に説明すると,.shipitで設定したい値がある場合はinit経由で取り出し,実際の作業はrunのなかで実行する,というのがShipIt::Step::* の基本的な書き方です。また,あらかじめどのような動作になるか確認できるよう,--dry-runオプションがついているときは実際の処理をスキップするようにしておくのも大事なことです。

package ShipIt::Step::MySendmail;

use strict;
use warnings;
use base 'ShipIt::Step';
use Email::Sender::Simple 'sendmail';
use Email::MIME;
use Email::MIME::Creator;

sub init {
    my ($self, $conf) = @_;
    $self->{mailto} = $conf->value('Sendmail.to');
}

sub run {
    my ($self, $state) = @_;

    my $distfile = $state->distfile;
    my $msg = "New features of $distfile\n";
    $msg .= $state->vc->local_diff($_) for $state->changelog_files;
    my $email = Email::MIME->create(
        header => [
            From    => 'my_address@localhost',
            To      => $self->{mailto},
            Subject => "[Release] $distfile",
        },
        body => $msg,
    );

    if ($state->dry_run) {
        print "DRY-RUN.  ", $email->as_string, "\n";
        return;
    }

    sendmail($email);
}

1;

このようなモジュールは,汎用性があるなら独立したディストリビューションの一部としてもよいでしょうし,そのディストリビューションでしか使わないものなら,ディストリビューション内のリポジトリに入れたうえで,MANIFEST.SKIPや.gitignoreなどを利用してディストリビューションからは排除するようにしてもよいかもしれません。CPANにモジュールをアップロードしない場合でも案外便利に使えますので,これまで利用してこなかった方は一度試してみるとよいでしょう。

Dist::Zilla

このようなリリースまわりの面倒を見てくれるモジュールとしては,ほかにもブライアン・フォイ(brian d foy)氏のModule::Release(これはCPANだけでなく,SourceForgeへのリリースなども行ってくれます)ヤニク・シャンプー(Yanick Champoux)氏のDist::Releaseがありますが,ここではもうひとつ,リカルド・シグネス氏が2008年から開発を進めているDist::Zillaについても触れておきましょう。これもShipItと同じくリリース前にさまざまな処理をしてくれるアプリケーションですが,こちらは単にバージョンをあげたりファイルのアップロードを行ったりするだけでなく,前回とりあげたひな形作成ツールが用意してくれるようなMakefile.PLやREADMEなども自動生成しようとするのが大きな特徴で,既存のひな形作成ツールとの相性はあまりよくありませんが,Mooseのロールを使ってプラグインの実行順序などを細かく制御できるようになっているため,Mooseの流儀に慣れた人には拡張しやすいものになっています。

Dist::Zillaを使う場合は,プロジェクトごとにdist.iniという設定ファイルを用意します。一からプロジェクトを始める場合は,コマンドラインから「dzil new Foo::Bar」を実行すると,Foo-Barというディレクトリが作成され,その下にこのようなdist.iniファイルが生成されます(既存のプロジェクトをDist::Zilla管理に切り替える場合は,プロジェクトのディレクトリに移動したあと「dzil new .(ピリオド⁠⁠」を実行すると同様のdist.iniを生成できます⁠⁠。

name    = Foo-Bar
version = 1.000
author  = Kenichi Ishigaki
license = Perl_5
copyright_holder = Kenichi Ishigaki

[@Classic]

これはそれぞれディストリビューション名,最初のバージョン番号,作者名,Software::Licenseモジュールのサブクラス名,著作権保持者名の指定で,最後の [@Classic] はDist::Zilla::PluginBundle::Classicというプラグインバンドルを利用する,という指示です。これは,ディレクトリ内のファイルをかき集め(AllFiles⁠⁠,ドットファイルなどのよくある不要なファイル(PruneCruft)や,MANIFEST.SKIPで指定されているファイル(ManifestSkip)を除外し,META.yml(MetaYAML)やライセンス(License⁠⁠,README(Readme)を追加し,ディストリビューション内のすべてのモジュールにバージョン指定を加え(PkgVersion⁠⁠,PODにもバージョンを指定する一文を付け加え(PodVersion⁠⁠,PODテスト(PodTests)や作者用のテストなどを付け加え(ExtraTests⁠⁠,binディレクトリやshareディレクトリがあればそれもパッケージに含まれるようにし(InstallDirs⁠⁠,Makefile.PL(MakeMaker)とMANIFEST(Manifest)を生成する,という設定をひとまとめにしたものですが,特定の処理が気に入らない場合は,[@Classic] の行をこのように書きかえると,特定の設定だけ除外することができます。また,別のプラグインを追加したい場合は,dist.iniにプラグイン名を追加します(実行順序はそのプラグインに適用されているロールによるので,dist.ini内で記述の順序を気にする必要はありません⁠⁠。

[@Filter]
bundle = @Classic
remove = PodVersion

[AutoVersion]

Dist::Zillaを使ううえで注意が必要なのは,依存モジュールの扱いです。従来の書き方に慣れた人はついMakefile.PLなどで指定すればいいと思ってしまうところですが,デフォルトのDist::ZillaではMakefile.PLやMETA.ymlなどを作成するときにdist.iniのなかで指定した依存モジュールの一覧を参照するようになっているため,⁠Makefile.PLの自動生成をしたくない場合でも)このようなPrereqセクションを用意するか,あるいはジェローム・ケラン(Jerome Quelin)氏のAutoPrereqプラグインを利用して依存モジュールを機械的に検出する必要があります(現状ではbuild_requiresなどのオプションには対応していないようです⁠⁠。

[Prereq]
Test::More = 0.88

その他の使い方については,Dist-Zilla-PluginBundle-RJBSのように自分の流儀をまとめたプラグインバンドルがいくつか公開されているので,参考にしてみるとよいでしょう。

Githubからのリリース

ちなみに,CPANにモジュールを登録する場合はかならずこのようなアップロードツールを使わなければならない,ということはありません。昨年ピッツバーグで開催されたYAPC|10(YAPC::NA)では,マイク・シリ(Mike Schilli)氏がgithubのダウンロードファイルをPAUSEに取り込ませる方法を紹介して一部の話題になっていました。詳しくは氏のブログ記事やそのコメント欄にある通りですが,ふだんからgitリポジトリ内に適切なMETA.ymlやMANIFEST,incディレクトリなどを入れている(make dist時に自動生成したりせず,tar/gzipで圧縮するだけで過不足ないディストリビューションができるようにしている)場合は,gitでタグを切るだけでgithub上にダウンロード可能なファイルが生成されるので,そのURLを少々加工してPAUSEに渡してやれば,cpan-uploadのようなツールに頼らなくてもCPANにモジュールをリリースできる,というのがその仕組みです。いまのところそのやり方に追随しているモジュールもなく,あまり実用的なやり方とはいえませんが,自分のサイトなどでダウンロード可能なアーカイブを提供している方なら,コミット時のフックポイントに細工をして,タグを切ったらリリース可能なアーカイブを作成してCPANに登録,という仕掛けをつくってみるのもよいかもしれません。

著者プロフィール

石垣憲一(いしがきけんいち)

あるときは翻訳家。あるときはPerlプログラマ。先日『カクテルホントのうんちく話』(柴田書店)を上梓。最新刊は『ガリア戦記』(平凡社ライブラリー)。

URLhttp://d.hatena.ne.jp/charsbar/