読者です 読者をやめる 読者になる 読者になる

weblog of key_amb

主にIT関連の技術メモ

ShipIt を使って Perl モジュールのリリース作業を自動化する

ShipIt は Perl プロダクトのビルド、テスト、リリースを自動化してくれるツールで、CPAN へのアップロードもできます。

今回は以下の作業を半自動化するために、ShipIt を利用しました。

  • モジュール群の VERSION インクリメント
  • ChangeLog の更新
  • リリースタグを作成し、GitHub に push

前提として、プロジェクトはスクラッチで開発しており、lib/ 以下にモジュールが出来ているものとします。

1. ShipIt のインストールと初期設定

cpanm で ShipIt をインストールします。

cpanm ShipIt

プロジェクトのルートディレクトリで次のコマンドを実行し、設定ファイル .shipit を生成します。

shipit --write-config

今回、.shipit の内容は以下のようにします。

steps = FindVersion, ChangeAllVersions, CheckChangeLog, DistTest, Commit, Tag
git.push_to = origin

ChangeAllVersions を使うと、プロジェクトの全モジュールの VERSION を更新することができました。

※追記※

今回の目的に照らし合わせると、DistTest は不要でした。

2. Module::Build によるビルドの用意

shipit を動かすには最低限 Build.PL や Makefile.PL などが必要なようです。 試しに用意せずに shipit を実行すると次のようなエラーになります。

$ shipit
(git)-[master][~/path/to/project]
Running step ShipIt::Step::FindVersion=HASH(0x7fddc2b6f688)
Unknown project type.  Can't find Makefile.PL, Build.PL, configure.ac, etc.. at ~/.plenv/versions/5.18.2/lib/perl5/site_perl/5.18.2/ShipIt/ProjectType.pm line 47.

今回は Module::Starter でビルドの雛形を作って、必要なものをプロジェクトのリポジトリにコピーすることにします。 DistTest を実施しないのであれば、以降で生成されるファイルの内、最低限必要なものは Build.PL だけなので、もっと簡易なやり方もあります。(後述)

Module::Starter がない人は cpanm でインストールしましょう。

ビルドモジュールとしては Module::Build を使うことにします。

$ cpanm Module::Starter

$ cd ~/tmp
$ module-starter --module=Foo::Bar --author="Your Name" --email="your.name@example.com" \
  --build=Module::Build

$ ls Foo-Bar/
Build.PL   Changes    MANIFEST   README     ignore.txt lib        t

今回は lib/, t/, README, Changes は既にプロジェクト側で用意していたので、Build.PL, ignore.txt をコピーしました。

MANIFEST は後で Module::Build によるビルドで生成します。

3. MANIFEST 生成

※shipit で DistTest を実施しない場合、こちらの手順は不要です。

まず Build.PL から Build スクリプトを生成します。

perl Build.PL

次に標準の MANIFEST.SKIP ファイルを生成した後、プロジェクトのファイル群を MANIFEST に追加します。

./Build manifest_skip
./Build manifest

4. shipit 実行

shipit を実行する前に、ビルドに必要なファイルは git add しておかないと、git への push が失敗します。

shipit を実行すると、対話式インタフェースで処理が進行します。

$ shipit
(git)-[master][~/path/to/project]
Running step ShipIt::Step::FindVersion=HASH(0x7f8a08828c60)
Current version is: 0.01
Next/release version? 0.02
Running step ShipIt::Step::ChangeAllVersions=HASH(0x7f8a08c0ef90)
Update $VERSION in lib/Foo/Bar.pm.
Update $VERSION in lib/Foo/Bar/Baz.pm.
Running step ShipIt::Step::CheckChangeLog=HASH(0x7f8a08c77b60)
No mention of version '0.02' in changelog file 'ChangeLog'
Edit file? [Y/n] y

/* エディタで ChangeLog を編集 */

"ChangeLog" [converted] 37L, 868C written

Running step ShipIt::Step::DistTest=HASH(0x7fdbd9c78c40)
Could not get valid metadata. Error is: Invalid metadata structure. Errors: License 'Artistic_2_0' is invalid (license -> Artistic_2_0) [Validation: 2]
 at ~/.plenv/versions/5.18.2/lib/perl5/site_perl/5.18.2/Module/Build/Base.pm line 4555.

Could not create MYMETA files
Creating new 'Build' script for 'Foo-Bar' version '0.02'
Creating Makefile.PL
*** Did you forget to add META.yml to the MANIFEST?
Creating Foo-Bar-0.02
Could not get valid metadata. Error is: Invalid metadata structure. Errors: License 'Artistic_2_0' is invalid (license -> Artistic_2_0) [Validation: 2]
 at ~/.plenv/versions/5.18.2/lib/perl5/site_perl/5.18.2/Module/Build/Base.pm line 4555.

Could not create MYMETA files
Creating new 'Build' script for 'Foo-Bar' version '0.02'
Building Foo-Bar
No tests defined.
Cleaning up build files
Cleaning up configuration files
Running step ShipIt::Step::Commit=HASH(0x7fdbd9c7f3c8)
[master 3cd888d] Checking in changes prior to tagging of version 0.02.
 13 files changed, 163 insertions(+), 5 deletions(-)
 create mode 100644 .shipit
 create mode 100644 Build.PL
 create mode 100644 MANIFEST
 create mode 100644 MANIFEST.SKIP
 create mode 100644 Makefile.PL
 create mode 100644 ignore.txt
pushing to origin at ~/.plenv/versions/5.18.2/lib/perl5/site_perl/5.18.2/ShipIt/VC/Git.pm line 74.
Counting objects: 33, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (17/17), done.
Writing objects: 100% (20/20), 3.16 KiB | 0 bytes/s, done.
Total 20 (delta 6), reused 0 (delta 0)
To git@github.com:key-amb/perl5-Foo-Bar.git
   272c0ad..3cd888d  master -> master
Running step ShipIt::Step::Tag=HASH(0x7fdbd9c7f7d0)
pushing to origin at ~/.plenv/versions/5.18.2/lib/perl5/site_perl/5.18.2/ShipIt/VC/Git.pm line 116.
Counting objects: 1, done.
Writing objects: 100% (1/1), 186 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:key-amb/perl5-Foo-Bar.git
 * [new tag]         0.02 -> 0.02
$ 

shipit 内で(というか ShipIt::Step::DistTest の中で)ビルド生成物のクリーンアップも行ってくれるようです。

補遺

後で ShipIt のソースを読みながら試したところ、ShipIt::Step::DistTest を実施しない場合、最低限の Build.PL の内容は次で十分です。

+{
    dist_version_from   => 'lib/Foo/Bar.pm',
};

Makefile.PL の場合は次のようになります。

version_from 'lib/Foo/Bar.pm';

感想

CPAN にモジュールを上げるときは Minilla を使うと楽でよいですが、今回のような限定的な用途だと、shipit の方が向いてるのかなと思いました。

ハマったこと

実は bin/ 以下にスクリプトを置いていて、そちらにも VERSION を付けていたのですが、 ShipIt::Step::ChangeAllVersions のせいで実行ビットが落ちてしまったので、とりあえず VERSION を消しました。

(追記) Issue 上げたところ、作者に速攻で直してもらえました:D https://github.com/gfx/Perl5-ShipIt-Step-ChangeAllVersions/issues/2

参考