以前に書いたRedmineプラグインをGitHub Actionsでテストするでの、以下の問題点を解消するために、Dockerイメージを使用した形に改良したまとめです。
- パッケージやRedmine自体のインストールも都度行われるため、時間がかかる。
- actions/setup-rubyで、Ruby v2.3.xはインストールできない。
改良後の結果
Redmine Auto Assign Group Pluginのテストを行うワークフローでの結果です。
テストにかかる時間
Redmine Auto Assign Group Pluginのテストに、GitHub ActionとしてRedmine plugin test actionを使用しています。改良前のv1と改良後のv2での比較は以下の通りで、大きく改善できました。
対象 | 実行時間(m:ss) | v1-v2 |
---|---|---|
v1(改良前) | 6:28 | ------ |
v2(改良後) | 2:33 | 3:55 |
※記事を書いている時点で最新の成功ビルド5件ずつの時間から、最大最小を除いた3件の平均で算出。
※Redmine-Rubyの組み合わせ10環境、テストは49 runs, 244 assertionsでMiniTestを使用。ただし、v1ではRuby v2.3.xは使用できないため、v2.3.xは除いた場合。
Ruby v2.3.xでのテスト
dockerhubのruby:2.3-slimベースのイメージを作成することで、テストできるようになりました。
改良内容
Redmine plugin test actionのv1は、Github Actionsのubuntu-latestに対して環境を作っていくものでした。これだとテストまでの準備に時間がかかるため、あらかじめRedmineをインストールしたテストを実行するイメージをDockerHubに作成しておき、その上でプラグインのテストを実行する動きにしました。
流れをまとめると以下のとおりです。
プラグインのGitHubアクションワークフロー → DockerHubからイメージ取得 → プラグインのテスト実行
プラグインのGitHubアクションワークフロー
Redmine Auto Assign Group Pluginでの変更は、このコミットのような感じです。
環境構築のための定義はバッサリなくなり、RedmineとRubyのバージョン、プラグイン名の指定のみとなりました。これに伴って、GitHubアクションとしてパラメータが変更になったため、v2に変更しています。
DockerHubからイメージ取得
ベースのなる環境は、DockerHubのrubyのslimイメージを元にして、RedmineとChrome、ChromeDriverをインストールしたイメージを作っています。行っている事自体は、v1と同じです。DBはPostgreSQL, MySQL, sqlite31。Dockerfileのリポジトリはここ、DockerHubはここです。
RedmineとRubyのバージョン組み合わせの作成
以下の記事がとても参考になりました。
dockerhubのautomated buildで任意のdocker buildコマンドを利用し、単一のDockerfileから設定を動的に変えて複数イメージをビルドする
DockerHubのビルド設定で行ったタグ名を元に、フックでRedmineとRubyのバージョンを取得して、ビルドを行っています。フックは以下のようなものです。
#!/bin/bash
set -eux
LIST=(${DOCKER_TAG/_/ })
RUBY_VERSION=${LIST[1]/ruby/}
REDMINE_VERSION=${LIST[0]//trunk/master}
LIST=(${REDMINE_VERSION//[.-]/ })
if [ ${#LIST[*]} -eq 2 ]; then
LATEST_VER=LATEST_${REDMINE_VERSION/./_}
if [ ${LATEST_VER} != "" ]; then
eval REDMINE_VERSION=\$$LATEST_VER
fi
fi
docker build --build-arg REDMINE_VERSION=${REDMINE_VERSION} --build-arg RUBY_VERSION=${RUBY_VERSION} -f $DOCKERFILE_PATH -t $IMAGE_NAME .
DOCKER_TAG に、DockerHubのタグ名が入ってきます。 4.1_ruby2.6 などのような規則にしておき解析することで、バージョンを決定して以下のようにDockerfileへARGで渡しています。
ARG RUBY_VERSION
FROM ruby:${RUBY_VERSION}-slim
ARG REDMINE_VERSION
DockerHubのビルド設定は、 Builds - Configure Automated Builds の BUILD RULES に以下のような感じで追加しています。Sourceはすべてmasterにしていますが、 Docker Tag を変えて複数登録することで、組み合わせでイメージをビルドできます。
GitHubアクションからのイメージ使用
実際にテストを行うGitHubアクションである、Redmine plugin test actionは、Dockerコンテナのアクションとして作成するつもりでした。プラグイン側のアクションから受け取ったパラメータでDockerHubのイメージを指定できるかと思ったのですが、ARGの受け渡しができず、うまくいきませんでした。
このため、v1と同じくシェルスクリプトをキックして、DockerHubのイメージをベースにしたDockerfileをビルド、起動する形にしています。シェルスクリプトはこれです。
GitHubのブランチ名の取得は環境変数から取得しますが、プルリクの場合とブランチへのコミットの場合で分けて取得する必要がありました。
if [ "${GITHUB_HEAD_REF}" = "" ]; then
PLUGIN_BRANCH=$(echo ${GITHUB_REF#refs/heads/})
else
PLUGIN_BRANCH=${GITHUB_HEAD_REF}
fi
あとはDockerfileにブランチ名やアクションのパラメータを渡してビルド、実行します。
docker build -t redmine-plugin-test \
--build-arg REDMINE_VERSION=${REDMINE_VERSION} \
--build-arg RUBY_VERSION=${RUBY_VERSION} .
docker run -e "GITHUB_REPOSITORY=${GITHUB_REPOSITORY}" \
-e "PLUGIN_NAME=${PLUGIN_NAME}" \
-e "PLUGIN_BRANCH=${PLUGIN_BRANCH}" \
-e "DATABASE=${DATABASE}" \
-t redmine-plugin-test
プラグインのテスト実行
テスト自体はDockerfileのENTRYPOINTで実行するシェルスクリプトに書いています。
インストール→テスト→アンインストール のrakeを実行する内容になっています。
まとめ
Redmine Auto Assign Group Pluginでの結果は、以下のような感じです。
Redmine plugin test actionのv1に比べて、だいぶ実行時間を短縮できました。プラグイン側のワークフローもシンプルになったので、使いやすくなったのではと思います。
-
2020/04/04編集:v2.0.1でPostgreSQL、MySQL(MariaDB)にも対応しました。 ↩