Travis CIからGitとSubversionのリポジトリへコミットする

Travis CIを用いて、GitとSubversionのリポジトリの両方へコミットするプラクティスです。
例えば、公式リポジトリで公開しているWordPressテーマ・プラグインをGitで管理していてGithubに公開しており、Subversionには触りたくない、というようなケースで有効だと思います。

準備

Gitリポジトリの用意

このポストの方法で管理する、あなたのGitリポジトリです。パスやURLを読み替え、適当に用意してください。

# 新しいGitリポジトリを作成
$ cd path/to/repo
$ git init
## ここまでに、Githubでリポジトリ{user}/{repo}を作っておく
$ git remote add origin git@github.{user}/{repo}.git
$ git add .
$ git commit -m"Initialize"
$ git push origin master

このインタラクションでは新規にGitリポジトリを作成しましたが、既存のものでも問題ありません。
これ以降は、このリポジトリのディレクトリをカレントディレクトリとして話を進めます。
また、このプログラムをコミットする予定のSubversionへアクセスするためのユーザー名とパスワードを用意して下さい。

Githubのアクセストークンの取得

Github右上の自分のアイコンから、[Settings]を選択し、左のメニューから[Personal access tokens]を選択します。
生成済みトークンの一覧が表示されますので、右上の[Generate new token]ボタンをクリックして新しいトークンの生成を開始します。このリンクからも移動できますよ。

アクセストークンの生成を開始

Select scopeの項目で、アクセストークンに許可する権限の範囲を設定します。ここでは、public_repoにアクセスする権限を与えています。権限が正しく設定されていることを確認したら、[Generate token]のボタンからアクセストークンを生成してください。

アクセストークンへの権限設定

これでアクセストークンが生成されました。この値を誰かに漏らしてしまうと、Github上のあなたの公開リポジトリすべてにコミットを許してしまうことになるので、細心の注意で扱ってください。なお、画像のトークンは当然無効化済みです。また、不要になったトークンはこまめに消しておくといいでしょう。

アクセストークンが生成される。
アクセストークンが生成される。

Githubへの公開鍵の登録、Travis CIへのサインイン

以降では、おそらく公開鍵認証が必要なので、Githubへあなたの公開鍵を登録しておいて下さい。
これについては、インターネット上に色々記事があります。

gitHubでssh接続する手順~公開鍵・秘密鍵の生成から~

また、Travis CIは、Githubアカウントでサインインできますのでしておいてください。

セキュアな情報の暗号化

travis CIのCLIツールを用います。インストールしていない場合はインストールします。

$ gem install travis

 

インストールしたtravisコマンドを用いて、先ほど取得したアクセストークンや、Subversionの認証情報など、セキュアな情報を暗号化します。travis encryptコマンドにはスペース区切りで複数の値を渡すことができ、その後暗号化された値が帰ってきます。この暗号フレーズは、Travis CIの設定ファイルである.travis.ymlに記載することで、Travis CI上のコンテナで環境変数として復号されます。

$ travis encrypt "GH_TOKEN=9cddef762c2a8737211a20fdf164fc3d90185b8e SVN_USER=xxxx SVN_PASS=xxxx"
Detected repository as {user}/{repo}, is this correct? |yes| yes
Please add the following to your .travis.yml file:

  secure: "i0w26DXbGUd.." # 本当はもっと長いですよ

私はMac用にtravis encryptの簡単なラッパースクリプトを作成して暗号フレーズを生成しています。

#! /usr/bin/env bash

# [name] Travis Encrypt WP
# [description] Encrypt GH_TOKEN, SVN_USER and SVN_PASS at once
# [usage] bash travis-encrypt-wp.sh {GH_TOKEN} {SVN_USER}
# [dependency] Run on Mac. It uses keychain to find svn password
service=" Use your WordPress.org login"
GH_TOKEN=$1
SVN_USER=$2
SVN_PASS=`security find-generic-password -wgs "$service" -a$SVN_USER`
travis encrypt "GH_TOKEN=${GH_TOKEN} SVN_USER=${SVN_USER} SVN_PASS=${SVN_PASS}"

上記のスクリプトは、Githubのアクセストークンとplugins.svn.wordpress.orgのユーザー名を与えると、MacのKeychainからplugins.svn.wordpress.orgのパスワードを取得し、これら全てをtravis encryptします。
repository not knownが帰ってきた場合は、Travis CIのUI(https://travis-ci.org/profile/{user})から、Githubリポジトリを同期して、その後Travis CIのインテグレーションを有効化してあげてください。Travis CIへのサインインが済んでいれば、右上のユーザー名のメニューからたどり着けるはずです。

Githubリポジトリの同期
Githubリポジトリの同期
GithubへのTravisCIのフックを有効化
GithubへのTravisCIのフックを有効化

Travis CIの設定

Travis CIの設定ファイルを作成します。

$ travis init
Main programming language used: |PHP| 
.travis.yml file created!
{user}/{repo}: enabled :)

必要な情報を記載していきます。次の例ではリダイレクトしていますが、テキストエディタで編集してももちろん構いません。

# テストスクリプト、ビルド成功後のスクリプトや、環境変数を追記
scripts:
  - ls .
  - echo "ここでテストやビルドのコマンドが実行できます"
  - echo "何もスクリプトを渡さないと、言語固有のテストが走る様です。PHP: PHPUnit"
   - echo "テストが設定されていないとエラーを吐いてビルドがこけるので、lsコマンドか何かをとりあえず入れておきましょう"
after_success:
  - bash bin/deploy.sh
env:
  global:
    - GH_REF: github.com/{user}/{repo}.git
    - SVN_REF: {SubversionのURL} # WordPressプラグインの例 https://plugins.svn.wordpress.org/{plugin-slug}/
    - secure: \"i0w26DXbGUd..\" #先ほど取得した、暗号化された環境変数
" >>./.travis.yml

後は、設定した環境変数や、Travis CIが渡してくれる環境変数を使って、シェルスクリプトを書いていくだけです。

$ mkdir ./bin
$ vi ./bin/deploy.sh


#! usr/bin/env bash

# masterブランチ以外へのプッシュや、Pull Requestだった時はデプロイを実行しない
if [[ ("master" != "$TRAVIS_BRANCH") || ("false" != "$TRAVIS_PULL_REQUEST") ]]; then
  exit 0
fi
RELEASE_DIR=$(pwd)

# Gitの操作
## Gitリポジトリの初期化
rm -rf ./.git
rm ./.travis.yml # 無限にビルドされてしまうのを防ぐ
git init
git config user.name "{user}"
git config user.email "{user}@travis-ci.org" # この値は適当でも問題ありません
## 強制的にlatestブランチにプッシュ
git add .
git commit --quiet -m "Deploy from travis."
git push --force --quiet "https://${GH_TOKEN}@${GH_REF}" master:latest > /dev/null 2>&1

# Subversionの操作
# 新しくディレクトリを切り、リポジトリをチェックアウト
rm -rf ./.git
cd "$(mktemp -d)"
svn co --quiet "$SVN_REF"
cd "$(basename "$SVN_REF")"
## 一旦空にする
find ./trunk -type d -name ".svn" -prune -o -type f -print | xargs -I% rm -r %
## 先ほどGithubにプッシュしたディレクトリからコピー
cp -r "$RELEASE_DIR"/* ./trunk
## バージョニングの更新
svn st | grep "^!" | sed -e "s/\![ ]*/svn del -q /g" | sh
svn st | grep "^?" | sed -e "s/\?[ ]*/svn add -q /g" | sh
# コミット
svn ci --quiet -m "Deploy from travis." --username "$SVN_USER" --password "$SVN_PASS" --non-interactive > /dev/null 2>&1

それから、Travis CI側で、リポジトリの設定(https://travis-ci.org/{user}/{repo}/settings)から、.travis.ymlがない場合はビルドしないように設定しましょう。
Travis CIからのプッシュに再度Travis CIが発火し、無限ループしたりするかもしれません。

.travis.ymlがあるときだけビルドする
.travis.ymlがあるときだけビルドする

こんな感じでうまくいくと思います。
以上の準備が整ったら、masterブランチからpushしてうまく動作しているか確認します。

$ git add .
$ git commit -m"Add Travis CI settings"
$ git push origin master

用例

同様の方法で運用しているWordPressプラグインのリポジトリを例示します。
KamataRyo/oembed-travis@Github
このポストで紹介しているものよりやや複雑なスクリプトを使っており、以下のような感じで、デプロイがなされていきます。
https://travis-ci.org/KamataRyo/oembed-travis/jobs/135581728#L409

スクリプト類はまとめてここに置いてあり、curlで取得して実行します。
KamataRyo/travis-scripts-collection@Github

注意点

この方法には幾つか注意点があります。
Githubのアクセストークンは暗号化されていますが、Travis CIでのビルドプロセスでは復号され、環境変数として展開されています。
travis-ci.orgのビルドログはすべて公開されるので、決してecho "$GH_TOKEN"などしてはいけません。
また、Subversionのパスワードも展開されています。アクセストークンについては、リポジトリごとに1つづつ発行できますが、こちらについてはすべてのリポジトリで使いまわすことになり、間違って暴露してしまうリスクは大きくなります。その際は、すべてのリポジトリの.travis.ymlを修正することになり、かなり面倒でしょう。
これらの注意点をよく理解したうえで、CIツールの設定を行うことをお勧めします。