RubyGemsリリースを自動化した話

#TL;DR
Github上で**v1.2.3**のようなreleaseタグを作るだけで、
あとはCircleCIが自動で
version.rbの更新→Gemビルド→RubyGemsへリリースする仕組みを作りました。
サンプルはこちらにあります。
https://github.com/NA070/release_test
# RubyGems公開手順
RubyGems公開には以下の手順が必要です。

1. RubyGems APIキーを~/.gem/credentialsへ書き込む
2. ./lib/*{package_name}*/version.rbの更新（ 更新箇所: `VERSION = '1.2.3'` ）
2. gemのパッケージ化 ( コマンド例: `gem build package_name.gemspec` )
3. RubyGemsでの公開 ( コマンド例: `gem push package_name-1.2.3.gem`)

# 運用の要求
releaseタグを使って管理したいという要求がありました。
理由としては以下の要点があります

* 更新内容を明記したい
  * masterブランチが更新されるたびにリリースすることもできるがそれだと更新内容がわかりづらい
  * releaseごとの更新情報を管理できない
* コード実装完了＝リリースしてOKではない
  * ドキュメント更新がある場合もあるので、それも整備し終えてからリリースしたい
  * masterブランチ更新でリリースだと↑は満たされない

# 自動化したフロー
releaseタグ作成を入れて、自動化した公開手順は以下です。

※ 1だけ手動であとは自動実行されます。
1. 新しいreleaseタグをgithub上で作成 :hand_splayed:
2. ./lib/*{package_name}*/version.rbのバージョンナンバー更新 :robot:
3. masterブランチへpush :robot: 
4. gemのパッケージ化 :robot: 
5. RubyGemsでの公開 :robot: 

次にどのように自動化しているかを説明していきます
# 設定方法
CircleCIを使って自動化しました。
設定を進める前に空のジョブでいいので、リポジトリとCircleCIを連携させておく必要があります。

## ① RubyGemsのAPIキーをCircleCIプロジェクトの環境変数に設定する
CicleCIのプロジェクトセッティングから環境変数を設定します。
サンプルではRUBYGEMS_API_KEYとしました。
APIキーはRubygemsのプロフィール編集ページで確認できます。（要ログイン）
<img width="1416" alt="Screen Shot 2019-05-14 at 16.23.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/4609dc89-a0c2-0acf-240f-466415749287.png">

## ② Checkout SSH keysに鍵を追加する
version.rbを更新したあとにリポジトリへpushsする必要があります。
そのためにwrite権限が必要です。

1. Githubの認証を許可します
<img width="1200" alt="Screen Shot 2019-05-14 at 16.26.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/c51c7de4-9fbc-d865-08d5-7bdc7dc86c1f.png">

2. 鍵を作成します
<img width="1200" alt="Screen Shot 2019-05-14 at 16.26.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/2d04ffe4-3e1a-359f-9e6f-65dcaf4c3442.png">
追加されました！
<img width="1200" alt="Screen Shot 2019-05-14 at 16.27.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/0cba2323-765e-60bd-9360-10a8b7f842fb.png">

## ③ CircleCIの設定ファイルを追加

リポジトリへpushするための設定は `add_ssh_keys` で設定します。
先程追加したsshキーのfinger printを記述します。

https://github.com/NA070/release_test/blob/master/.circleci/config.yml

```yaml
version: 2
jobs:
  publish:
    docker:
      - image: circleci/ruby:2.4.1
    steps:
      - add_ssh_keys:
          finerprints:
            - "b8:3b:3a:5b:4b:0b:50:73:bf:92:e0:e3:ac:00:01:c1"
      - checkout
      - run:
          name: Setup Rubygems
          command: bash .circleci/setup_rubygems.sh
      - run:
          name: Update vresion.rb and publish on RubyGems
          command: bash .circleci/deploy_to_rubygems.sh
workflows:
  version: 2
  deploy:
    jobs:
      - publish:
          filters:
            tags:
              only: /^v[0-9]{1,}(\.[0-9]{1,}){2}$/
            branches:
              ignore: /.*/
```

## ④ ジョブで使うshellスクリプトを追加

### 1. RubyGemsのcredentialファイル作成処理

環境変数 $RUBYGEMS_API_KEY に設定されたAPIキーをファイルへ書き込みます。
https://github.com/NA070/release_test/blob/master/.circleci/setup_rubygems.sh

```sh
mkdir ~/.gem
echo -e "---\r\n:rubygems_api_key: $RUBYGEMS_API_KEY" > ~/.gem/credentials
chmod 0600 /home/circleci/.gem/credentials
```

### 2. version.rb更新→gemビルド→gem pushする処理
役割が多いですが、1ファイルにしています。（責任が多いので分けるのが良いかもです。）
↓では説明のために分割しています。

https://github.com/NA070/release_test/blob/master/.circleci/deploy_to_rubygems.sh

タグを取得します。
また、git操作するための設定を行います。
メールアドレスにはgithubが用意しているダミーアドレスを使いました。
（参考：https://help.github.com/en/articles/about-commit-email-addresses）


```sh

VERSION=$(git describe --tags | sed -e 's/^v//')
git config user.email "2687752+NA070@users.noreply.github.com"
git config user.name "2687752+NA070"

```

version.rbを更新し、commitします。

```sh
# Update version.rb
sed -i '' -e "s/VERSION = '[0-9]\{1,\}.[0-9]\{1,\}.[0-9]\{1,\}'/VERSION = '$VERSION'/" lib/release_test_nao/version.rb
git diff
git checkout master
git add lib/release_test_nao/version.rb
git commit -m "Version $VERSION"
```

ビルドし、gem push（RubyGemsへリリース）します

```sh
# Build and release gem
gem build release_test_nao.gemspec
gem push "release_test_nao-$VERSION.gem"
```
最後にリポジトリへpushします。
最後に行うのはそれまでの処理で何らかのエラーがあった場合に誤った状態でのpushを防ぐためです。

```sh

# Push to master
git push origin master
```

設定は以上です。

# リリースしてみる
リリースタグを作ります。
<img width="1054" alt="Screen Shot 2019-05-14 at 16.51.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/f709dfba-aa1d-32b6-a59d-d7a3916b44cd.png">
<img width="1072" alt="Screen Shot 2019-05-14 at 16.52.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/a4642429-cb1a-6813-c6bc-79047c88b30e.png">
v0.1.32 でリリースします。
<img width="1012" alt="Screen Shot 2019-05-14 at 16.53.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/d09f0556-d07a-0ed4-02a3-d879174b0923.png">

<img width="1333" alt="Screen Shot 2019-05-14 at 16.55.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/c17bf23c-04c1-fb3b-0e86-fd1ba0ebb33c.png">
こんな感じにログが出ます。
<img width="1324" alt="Screen Shot 2019-05-14 at 16.55.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/b62416de-a727-aef8-3d87-bef00aeb300b.png">
無事リリースされました！（この記事を書いたあとにRubyGemsからは削除したので現在は見れません）
<img width="1085" alt="Screen Shot 2019-05-14 at 16.56.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/75203039-b390-550d-c4e0-f126c477a9b8.png">
リポジトリにもpushされています。
<img width="1029" alt="Screen Shot 2019-05-14 at 16.57.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10800/c5848eda-6c60-5883-7be2-4f42dee82308.png">

無事うまくいきました。
要求を満たした自動化が実現できました :clap: 

実現はできたもののの、OSSの経験が少ないので、何が最適なのかは探求する必要がありそうです。
アドバイスなどがありましたらコメントいただけると嬉しいです。

### 参考にさせていただいた記事
- https://blog.leko.jp/post/automate-deploy-to-rubygems-with-circleci/
- https://christina04.hatenablog.com/entry/circleci-workflow