Travis CIでテストを並列実行する場合に、全テストがパスしたときだけリリースタグを打つ方法を紹介します。
これは普通に実現できそうな内容に見えるかもしれませんが、これまでTravis CIではタスクの依存関係を定義することができませんでした。つまり、Build Matrixの仕組みを使って複数のテストジョブを並列実行した場合に、全テストの後続タスクとしてデプロイを実行するようなことは不可能でした1。
今回、Travis CIの新機能であるBuild Stages2を利用すれば要求を満たせることに気付いたので、実際に試してみたというわけです。
.travis.yml
の記述
既存の全テストジョブが成功したらGitでタグを打つための手順を紹介します。まずは、既存の.travis.yml
の末尾に次のように書いてください。
jobs:
include:
-
if: branch = master
stage: Push release tag
script: ./git-tag.sh
deploy: []
このようにすると、matrix:
で定義してある既存のテストは全て「test」ステージのジョブになり、その後続タスクとして「push release tag」ステージが実行されることになります。このステージではgit-tag.sh
が実行されます。
リリースタグを打つスクリプト
このgit-tag.sh
の中身は次のようなものです。
#! /usr/bin/env bash
# この時点で打つべきタグを決定して$TAGに代入しておく
# タグの情報源はgitのコミットログやプロジェクト内の設定ファイルなどが考えられる
TAG=${PKG_VERSION}-${PKG_RELEASE}
if [[ -n "$(git tag -l ${TAG})" ]]; then
echo "Already exist tag: ${TAG}"
echo "Do nothing."
else
git config --global "url.git@github.com:.pushinsteadof" "https://github.com/"
git config --global user.name "Travis CI"
git config --global user.email "travis@example.com"
mkdir -p $HOME/.ssh
chmod 700 $HOME/.ssh
openssl aes-256-cbc -K $encrypted_****_key -iv $encrypted_****_iv -in id_ecdsa.enc -out $HOME/.ssh/id_ecdsa -d
chmod 600 $HOME/.ssh/id_ecdsa
echo git tag $TAG
git tag ${TAG}
echo git push origin $TAG
git push origin ${TAG}
fi
見てわかる通り、git tag
してgit push
しています。pushの権限を与えるのにGitHubのdeploy keyの仕組みを利用しています。
deploy keyの準備
GitHubには「deploy key」という仕組みがあり、特定のプロジェクトに紐付くSSH鍵を登録することができます。deploy keyはGitHubに登録してある既存の鍵は使えないので、デプロイ専用の鍵ペアを新規作成して利用します。
$ ssh-keygen -t ecdsa -f /tmp/id_ecdsa
$ travis encrypt-file /tmp/id_ecdsa
ssh-keygenで指定するパスフレーズは空文字列にします。つまり、ここで作られる秘密鍵はパスフレーズで守られていないことになりますが、travis encrypt-file
により公開鍵暗号で暗号化されますので理屈上は安全です。
travis encrypt-file
を実行するとopenssl
の行が表示されますので、これを.travis.yml
に貼り付けた上で適宜修正します。また、カレントディレクトリにid_ecdsa.enc
ファイルが作られます3ので、これをGitリポジトリにコミットします。
さらに、対になる公開鍵id_ecdsa.pub
をGitのWeb管理画面からdeploy keyとして登録します。deploy keyはGitHubのプロジェクトページの「Settings」「Deploy keys」から登録できます。今回はtagをpushしたいので、「Allow write access」のチェックボックスをオンにする必要があります。
結果
上記の設定を行うと、masterへのコミットに対して、たとえば下記のように4並列のジョブが全部パスした後でタグだけを打つジョブが走ることになります。
設定にもよりますが、このようにタグを打つと再度Travis CI上でビルドが走るはずです。くれぐれも無限ループしないよう気をつけてください。このプロジェクトではタグを打ったときだけGitHub Releaseにデプロイするようにしてあるので、この仕組みにより手動でタグを打つ一手間が減ったことになります。
補足:こんな面倒なことをする理由
今回実現したかった内容は「masterでのビルドが通ったらGitHub Release上に生成物をデプロイしたい」というものです。
ただし、GitHub Releaseはその仕組み上、必ず対応するタグが必要になります。タグに対応するビルドが走るのは必須ということになります。
一方で、ビルドが通るかわらかないうちからタグを打つわけにいかないので、masterでのビルドも必須です。そこで、本稿で説明したように必ず2周ビルドする処理を組むことにしました。リソースの無駄遣いのような気もしますが、他にどうしようもないと思います。