Travis CIで全テスト通ったら勝手にリリースタグを打って再度ビルドを走らせる方法


Travis CIでテストを並列実行する場合に、全テストがパスしたときだけリリースタグを打つ方法を紹介します。

これは普通に実現できそうな内容に見えるかもしれませんが、これまでTravis CIではタスクの依存関係を定義することができませんでした。つまり、Build Matrixの仕組みを使って複数のテストジョブを並列実行した場合に、全テストの後続タスクとしてデプロイを実行するようなことは不可能でした1

今回、Travis CIの新機能であるBuild Stages2を利用すれば要求を満たせることに気付いたので、実際に試してみたというわけです。

.travis.ymlの記述

既存の全テストジョブが成功したらGitでタグを打つための手順を紹介します。まずは、既存の.travis.ymlの末尾に次のように書いてください。

.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の中身は次のようなものです。

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 "[email protected]:.pushinsteadof" "https://github.com/"
    git config --global user.name "Travis CI"
    git config --global user.email "[email protected]"
    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周ビルドする処理を組むことにしました。リソースの無駄遣いのような気もしますが、他にどうしようもないと思います。


  1. テストを1並列で行うのであれば「テスト成功時のみデプロイ」は以前から実現可能です。deploy:セクションに書いた内容はscript:セクションのテストやビルドが成功したときだけ実行されます。 

  2. 2017年10月時点ではまだベータ版です。機能としてキャンセルされる可能性もゼロではないのでご注意ください。 

  3. ECDSA鍵を使っているのは個人的な趣味です。RSA鍵を使っても問題はありません。