フリーランスのためのネットビジネス専門学校 ネットで独立開業を目指す人を応援
フリーランスのためのネットビジネス専門学校 ネットで独立開業を目指す人を応援

GitLabで複数環境でのテストを簡素に書く

GitLab.comにはGitLab-CI/CDが一緒になっているので、ライブラリ・パッケージ開発にも重宝してるのですが、悩ましいのが「バージョンのサポート」です。
それでも、変に新しすぎる機能を突っ込んでやや古いぐらいのバージョンに対応できるのは避けたいので、なるべく多くのバージョンでのテストを行うのが望ましいですね。

Travis-CIだと、テスト時の言語バージョンを割と簡単に複数指定できるのですが、GitLab-CI/CDだとどれだけ簡素にかけるかを少し調べてました。

TL;DR

  • YAMLのアンカーとエイリアスが普通に使えるので、使いましょう。
  • 具体例は、 「テストのみの処理」を共通化する(before_scriptは使わない)

以降の例

  • ちょっと個人的興味を兼ねて手を出している、「PHPのEOLでないバージョン全てで動くパッケージを作る」でサンプルコードを書いてます
    • 基本的にはどんな言語でもいけるはず
  • テストコードとかも全く出す予定もなく、基本的にはYAMLが続きます

(ここからが本文)

まずは最新バージョンのテストジョブを定義する

.gitlab-ci.yml
phpunit:
  image: php:7.2-cli-alpine
  script:
    - apk add git
    - curl https://getcomposer.org/download/composer.phar > composer.phar
    - php composer.phar install
    - vendor/bin/phpunit --bootstrap vendor/autoload.php

普通ですね。
GitLab-CI/CDは他のCIサービスなどと同じような感じで、.gitlab-ci.ymlにジョブを定義すると、git pushをトリガージョブが走ります。 1

複数バージョンに雑に対応させる

一番最初のケースではPHP 7.2での動作を前提としていますが、PHP7.1での動作もちゃんと保証させたいとします。
とりあえず、雑にジョブを増やしてみましょう。

.gitlab-ci.yml
phpunit-7.2:
  image: php:7.2-cli-alpine
  script:
    - apk add git
    - curl https://getcomposer.org/download/composer.phar > composer.phar
    - php composer.phar install
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

phpunit-7.1:
  image: php:7.1-cli-alpine
  script:
    - apk add git
    - curl https://getcomposer.org/download/composer.phar > composer.phar
    - php composer.phar install
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

コピペするとすごく手早く増やせます。
ジョブの名前をphpunit-(PHPのバージョン)にしておくことで、分かりやすいようにしておきましょう。
これぐらいだと、特にそんなに面倒な印象はありませんね。

さて、このままPHP 7.0, 5.6まで範囲を広げると、こうなります。

.gitlab-ci.yml
phpunit-7.2:
  image: php:7.2-cli-alpine
  script:
    - apk add git
    - curl https://getcomposer.org/composer.phar > composer.phar
    - php composer.phar install
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

phpunit-7.1:
  image: php:7.1-cli-alpine
  script:
    - apk add git
    - curl https://getcomposer.org/composer.phar > composer.phar
    - php composer.phar install
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

phpunit-7.0:
  image: php:7.0-cli-alpine
  script:
    - apk add git
    - curl https://getcomposer.org/composer.phar > composer.phar
    - php composer.phar install
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

phpunit-5.6:
  image: php:5.6-cli-alpine
  script:
    - apk add git
    - curl https://getcomposer.org/composer.phar > composer.phar
    - php composer.phar install
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

うーん、かなり冗長ですね。
これ以上なにもしないなら問題はそこまで大きくはないです。
ただ、特殊なPHP拡張も必要なケースがあった場合は、毎回4箇所編集しないと駄目なのでよくありません。2

ジョブで共通する処理はまとめる

.gitlab-ci.yml
before_script:
  - apk add git
  - curl https://getcomposer.org/composer.phar > composer.phar
  - php composer.phar install

phpunit-7.2:
  image: php:7.2-cli-alpine
  script:
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

phpunit-7.1:
  image: php:7.1-cli-alpine
  script:
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

phpunit-7.0:
  image: php:7.0-cli-alpine
  script:
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

phpunit-5.6:
  image: php:5.6-cli-alpine
  script:
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

GitLab-CI/CDでは、全ジョブの実行時に各ジョブのscriptより前に実行したい共通処理をbefore_script上に書くことができます。
これによって、「テスト時に同じ処理を共通化して編集コストを減らす」ことが実現できます 3

テスト以外があったら?

GitLab-CI/CDはCIだけでなくCDも視野に入れています。
だからというわけではないのですが、

  • パッケージのリリースもGitLab-CI/CDを止めたい
  • ユニットテストの前に文法チェック(php -lphanなどなど)をやってNGならパイプラインを止めたい

などなど、単純なテスト以外のジョブも混ざってきます。
となってくると、before_scriptにいろいろ詰め込みすぎると「リリースには全く必要がないのに、composer installをしないといけない」などという事態になって、よろしくありません。

「テストのみの処理」を共通化する(before_scriptは使わない)

.gitlab-ci.yml
phpunit-7.2: &phpunit-latest
  image: php:7.2-cli-alpine
  script:
    - apk add git
    - curl https://getcomposer.org/composer.phar > composer.phar
    - php composer.phar install
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

phpunit-7.1:
  <<: *phpunit-latest
  image: php:7.1-cli-alpine

phpunit-7.0:
  <<: *phpunit-latest
  image: php:7.0-cli-alpine

phpunit-5.6:
  <<: *phpunit-latest
  image: php:5.6-cli-alpine

YAMLには「アンカー」と「エイリアス」という仕様があり、「&でアンカーを定義」「*でエイリアスとしてアンカーのデータ構造をまるっと参照」が可能です。
これによって、<<: *(名前)によるアンカー先のデータをそのまま使いまわせるため、scriptを記述せずにジョブを増やす」ことが可能になります。

こんなことも可能です。(PHPのバージョンは同じだけど、 composerのバージョンを変える例)

.gitlab-ci.yml
phpunit-7.2: &phpunit-latest
  image: php:7.2-cli-alpine
  variables:
    COMPOSER_VERSION: 1.7.2
  script:
    - apk add git
    - curl https://getcomposer.org/download/${COMPOSER_VERSION}/composer.phar > composer.phar
    - php composer.phar install
    - vendor/bin/phpunit --bootstrap vendor/autoload.php tests/

phpunit-7.2-composer-1.6.5:
  <<: *phpunit-latest
  variables:
    COMPOSER_VERSION: 1.6.5

これによって、「Laravelの複数バージョンにも対応している何か」も比較的テストしやすくなります。4

まとめ

ライブラリ開発のテストをCIなどでやると、記述内容の重複が起こってしまうケースがあります。
特に「Webアプリケーションフレームワークの拡張」を目的としたライブラリなどを開発していて、
可能な限り守備範囲を広げようとすると、言語バージョンxFWバージョンの掛け算でパターン数が爆発します。
YAMLの機能をきちんと使うことで、DRYでいけそうなシーンで適切にDRYな設定が書けるので、よりスリムなYAMLを目指したいと思います。

余談

phpunit-multiple-versions-in-gitlab-ci.png

前段で作ってるパッケージについて、ローカルで最低限のテストをパスしたプロジェクトを作って、↑の.gitlab-ci.ymlでCIを流した結果がこちら。
(テストコードの側で)PHP7.2から使えるメソッド使ってたりしてて、いきなり複数バージョン対応の大変さを思い知らされました。 5

外部リンク/参考情報など


  1. 最近は別のファイルを指定できるらしいですが、今回は触れません 

  2. 超余談ですが、この記事を書いてるタイミングで、テストジョブのスクリプトの間違いに気づいて、今まさに全部編集して良くないことになりました。 

  3. ただし、各ジョブごとにscriptを空にすることはできないので、「全く同じコマンド」しかなくても、何かしらscriptを書く必要があります。 

  4. さらに、ジョブ内でbefore_scriptの定義もできるため、「バージョン間で事前準備がほんの少しだけ違う」にも対応可能なはず 

  5. その他、PHPUnitのバージョン対応問題とか、関数定義時の型宣言の対応量とか、敵が多いです 

[紹介元] PHPタグが付けられた新着投稿 – Qiita GitLabで複数環境でのテストを簡素に書く

コメント

記事に戻る

コメントを残す