はじめてのTravisCI - テストとデプロイを自動化しよう!

🤔***...oO(皆どうやってGitHub Releasesに自動アップロードしてるんだろう...?)***
と気になったのがきっかけで Travis CI まで辿り着いたので、使ってみることにしました。

そもそも *"CI って何 ?"* って所からスタートだったので、使用方法や思った事を綴っていきます。


# CI(継続的インテグレーション)
- [継続的インテグレーション - Wikipedia](https://ja.m.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E7%9A%84%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3)

超ざっくり言うと
***"プログラマはコードさえ書いてればいい"***
を実現するための仕組です。

- コーディング
- ビルド
- テスト
- デプロイ

一般的なこれらの工程のうち "ビルド/テスト/デプロイ" を自動化してくれる仕組とも言えます。


# Travis CI
- [Travis CI - travis-ci.org](https://travis-ci.org)

GitHub と連携できる CI サービスです。
リポジトリ内に`.travis.yml`というコンフィグファイルを置いとくと、`push`や`pull request`をトリガーにバッチが走り、自動で色々やってくれる便利なやつです。


# 使ってみる
## リポジトリの用意
まずは GitHub にリポジトリを作ります。
そしてリポジトリのルートディレクトリに`.travis.yml`というファイルを作ります。

Travis CI は大抵の言語に対応していますが、今回は`Node/Express`という体で進めていきます。


## .travis.yml
上から順を追っていきます。

### 言語/バージョン指定
```yaml:.travis.yml
language: "node_js"
node_js: "10.14.1"
```
これは一目瞭然ですね。
`language:`に言語名を、`(language):`にバージョンを指定します。

### 環境変数
ここは初見だと少し分かりにくいポイントでした。

そもそも Travis CI は、トリガー毎に仮想マシンが建てられて、その中でバッチが進行するので、環境変数やシェルスクリプトの実行が可能です。

```yaml:.travis.yml
env:
    global:
        - "USER_NAME=dojyorin"
        - "MY_ENV=foobar"
        - secure: "Re/0W8pVRnuqHvHcgbUgvkFYDb57TSybqac5/mxnSwZGX5dzO9ev2uvM0YQjpvcX+4rJpIrBLuUOqdaCak1oabhwwVahrBkjTdTQULXK2r0hCGRrKzY04zIQ3nkGH2rNSORac+1D1F8IueinHzjydiqgTJk0mWuU0nZd2AP/yKz5RmFRPwX6hUte+46aQCE9wH2bbKrAWEfm5dvLaaML2ScSDh9+gK2QwSybDpndoDp3a2LBJ3CHSolqtjQK7OzsIC1uZjYp+AfrVt30jrQZ354WRZcgp48kTC15RHqOhlZyrdBk2UHsZbpBQeoEcjUbFUDcoiJ2doaW4hvLu2pid1eQVtHAP8eYx69AQ962I6TrnxFHCMoFHOh9JNUyEtElqCJVzg4CJsdE3DmdAJ5X8R92YfH0RL3AtFtBV4YtJq7ewSjYli5JtEVQLUJ+ELPJ6XnWaQwUsCDrUCVcKd0TelIgC17m//R/GWqtnbP/kkLXCghyOfXH3cKDNbgnQ81H/hhJ1iZITqy2kzvvvQjhyPPY9OnpGlP+7hk1P3NBXj7CujKYl+ToQmaDNM8R89j+LKDKbUkc2zbcs6KsU5C9KGoBo6LAQ72d4XxOqAE1arj9q6QFt+JX60RZL3O/TZMEqLgstxGnvPSDNk1Kqhsauk1Isy9zTTLLM14MwbclyDo="
```
`env:`内に環境変数を記述していくのですが、上記のように複数ある場合は`env:global:`へ列挙します。

```yaml
env:
    - "FOO=bar"
    - "HOGE=huga"
```
のように`env:`へ直接列挙すると、列挙した数だけバッチが並行して走ってしまいます。

### 暗号化
環境変数に外部APIへのアクセストークンなどを収めたい場合、生トークンをそのまま記述する訳には行かないので、暗号化します。

```yaml
global:
# Decrypted
    - "ACCESS_TOKEN=0123456789abcdef"
# Encrypted
    - secure: "..."
```
その暗号化されたデータが上記`secure: "..."`となります。

暗号化は Travis Client CLI を使うか Web サービスを使うかの2択です。

- [Travis Client - RubyGems](https://rubygems.org/gems/travis)
- [travis-encrypt - GitHub.io](https://travis-encrypt.github.io)

Travis Client は Ruby 製なので gem からインストールします。
多機能ですが Ruby のインストールが必要になります。

```shell:Shell
$ travis encrypt -r user-name/repository-name ACCESS_TOKEN=0123456789abcdef
```
これで暗号化された文字列が生成されます。


暗号化だけなら手っ取り早く Web サービスを使うのも良いかと思います。

なお暗号化は公開鍵方式で、秘密鍵はTravis内部にしか存在しません。
一度暗号化すると本人でさえ復号手段は無くバッチ中に復号される為、安全に使えます。

### Git設定
```yaml:.travis.yml
git:
    depth: 3
```
`git:depth:`は Travis CI が GitHub から`git clone`する際の深さを指定します。
デフォルトで`50`となっていますが、そんなに掘り下げなくて良いので`3`位にしておきます。

### ブランチ設定
```yaml:.travis.yml
branches:
    only:
        - "master"
        - "/^v\\d\\.\\d\\.\\d/"
    except:
        - "dev"
        - "experiential"
```
デフォルトだと、どのブランチに`push`しても全ブランチのバッチが走ってしまいます。
`branches:only:`でトリガーするブランチを指定できます。
また`branches:except:`でトリガーから除外するブランチを指定できます。

また、デフォルトではタグへの`push`はトリガーされません。
タグを正規表現で指定する事により、トリガーが可能となります。
上記の場合`master`ブランチか`vx.x.x`タグが`push`された時だけバッチが走ります。

### テストフェーズ
ここは前/中/後の3フェーズに分かれています。
どのフェーズも各種シェルスクリプトが実行可能です。

```yaml:.travis.yml
before_script:
    - "npm i -g mocha"
    - "touch .env"
    - "echo EXPRESS_SESSION_SECRET=\"${EXPRESS_KEY}\" >> .env"
script:
    - "npm run test"
after_script:
    - "rm .env"
```
まず`before_script:`が走ります。
ここでは主に、テストスクリプトを回す為の下準備を行えるようになっています。

そして次に`script:`が走ります。
テストスクリプト本体はここに記述すると良いでしょう。

最後に`after_script:`が走ります。

### デプロイフェーズ
テストプロセスが成功すると、デプロイフェーズに入ります。
テストプロセスで失敗した場合は、そのままバッチが終了します。
ここも前/中/後の3フェーズに分かれています。

#### Before
```yaml:.travis.yml
before_deploy:
    - "rm -f .env"
    - "zip -qr9 ${TRAVIS_TAG}-release.zip . -x \"*.git*\" -x \"*node_modules*\" -x .travis.yml -x .gitignore -x package-lock.json"
    - "zip -qr9 ${TRAVIS_TAG}-release-bundled.zip . -x \"*.git*\" -x .travis.yml -x .gitignore -x package-lock.json"
```
`before_deploy:`でデプロイ用のzip生成など、下準備を行います。

環境変数`${TRAVIS_TAG}`には、タグへの`push`時のみタグ名が載ってます。

#### Deploy
```yaml:.travis.yml
deploy:
    provider: "releases"
    api_key:
        secure: "..."
    file:
        - "${TRAVIS_TAG}-release.zip"
        - "${TRAVIS_TAG}-release-bundled.zip"
    skip_cleanup: true
    on:
        tags: true
        repo: "${TRAVIS_REPO_SLUG}"
```
`deploy:`だけは、お作法に則って記述する必要があります。
`deploy:provider:`でデプロイ先のサービスを指定します。
`releaaes`は GitHub Releases を指します。
その他 npm などの各種パッケージ管理システムにも対応してます。
`deploy:api_key:`は GitHub Release 選択時に特有で GitHub へのアクセストークンを記述します。

このアクセストークンは Travis Client で簡単に生成可能なのでご紹介します。

```shell:Shell
$ travis login --org
$ travis setup releases --org -r user-name/repository-name
```
これで生成可能です。
生成されたら`deploy:api_key:`へ転記します。

`deploy:file:`でデプロイするファイルを指定します。
列挙する事により、複数アップロードが可能です。

`deploy:skip_cleanup:`は必ず`true`にします。
`false`になっていると、テストフェーズ終了時にキレイさっぱり全ファイル削除されてしまいます。

`deploy:on:`でデプロイが実行される条件を指定できます。
`deploy:on:tags:`は、タグへの`push`のみデプロイを実行する場合`true`にします。
GitHub Releases はタグと紐付いてるので、ここは大抵`true`で問題ないかと思います。

`deploy:on:repo:`はデプロイ先のリポジトリを指定します。
環境変数`${TRAVIS_REPO_SLUG}`にリポジトリ名が載ってるので、それを適用します。

#### After
```yaml:.travis.yml
after_deploy:
    - "curl -X POST -u ${AZURE_KEY} -T ${TRAVIS_TAG}-release.zip https://${AZURE_APP_NAME}.scm.azurewebsites.net/api/zipdeploy"
```
`after_deploy:`はサービスへのデプロイが完了後に、別のサービスへ REST API などでデプロイしたい場合などに記述します。

このリポジトリは Azure AppService にもデプロイしている為`curl`でデプロイ用の API を叩いてます。


## トリガー有効化
Travis CI の Web ポータルサイトに GitHub アカウントでログインします。

そして Settings > Repositories の Sync Account でリポジトリ情報を同期した後、各リポジトリ毎にトリガーの有効化/無効化をトグルスイッチで設定します。


# 結果
これで`push`するだけでテストプロセスが走り、タグを付けて`push`するとテストプロセス後に GitHub Releases と Azure AppService へ自動デプロイされるようになりました!!


# 応用
`after_deploy:`で Twitter など各種 SNS API を叩けば、リリース時に通知など出来たりします。


# おわりに
最初は、個人で CI サービスなんて大げさだと思ってました。
しかし、使い始めてみたら簡単で正直驚きました。
特に Travis CI ポータルサイトでの設定項目は数える程度で、迷う事が無かったのはとても良い点だと感じました。

とても簡単で便利なサービスだったので、ぜひ使ってみて下さい!!