flutterのバージョンをGitLab CI Runner上で動的に切り替える
この記事はFlutter Advent Calendar 2019 (#2)の記事です。
※12/21 8時時点で18日分に空きがあったので埋めさせていただきました(参考)
はじめに
GitLab CIを使ってFlutterのCI/CDをやっているのですが、CI環境において複数のFlutterのバージョンを管理する必要があり、少し悩んだので以下にまとめます。
GitLab CI Runnerは以下のような感じで、shellモードでMac mini上で動かしています。
今回、Flutterのバージョンアップの検証が必要になったのですが、すでに配信中のアプリで利用しているFlutterのバージョンに対してはバージョンアップが完了するまでの間に緊急パッチを宛てる可能性があります。そのため、緊急パッチのビルド時につかうFlutterのバージョンと、バージョンアップ検証で使うFlutterのバージョンをそれぞれのビルドで使い分ける必要があります。
検討した解決策
CI環境上で複数のflutterのバージョンを動作させる方法として、以下の2つ案を考えました。
- 配信版と追加開発をブランチを分けて、ブランチごとに固定のGitLab CI Runnerを割り当てる
- GitLab CIの実行時に使うバージョンを動的に切り替えられるようにする
メリット・デメリットは以下の通りです。
案1 |
|
|
案2 |
|
|
GitLab CIではCI Runnerにタグをつけることができ、tag
、only
、except
等を記述することで特定のブランチのジョブを特定のCI Runnerで実行させる、という設定ができます。
https://docs.gitlab.com/ce/ci/yaml/
しかしデメリットで書いた通り、普段の開発においてはfetuareブランチやhotfixブランチを切ったりリリースタグを切ったりとブランチの命名規則を複数考慮してgitlab-ci.yml
を設定するのはなかなか骨が折れます。
今回は設定が煩雑になることに加え、バージョンアップ版のリリースまでの移行期間のみ並行運用が走ること、また都度実行で増える実行時間が2-3分程度で待てるレベルであることを踏まえて2を選択することにしました。
実装
各ビルドで使うflutterのバージョンはpubspec.yamlに記載できるため、それを使ってflutterのバージョンを切り替えてからCIを実行するように.gitlab-ci.yml
を設定します。
... environment: sdk: ">=2.1.0 <3.0.0" flutter: 1.9.1+hotfix.6 ...
yamlから特定のキーの値を取得するのにはyq
が使えます。
pubspec.yamlに記載されたバージョンでflutterのversionを切り替えるシェルは以下のように記載できます。
#!/bin/sh set -x set -e # get tagert flutter version TARGET_FLUTTER_VERSION=`cat pubspec.yaml | yq -r .environment.flutter` TARGET_FLUTTER_VERSION_TAG_NAME=v${TARGET_FLUTTER_VERSION} CURRENT_DIR=`pwd` FLUTTER_DIR=${HOME}/development/flutter cd ${FLUTTER_DIR} # current version flutter --version # flutter checkout git checkout -f master git pull git checkout -f ${TARGET_FLUTTER_VERSION_TAG_NAME} flutter precache flutter doctor # updated version flutter --version cd ${CURRENT_DIR}
ポイントとしてはflutterのバージョンはpubspec.yamlにはvなしで記載されているのに対し、flutterのタグではv
がついているためgit checkoutするときに付与する必要があります。
flutterのバージョンの切り替えはflutter version
コマンドを使うこともできますが、これを実行するには対象のバージョンがあるchannelをflutter channel
で事前に指定し、かつupgradeを実行して最新化しておく必要があります。
最新化がされていなかったり、切り替えたいバージョンのchannelが異なっている場合はflutter versionコマンドは失敗してしまいます。
$ flutter version -f v1.13.3 There is no version: 1.13.3 Unable to checkout version branch for version 1.13.3.
なので、今回はflutterコマンドがインストールされている場所~/development/flutter
に移動し、master上でpullして都度タグをcheckoutする方式を取るようにしました。
チェックアウトした後はflutter precache
することで依存するライブラリが落ちてきます。
最後に↑のシェルを.gitlab-ci.yml
のbefore_script
の中で実行するように設定すれば完成です。
... before_script: - ./set-flutter-version.sh ...
似たような感じでxcode-select
すればXCodeのバージョンも指定できそうですね。
gradle wrapperやmaven wrapperでのバージョン指定、Docker buildなどと同様にビルドさせる環境のツールのバージョンはgitレポジトリに定義含めてしまって、CIの実行の度に動的に変えられるようにしておくと管理が便利になりますね。
あとはflutterのバージョン切り替えもDocker Buildみたいにキャッシュできたらいいのになー。