Travis CI 上の環境変数（PULL_REQUEST, BRANCH, TAG）を使って、ワークフローの改善とリリース自動化を実現する

`CI` を中心としたワークフローやリリース（デプロイ）自動化システムを構築するには、現在対象としているコードベースの状態を把握する必要があります

- ブランチは、feature か master か
- プルリクエストをマージしたのか
- タグはついているのか

`Travis CI` でそれらを把握するためには表題にある 3 つの環境変数の意味と組み合わせを理解しないと出来ないのですが、まとまった公式のドキュメントやネット上のレファレンスが見つからなかったので書きます

![http://aniszczyk.org/2012/04/05/travis-ci/ より引用](https://qiita-image-store.s3.amazonaws.com/0/24932/8930d563-87ae-f679-5983-6879bc670a66.png)

http://aniszczyk.org/2012/04/05/travis-ci/ より

# Travis CI を使ったリリース自動化の例

例えば、[最近試した iOS のプロジェクト](https://github.com/yoheimuta/mtburn-ios-sdk-demoapp)では、次のような、Travis CI を使った比較的複雑な、ワークフローの構築とリリース自動化を行いました

- なぜこうしているのかという意図などは、リンク先の [README](https://github.com/yoheimuta/mtburn-ios-sdk-demoapp) にある程度詳細に書いているのでご参照ください

### feature ブランチを master ブランチに対してプルリクエストした場合

- `テスト`する
- `ビルドしてバイナリを生成`する
- そのバイナリをチームメンバーがインストールできるホスティングサービスに`デプロイ`する

### feature ブランチを master ブランチにマージした場合

- プルリクエストした場合とやることは同じ
- ただし、`デプロイ先アドレスは変える`（= マスターブランチから生成したバイナリとフィーチャーブランチから生成したバイナリは分けてホスティングする）


### タグをつけたコミットをプッシュした場合

- `テスト、ビルド、ホスティングサービスにデプロイ` までは同じ（マージの時と同じようにデプロイ先アドレスは変える）
- 次に、`GitHub Releases に生成したバイナリをデプロイ`する
- さらに、このレポジトリに依存したレポジトリのリリース作業も行っていく
 - 依存レポジトリの `appledoc 更新、バージョン番号の更新、コミット、マスターにプッシュ`する
 - 依存レポジトリの `GitHub Pages を更新`する
 - 依存レポジトリを `GitHub Releases に公開`する

# 状態を把握するために、.travis.yml で参照できる 3 つの環境変数

上記に書いたような、場合分けを伴うリリース自動化をするために参照する環境変数は次の 3 つです（これらの環境変数は、Travis CI 側で値を設定しているものです）

- `TRAVIS_PULL_REQUEST`
- `TRAVIS_BRANCH`
- `TRAVIS_TAG`

### TRAVIS_PULL_REQUEST

型

- 文字列

取りうる値

- false
 - プルリクエストではない場合
- 1 など
 - プルリクエストである場合
 - プルリクエスト番号が入る

### TRAVIS_BRANCH

型

- 文字列

取りうる値

- master や feature1 など
 - タグのプッシュではない場合
 - ブランチ名が入る
- v1.0.0 など
 - タグのプッシュである場合
 - タグ名が入る

### TRAVIS_TAG

型

- 文字列

取りうる値

- 空白
 - タグコミット（= タグプッシュ）ではない場合
- v1.0.0 など
 - タグコミット（= タグプッシュ）である場合
 - `git tag` でつけたタグ名が入る

# Git / GitHub 上での操作を例に、3 つの環境変数の組み合わせをまとめる

- GitHub 上で Travis CI と連携している前提です
- 運用フロー（≒ ワークフロー）は、[GitHub Flow](https://gist.github.com/Gab-km/3705015) を採用している前提です
 - ただし、iOS などネイティブアプリを念頭に置いているので、master をすぐにリリースするわけではなく、リリースはタグをつけて別に行うという点は注意ください
- 仮に、feature ブランチ名を `created-readme` とする
- 仮に、プルリクエスト番号を `8` とする
- 仮に、タグ名を `v10.0.13` とする

### feature ブランチをプッシュした

- `git push origin created-readme` などした場合に実行されます
- `continuous-integration/travis-ci/push` と表示されているのはこれです
- https://travis-ci.org/yoheimuta/mtburn-ios-sdk-demoapp/builds/52122672#L170

| TRAVIS_PULL_REQUEST | TRAVIS_BRANCH | TRAVIS_TAG |
| --- | --- | --- |
| "false" | "created-readme" | "" |

### feature ブランチのプルリクエストを master ブランチに出した

- GitHub 上で p-r ボタンを押したりした場合に実行されます
- `continuous-integration/travis-ci/pr` と表示されているのこれです
- https://travis-ci.org/yoheimuta/mtburn-ios-sdk-demoapp/builds/52122736#L175

| TRAVIS_PULL_REQUEST | TRAVIS_BRANCH | TRAVIS_TAG |
| --- | --- | --- |
| "8" | "master" | "" |

### feature ブランチを master ブランチにマージした

- GitHub 上の p-r ページでマージボタンを押したときに実行されます
- https://travis-ci.org/yoheimuta/mtburn-ios-sdk-demoapp/builds/53778003#L174

| TRAVIS_PULL_REQUEST | TRAVIS_BRANCH | TRAVIS_TAG |
| --- | --- | --- |
| "false" | "master" | "" |

### タグをプッシュした

- `git tag -a v10.0.13 -m"version up" && git push --tags origin master` などした場合に実行されます
- https://travis-ci.org/yoheimuta/mtburn-ios-sdk-demoapp/builds/52851779#L187

| TRAVIS_PULL_REQUEST | TRAVIS_BRANCH | TRAVIS_TAG |
| --- | --- | --- |
| "false" | "v10.0.13" | "v10.0.13" |

### 注意点

- feature ブランチのプルリクエストを master ブランチに出したときに、`TRAVIS_PULL_REQUEST` が `8` で `TRAVIS_BRANCH` が `created-readme` でも実行されるのかなと思ったのですが、されません

# 最後に

参考になるかもしれない、蛇足を書きます

### タグをプッシュするときの例

- `make release NEXT_VERSION=1.0.1` 
 - ファイル中のいくつかのバージョン番号を置換して、タグをつけてプッシュします
- https://github.com/yoheimuta/mtburn-ios-sdk-demoapp/blob/master/Makefile から抜粋

```mf
release:
	if [ -z "$(NEXT_VERSION)" ] ; then exit 1; fi
	$(eval CURRENT_VERSION := $(shell echo $$(git for-each-ref --sort=-taggerdate --format="%(tag)" refs/tags | head -n 1 | sed -e "s/v//")))
	git checkout master
	sed -i '' -e"s/$(CURRENT_VERSION)/$(NEXT_VERSION)/g" \
		DemoApp/DemoApp-Info.plist
	git add .
	git commit -m"Updated version to v$(NEXT_VERSION)"
	git tag -a v$(NEXT_VERSION) -m"Updated version to v$(NEXT_VERSION)"
	git push --tags origin master
```

### .travis.yml にて、環境変数を使った例

- やっていることは、`Travis CI を使ったリリース自動化の例` にあるとおりです
- 補足する点があるとすれば、`before_deploy -> deploy -> after_deploy` までを実行するかどうかの判定は、Travis CI 側で `TRAVIS_TAG` が空でないかどうかで勝手に行ってくれています
 - http://docs.travis-ci.com/user/deployment/releases/ に仕様が書いてあります
- https://github.com/yoheimuta/mtburn-ios-sdk-demoapp/blob/master/.travis.yml から抜粋

```yaml
before_script:
  - '[ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" != "false" ] && MTB_PR=1 || echo "This is master or not PR"'
  - '[ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && MTB_MERGE_MASTER=1 || echo "This is not master or PR"'
  - 'DEPLOYGATE_MESSAGE=$(git rev-parse --short HEAD)'
  - '[ "$MTB_PR" ] && DEPLOYGATE_MESSAGE+=#"$TRAVIS_PULL_REQUEST" || echo "Not append PR number"'
  - echo TRAVIS_BRANCH=${TRAVIS_BRANCH}
  - echo TRAVIS_PULL_REQUEST=${TRAVIS_PULL_REQUEST}
  - echo TRAVIS_TAG=${TRAVIS_TAG}
  - echo MTB_PR=${MTB_PR}
  - echo MTB_MERGE_MASTER=${MTB_MERGE_MASTER}
  - echo DEPLOYGATE_MESSAGE=${DEPLOYGATE_MESSAGE}

script:
  - make test
  - '[ "$MTB_PR" ] && make append-pr-to-bundleid || echo "Not append -pr to bundleid"'
  - '[ "$MTB_MERGE_MASTER" ] && make append-master-to-bundleid || echo "Not append -master to bundleid"'
  - '( [ "$MTB_PR" ] || [ "$MTB_MERGE_MASTER" ] || [ "$TRAVIS_TAG" ] ) && make ipa || echo "Skip to make ipa"'
  - '( [ "$MTB_PR" ] || [ "$MTB_MERGE_MASTER" ] || [ "$TRAVIS_TAG" ] ) && make deploygate DEPLOYGATE_MESSAGE="$DEPLOYGATE_MESSAGE" || echo "Skip to make deploygate"'

after_success:
  - make send-coverage

before_deploy:
  - 'NEXT_VERSION=$(echo ${TRAVIS_TAG} | sed -e "s/v//")'
  - echo NEXT_VERSION=${NEXT_VERSION}
  - make release-public-repo NEXT_VERSION=$NEXT_VERSION

deploy:
  provider: releases
  api_key:
    secure: gvj2V09zMPsHDPhNoQCpP4ouMUqq7mdq7g2l79dRSTOqGh/diJpgRWKCOZdZ5hYibpe0ynDckixS3ZLyPGhsvx7qfCxNcWDpdmtZtSSv7yuoc3PEbV56QtFfaoCCJacHWohKjRd2+hymDs6bxfPQ3WjnaMAbA48CdEY3QQEftpg=
  file: DemoApp.ipa
  skip_cleanup: true
  on:
    repo: yoheimuta/mtburn-ios-sdk-demoapp
    tags: true
    all_branches: true  # https://github.com/travis-ci/travis-ci/issues/1675

after_deploy:
  - gem install dpl
  - make deploy-public-repo
```

### iOS のリリース自動化に関連して、cocoapods ライブラリのリリースについて

https://github.com/yoheimuta/mtburn-ios-sdk-demoapp#only-manual-operation-to-be-required に書いたのですが、2015/03/07 まではできませんでしたが、`COCOAPODS_TRUNK_TOKEN` という環境変数を使うことで、Travis CI などの CI を使ったリリースが出来るようになりました

- 手元で出来ることは確認しました
- 以前、自分がやろうとしたときに出来ないことを確認するのはけっこう大変だったので、メモ書き程度ですがひとこと書きました（最近追加されたので、出来ないままだと思っている人もいるかもしれないので）

### Travis CI に関連して、Caching Ubuntu packages に `http://packages.treasuredata.com` が加わってます

2015/02/09 まで、`cache apt:true` を追加すると、`sudo curl -L http://toolbelt.treasuredata.com/sh/install-ubuntu-precise-td-agent2.sh | sh` が失敗していたと思います

- travis が管理している cached APT repositories に http://packages.treasuredata.com が含まれていなかったためです
- http://docs.travis-ci.com/user/caching/#Caching-Ubuntu-packages にメールしてくれと書いてあるのでメールしたら追加してくれたので、今は `cache apt:true` しても失敗しません（docs の url リストにはなぜかまだ追加されていないですが）
- 前に 1 回やろうとしてこれを理由に apt キャッシュを見送った経緯もあるので（そのときの担当は自分でないので予想ですけど）、共有する場所もないので、メモ書き程度ですがひとこと書きました