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

「そんなself-updateで大丈夫か?」 Composer編

こんにちはこんにちは、

VOYAGE GROUPでBuild prayer*1として活動している@_nishigoriです。

pip, bundler, rebar 等 各プログラミング言語のビルドツールないしパッケージマネージャ等と呼ばれているツールを弊社でも利用していますが、 PHPでは依存管理ツールとしてComposerを利用しているプロジェクトがあります。

今回はComposer本体のバージョニングについて紹介し、

利用する上での良い側面と悪い(と思われる)側面を紹介します。

はじめに

これはComposerについて網羅されたエントリではありません。

全体像を掴むには本家ドキュメントを一読することをオススメします。

https://getcomposer.org/doc/

Composer

Composerの入手

ComposerはPHPで作られPharというPHP独自のアーカイブ形式で配布されています。

また公式ドキュメントにもダウンロード方法が記載されており、インストーラをPHP実行することで入手可能です。

https://getcomposer.org/download/

$ curl -sS https://getcomposer.org/installer | php
#!/usr/bin/env php
all settings correct for using composer
downloading...

composer successfully installed to: /xxx/composer.phar
use it: php composer.phar

$ php composer.phar --version
composer version 1.0-dev (07da489..) 2015-11-06 20:12:25

最新版 *2

最新版(以降 Latest)のrevisionは以下のurlで確認できます。

https://getcomposer.org/version

Installer

インストーラ経由での取得はComposerの入手 章で紹介したコマンドの通り

特にオプション等は必要なく取得できます。

$ curl -sS https://getcomposer.org/installer | php

self-update

composer.phar自体のアップデートはself-update commandで実行できます。

特に意識することなくそのまま実行するとLatestを取得します。

$ php composer.phar self-update
updating to version 649dc78f086e9f9cb7f4eb681ae17b95f896c823.
    downloading: 100%
use composer self-update --rollback to return to version 07da4892456cc2f297a1b1c252a1f75cd12b85ea

リリースサイクル

Composer取得先のhttp(s)://getcomposer.orgはgithubで管理されており、

Latestのリリースの仕組みはgithub上では公開されていません*3 が、

コミュニティのcommiter曰くgithub上のmaster branch pushをフックにビルドしているようです。 *4

またLatestを使い続ける場合、一定期間内にself-updateすることが推奨されています。 *5

(後述するtagging versionsを利用する場合はその限りではありません)

効能

Composerプロジェクトはコンスタントに更新を続けているプロジェクトのひとつで、

Latestを使い続けることにより新しい機能をすぐ使えることができます。

デメリット

self-updateする日時によってrevisionが異なる(場合がある)

Latestの更新は利用者側からバージョンをハンドル仕切れないので、

個々人の開発環境、CI ServerやService serversで利用している場合には注意が必要です。

ある日のself-updateで突然死

master branchのHEADイコールLatestですので、日々のself-update'd revisionで予期せぬエラーが内包されることはリスクとして存在します。

私自身は過去に何度か経験しました($ php composer.phar install 時にExceptionを吐く等)

git log --all --grep='revert' 等で見てみると過去のものが色々と見つかります)

余談ですが、Composerプロジェクトはcontributing-policyとしてGithub PRベースの更新を推奨しています。

https://github.com/composer/composer/blob/master/contributing.md#contributing-policy

Commiterがこのpolicyに沿っていないケースがあり、たまにmaster branchに直接pushしているケースが多いのは面白いなぁとみています。

回避策のひとつとしては、 --rollback (r) オプションを利用して 前回self-update command実行前のバージョンに戻すことが可能です。

(self-update実行時には、実行前のバージョンがバックアップされています)

$ php composer.phar self-update --rollback
rolling back to version 2015-11-06_20-12-25-07da489.

$ php composer.phar --version
composer version 1.0-dev (07da4892456cc2f297a1b1c252a1f75cd12b85ea) 2015-11-06 20:12:25

Tagging Versions

ComposerはGithub上のTaggingされたバージョンを指定して取得することが可能です。

2015-11-09現在は 1.0.0-alpha10 までリリースされています。

Installer

インストーラ経由での取得はphpコマンドに--version引数を追加することで指定バージョンの取得が可能です。

$ curl -sS https://getcomposer.org/installer | php -- --version=1.0.0-alpha10

self-update

self-updateで引数versionを指定して取得・アップデートできます。

$ php composer.phar self-update 1.0.0-alpha10
updating to version 1.0.0-alpha10.
    downloading: 100%
use composer self-update --rollback to return to version 649dc78...

リリースサイクル

ざっくり半年程で新しいバージョンが出ています…

https://github.com/composer/composer/releases

効能

Tagging Versionを利用することによって、 常に同じバージョンでcomposer.pharを利用できることができます。

これによりLatest利用のデメリットであるself-update時に不確定なrevisionが使用されることはありません。

デメリット

リリースサイクルが遅い

次期リリースのmilestoneが切られることが以前はありましたが、

最近はContributorがissueを上げるスタイルが多いように見受けられます。。。

つまり、 リリースタイミングが特に決められているわけではありません

新機能が利用できない

リリースサイクルが遅いことの弊害で、master branchに取り込まれた新機能を利用するタイミングが Latestを利用している場合より遅れることがままあります。

過去ではPSR-4 Supportやsemver support等のfeature releaseが当時のLatestでのみ使用可能な時期がありました。

公式ドキュメントがLatestにのみ言及(downloadページ以外)

例えばnpmでは「version◯◯以上のnpmで使える」等のアナウンスがドキュメントに記述されていますが、 getcomposer.orgにはそれが存在しないので注意が必要です。

各バージョンのドキュメントを読みたい場合はgetcomposer.orgでなくComposerプロジェクトのdoc/以下を参照しましょう。

例: https://github.com/composer/composer/tree/1.0.0-alpha10/doc

アイエエエエ! alpha!? alphaナンデ!?

Composerのtagging versionsでは現在alphaのみ存在する状況です。

「なぜalphaなのか?stableはいつ出るのか?」

Stable versionを出してほしいという要望はgithub上やComposer google groupsでも度々挙がりますが、 Composerコミュニティとしては否定的なようです。

  • 「Latestはnightly buildだ」(意訳)
  • 何を持ってstableとするかの定義がコミュニティ/proposer間で定まっていない
    • https://github.com/composer/composer/issues/3707#issuecomment-73233903

(ちなみに次期バージョンの1.0.0-alpha11 はそろそろ出そうです。

その他の選択肢

composer.pharをgit ignoreしない

https://getcomposer.org/doc/faqs/should-i-commit-the-dependencies-in-my-vendor-directory.md

Composerコミュニティではcomposer.phar, 依存パッケージ配置先のvendor/をVCSでignoreにすることを推奨していますが、

composer.pharをプロジェクトのVCS管理内に含めることを選択している組織もあるようです。

いわゆるLatestでもなく公式提供のTagging Versionsでもない第三の選択肢ですね。

Composerヲ使ワナイ ~ ウルトラC

依存するパッケージ群の管理にComposerを使わず、 例えばgit-submodule等で管理する等の選択肢もあります。

ただしこれはComposerが提供するautoloader等を自前で用意することになるので、 ややコスト高です。

事例

Travis CI

CI Serviceで有名なTravis CIですが、

.travis.ymlでlanguage: phpを選択するとComposerがバンドルされたコンテナ上で任意のジョブを実行することが可能です。

ただし各PHPバージョンのジョブ実行ではcomposer.pharのリビジョンが違う可能性があります。

2015-11-09現在では以下のようになっていました。

PHP Version $ composer --version 備考
7 c557715
5.6 1d8f05f Warning: over 30 days old.
5.5 1d8f05f Warning: over 30 days old.

Capistrano/Composer

Remote multi-server automation toolであるCapistranoでは公式extensionとして Capistrano/Composerを提供しています。

Configuration章で言及されていますが、 composer_versionを指定することによって 任意のTaggging Versionを指定して利用することができます。

set :composer_version, '1.0.0-alpha11' #(default: not set)

まとめ

以上に書きました通り、Composerをどのバージョンのスタイルで利用するにしても一長一短ですので、 プロジェクトで利用する場合は両方を加味した上で

Latest, Tagging Versions どちらを選択するか(あるいは別の選択を)していただければと思います。

composer.lockだけでなく、Composer's versionも

  • 個々人の開発環境
  • CI Server
  • リリースプロセス

に大きく関係してくるので、

個人的にはself-update実行時にmaster branches HEADを取得するLatestよりも

Tagging Versionsを利用して常に同じバージョンを取得して利用していきたいところです。


最後にComposerのバージョン固定しつつ利用するmakefileを書いておきますね。

それでは皆様よきComposerライフを :p

PHP:=$(shell which php)
COMPOSER_VERSION=1.0.0-alpha11

.PHONY: install composer_selfupdate

install: composer_selfupdate
    $(PHP) composer.phar install -vv

composer_selfupdate: composer.phar
    $(PHP) composer.phar self-update $(COMPOSER_VERSION)

composer.phar:
    curl -sS https://getcomposer.org/installer | $(php) -- --version=$(COMPOSER_VERSION)

*1:typoじゃないデス

*2:Composerの最新版は現在色々な呼ばれかたがされていますが、このエントリではLatestと書くことにします

*3:https://github.com/composer/getcomposer.org/blob/ce3494b/.gitignore#l4-l5

*4:https://github.com/composer/composer/issues/3707#issuecomment-113433891

*5:https://github.com/composer/composer/blob/1.0.0-alpha10/src/composer/console/application.php#l108