CircleCIでリリースブランチを作成しGitHubにPushする

# 何で？
通常web系のビルドタスクとかminify化は作業環境上で行ってpushすることが多いんで、こういったサイクルは自分ではあまりやらないです。
だけど、チームにデザイナーさんとか非エンジニア職の人がいる場合、作業環境を無理に揃えるよりもハードルが低くて良い選択肢になるんじゃないかと。

# CircleCI側の設定
CircleCIは使い始めた時点でGitHubと連携してるので、設定なしでGitHubにpush出来る予感がしたんですが気のせいでした。

CircleCI側の秘密鍵はリポジトリに対してread権限しか持ってないのでpushできません。
なのでwrite権限を持った秘密鍵を用意して別途登録する必要があります。

```sh:SSH設定リンク
https://circleci.com/gh/<ユーザor組織名>/<リポジトリ名>/edit#ssh
```
用意した秘密鍵は上記から追加できます。

今回の場合は`Hostname`に`github.com`を設定し`Private Key`に秘密鍵の内容をコピペして登録すれば完了です。

# circle.ymlのサンプル
`circle.yml`の内容はプロジェクト毎に違うので、あくまでサンプルです。

```yml:circle.yml
machine:
  timezone: Asia/Tokyo
  node:
    version: 0.12.0
dependencies:
  cache_directories:
    - node_modules
  override:
    - npm install
test:
  pre:
    - npm run build
  override:
    - npm test
deployment:
  github:
    branch: develop
    commands:
      - ./scripts/release_push.sh
```
上記では`develop`ブランチにpushされた時に`./scripts/release_push.sh`が実行される内容になってます。
`./scripts/release_push.sh`の中身は単純なgitコマンドの集合です。(後述)

今回のストーリーとしては`npm run build`で諸々生成されたファイルを`release`ブランチにコミットしてgithubにpushするという感じです。

# CircleCIビルド実行時の振り分け
ちょっと寄り道ですが、`develop`ブランチにpushするたびに毎回`release`ブランチが切られるのは嫌だという場合は[CircleCI REST API](https://circleci.com/docs/api)を使って、明示的に実行させる方法もあります。

```sh:CircleCI_REST_APIサンプル
curl \
  --header "Content-Type: application/json" \
  --data '{"build_parameters": {"USE_RELEASE_PUSH": 1}}' \
  --request POST \
  https://circleci.com/api/v1/project/<ユーザor組織名>/<リポジトリ名>/tree/develop?circle-token=<circleci_api_token>
```
上記のように`build_parameters`に設定した値を、CircleCIの実行コンテナ内で環境変数として利用することが出来ます。
なので`./scripts/release_push.sh`内で`$USE_RELEASE_PUSH`をチェックして、処理を実行するかしないか判断させれば目的は達成されるはずです。

さらに、このAPIをSlackなどのツールと連携させれば簡単なChatOpsが出来て便利です。

# `release_push.sh`のサンプル
最後に`./scripts/release_push.sh`のサンプルです。

```sh:./scripts/release_push.sh
#!/bin/bash

# gitユーザ設定
git config --global user.email "foo@bar.baz" #コミットユーザの有効なメールアドレス
git config --global user.name "hoge" #コミットユーザの名前

# リリースバージョン名
CI_RELEASE_VERSION=`date +"v%Y%m%d%H%M%S"`
# リリースブランチ名
CI_RELEASE_BRANCH="release/${CI_RELEASE_VERSION}"
# リモートリポジトリ
CI_REMOTE_REPOSITORY="git@github.com:${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}.git"
# リリースブランチ作成
git checkout -b ${CI_RELEASE_BRANCH}
#変更ファイルををすべて追加
git add --all :/
#コミット
git commit -m "[auto] release branch (${CI_RELEASE_VERSION})"
#リモートにプッシュ
git push ${CI_REMOTE_REPOSITORY} ${CI_RELEASE_BRANCH}

```
突然出てきた`CIRCLE_PROJECT_USERNAME`と`CIRCLE_PROJECT_REPONAME`は、元々CircleCIにある環境変数になります。
前述した、実行の振り分けを利用する場合は`if`文などで実行判定処理を入れるだけです。

また、GitHub側の[REST API](https://developer.github.com/v3/)を使えば`Pull Request`まで含めて自動化出来ます。

```sh:GitHub_REST_APIサンプル
curl \
  --header "Accept: application/vnd.github.v3+json" \
  --data "{\"title\": \"[auto] ${CI_RELEASE_BRANCH}\", \"head\":\"${CI_RELEASE_BRANCH}\", \"base\":\"master\" }" \
  https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/pulls?access_token=<github_api_token>
```
※APIトークンはソースに記述せず、CircleCIの設定画面から環境変数などに登録して利用します。

# まとめ
[GitHub](https://github.com/)と[CircleCI](https://circleci.com/)、あと今回は触れてませんが[Hubot](https://hubot.github.com/)/[Slack](https://slack.com/)の相互連携は、それぞれの目的に合わせて柔軟に自動化が行える反面、こだわり過ぎると無限に時間を吸われそうな印象です。

自動化環境作るの楽しい。