Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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のバージョン対応問題とか、関数定義時の型宣言の対応量とか、敵が多いです 

attakei
東京湾岸にて勤務中。 【公私】主にインフラ・サーバサイドWeb担当。Pythonista 【他】徒歩バカ
nijibox
ニジボックスの開発は、社内のUI/UXデザインチームと連携をとりながらワンストップで行う開発支援サービスです。Reactを始めPHP(Laravel)・Ruby on Rails、Swift・Kotlinを使った開発実績も多く、バックエンドからアプリまで幅広く対応しています。Twitterで情報発信しています: https://twitter.com/nijibox_jp
https://nijibox.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした