Packagist.jp と Prestissimo を Itamae で導入して Serverspec でテストする

Packagist.jp と Prestissimo を Itamae で導入して Serverspec でテストする

この記事が公開されるころには Rubykaigi 2016で Matz の基調講演を聴いているはずの kagata です。そのはずなんですが、台風13号こと Malou が迫っているそうで、スケジュールどおり移動できるか心配になってきました。

さて、今回は RubyKaigi 開催にちなんで、PHPer の集うバシャログでは珍しい Ruby 成分多めの記事をお送りします。Ruby 製ツールを使って、PHP アプリケーションの開発環境を整備していきます。

Packagist.jp と Prestissimo とは

表題にある Packagist.jpPrestissimo は、どちらも PHP の依存関係管理ツール Composer を日本近辺で高速に使えるようにするためのツールです。前者はリポジトリのミラーサイト、後者は Composer のプラグインです。

くわしくは下記記事をご覧ください。

PHPカンファレンス関西2016で基調講演してきました - Mercari Engineering Blog

先日の PHP カンファレンス関西に遠征して聴いたこの基調講演で刺激を受けて、帰りの高速バスでガーッと書き上げたのが今回ご紹介するコードになります。

Packagist.jp と Prestissimo を Itamae で導入するコード

それでは、Itamae を使って Composer をセットアップしていきます。今回は Vagrant で立ち上げた環境でユーザー vagrantcomposer コマンドを使えるようにすることを想定しています。検証には Fedora24を使っています。

Vagrant と Itamae の導入については以下の過去記事をご覧ください。

Vagrant+ItamaeでPHPアプリケーション開発環境を作る | バシャログ。

PHP と Composer が使うパッケージをインストールする

まずは何はなくとも PHP が必要です。そして、 Composer は内部で gitunzip を利用します。これらをまずインストールしましょう。

%w{php git unzip}.each do |pkg|
  service pkg do
    action :install
  end
end

Composer をインストールする

続いて Composer 本体をインストールします。インストールの手順は公式ドキュメントの記述を参考にしました。

# ユーザー vagrant から `composer` コマンドが使えるか確認するコマンド
composer_exists = 'su -l vagrant -c "composer --version"'

# Composer をインストールする
execute 'install Composer' do
  command 'curl -sS https://getcomposer.org/installer | php'
  user 'vagrant'
  not_if composer_exists
end

# `composer` コマンドで Composer が呼び出せるようにする
execute 'add composer command' do
  command 'mv composer.phar /usr/bin/composer'
  not_if composer_exists
end

これで、 composer コマンドから Composer が呼び出せるようになりました。

Packagist.jp と Prestissimo を導入する

Composer 本体の準備ができたら、Composer に Packagist.jp と Prestissimo を導入します。

なお、以下で適用する Composer のカスタマイズはユーザー vagrant にのみ有効です。この状態で root ユーザーからも composer コマンドは使えますが、初期設定のまま Composer を呼び出すことになります。

# Packagist.jp を使う設定を追加する
execute 'use packagist.jp' do
  command 'composer config --global repositories.packagist composer https://packagist.jp'
  user 'vagrant'
  not_if 'su -l vagrant -c "composer config --global --list | grep packagist.jp"'
end

# Prestissimo をインストールする
execute 'install prestissimo' do
  command 'composer global require hirak/prestissimo'
  user 'vagrant'
  not_if 'su -l vagrant -c "cd ~/.composer && composer show | grep hirak/prestissimo"'
end

これで、ひととおりの環境整備ができました。ヨーロッパから遠く離れた日本でも、快適な速度で Composer が使えるようになります。

Serverspec でテストするコード

では、ここまでの成果を Serverspec でテストしてみましょう。

テストにあたって問題になるのが、ユーザーによって Composer の状態が異なる、ということです。このまま素直に Serverspec でテストを走らせると、root ユーザーが利用する Composer の状態がテストされてしまいます。先に述べたとおり、Packagist.jp や Prestissimo はユーザー vagrant のみに導入しているので、これでは正しくテストすることができません。

そこで、 Serverspec の機能を一部拡張して、root でなく任意のユーザーを指定してテストができるようにしました。以下のコードを spec_helper.rb に追加します。

module Serverspec
  module Type
    class Command
      def by_user(user)
        self.class.new("su -l #{user.shellescape} -c #{@name.shellescape}")
      end
    end
  end
end

このコードは以下から拝借しています。

serverspecでユーザーを指定してコマンドを実行させる拡張

Ruby では、組み込みのもの含め任意のクラスをコードの途中で再定義して、メソッドを追加したり上書きしたりすることができるようになっています。これをオープンクラスといいます。ここでは、Serverspec が持つ Serverspec::Type::Command クラスに外野から by_user というメソッドを追加しています。

これでテストの準備が整いました。テストコードは次のようになります。

# 必要なパッケージがインストールされていること
%w{php git unzipo}.each do |pkg|
  describe package(pkg) do
    it { should be_installed }
  end
end

# ユーザー vagrant がコマンド `composer` を使えること
describe command('composer --version').by_user('vagrant') do
  its(:exit_status) { should eq 0 }
end

# ユーザー vagrant の Composer に Packagist.jp が導入されていること
describe command('composer config --global --list | grep packagist.jp').by_user('vagrant') do
  its(:exit_status) { should eq 0 }
end

# ユーザー vagrant の Composer に Prestissimo がインストールされていること
describe command('cd ~/.config/composer && composer show | grep hirak/prestissimo').by_user('vagrant') do
  its(:exit_status) { should eq 0 }
end

まとめ

  • Ruby 製の構成管理ツール Itamae を使って、日本近辺で快適に Composer が使える開発環境を立ち上げました。
  • また、その仕上がりを同じく Ruby 製のテストツール Serverspec でテストしました。
  • Composer の状態はユーザーごとに異なるので要注意です。
  • Ruby のオープンクラスはゆかいですね。
  • このエントリーをはてなブックマークに追加

この記事を読んだ人にオススメ