RailsアプリケーションをGithub Actionsを用いて自動テスト＆自動デプロイにしました

# はじめに
はじめまして！現在DMM WEB CAMPに通わせていただいております、かいかいと申します！
ポートフォリオを作成して、自動テストとデプロイをなんとか構築することができたので、自分なりに手順をまとめて見ました！
間違ってる部分もあるかもしれませんが、コメントで教えていただけると幸いです。
よろしくお願いします〜〜！

# 前提条件
・Ruby  2.6.3
・Rails  5.2.5
・Mysql2 5.7.22
・Rspec-rails 5.0.1
・AWSのEC2、RDSを用いて、デプロイが完了していることを前提としています。

#今回のゴール
①ローカル環境からリモートリポジトリ（main以外のブランチ）にpush
②pushしたブランチから、mainリポジトリにマージした際にRSpecのテストが行われる。
③RSpecが合格したら、自動でEC2上の本番環境にデプロイ！
上記の流れができることを目指していきます！

#手順
1. testの際に使う、databace.yml.ciファイルを作成する。
2. Github Actions実行時に使う、workflow用のymlファイルを作成する。
3. GitHub上で、Secret(github上で用いる、環境変数のようなもの)を、作成する。
4. Github Actionsの仮想環境内から,EC2サーバーに接続するために必要な公開鍵を<br>
ローカル環境からEC2サーバ側に転送する。
5. 動作確認！<br>
それでは、実際にやっていきます！

##databace.yml.ciを作成する
最初に、GithubAction上で作成される仮想環境に必要なMysql2の設定ファイルを作成していきます。

```ruby:config/database.yml.ci
test:
  adapter: mysql2
  charset: utf8mb4
  collation: utf8mb4_bin
  encoding: utf8mb4
  database: （アプリケーション名）_test
  pool: 5
  username: root
  password: root
```

##workflow用のymlファイルを作成する。
次に、workflow用に、ymlファイルを作成します。

```ruby:.github/workflows/rails.yml
name: Rails-Rspec-Deploy

on:
  pull_request:
    branches:
      - main
    types: [closed]
    
jobs:
  setup_and_test_execution:
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged == true
    
    steps:
    - uses: actions/checkout@v2
    - name: Setup Ruby Version
      uses: actions/setup-ruby@master
      with:
        ruby-version: 2.6.x
        
    - name: Install dependent libralies
      run: sudo apt-get install libmysqlclient-dev
      
    - name: Setup bundler
      run: gem install bundler
      
    - name: bundle install
      run: |
        bundle install --jobs 4 --retry 3
    
    - name: Setup Database
      run: |
        cp config/database.yml.ci config/database.yml
        sudo systemctl start mysql
        bundle exec rails db:create
        bundle exec rails db:schema:load
      env:
        RAILS_ENV: test
      
    - name: Run RSpec
      run: bundle exec rspec
      env: 
        RAILS_ENV: test
        
    - name: Archive rspec result screenshots
      if: failure()
      uses: actions/upload-artifact@v1
      with:
        name: rspec result screenshots
        path: tmp/screenshots/
        
    - name: Set up
      env:
        PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
        USER_NAME: ${{ secrets.USER_NAME }}
        HOST_NAME: ${{ secrets.HOST_NAME }}
      run: |
        echo "$PRIVATE_KEY" > private_key && chmod 600 private_key
        ssh -o StrictHostKeyChecking=no -i private_key ${USER_NAME}@${HOST_NAME} 'cd Empathy &&
        git pull origin main &&
        ~/.rbenv/shims/bundle install &&
        ~/.rbenv/shims/bundle exec rails assets:precompile RAILS_ENV=production &&
        ~/.rbenv/shims/bundle exec rails db:migrate RAILS_ENV=production &&
        if [[ -e tmp/pids/puma.pid ]];then kill $(cat tmp/pids/puma.pid); echo kill puma process;fi &&
        ~/.rbenv/shims/rails s -e production'
```
少し長いので、区切って説明していきます！

```ruby:.github/workflows/rails.yml
name: Rails-Rspec-Deploy

on:                 
  pull_request:
    branches:
      - main
    types: [closed]  #プルリクがマージされた時
    
jobs:
  setup_and_test_execution:
    runs-on: ubuntu-latest  #OSはubuntuで実行
    if: github.event.pull_request.merged == true　#もしプルリクがマージされていたらという条件式
```

ここでは、OSにubuntuを使用する設定と、ワークフローが行われるタイミングを設定しています。
現状、GitHub Actionsには、プルリクをマージした際のイベントは用意されていないので、
プルリクエストがclosedになった際のイベントと、プルリクがマージされているかの条件式を組み合わせて、プルリクがマージされた時にワークフローが実行されるようにしています。
<br>

```ruby:.github/workflows/rails.yml
 steps:
#Rubyをインストール
    - uses: actions/checkout@v2
    - name: Setup Ruby Version
      uses: actions/setup-ruby@master
      with:
        ruby-version: 2.6.x　　#使用するrubyのversionを指定

#Mysqlをインストール
    - name: Install dependent libralies
      run: sudo apt-get install libmysqlclient-dev  #myswqlを使用するためのファイルをダウンロード
      
    - name: Setup bundler
      run: gem install bundler #bundlerをインストール
      
    - name: bundle install
      run: |
        bundle install --jobs 4 --retry 3
```
すみません、ここは特に説明もないのですが、、、
何やら、 --jobs --retry 3 をオプションでつけると、並列処理をしてくれるそうです、、、
install速度が早くなるらしいです！

<br>

```ruby:.github/workflows/rails.yml
- name: Setup Database
      run: |
        cp config/database.yml.ci config/database.yml  #ここで、最初に作成したファイルを使用します！
        sudo systemctl start mysql
        bundle exec rails db:create
        bundle exec rails db:schema:load
      env:
        RAILS_ENV: test

    - name: Run RSpec
      run: bundle exec rspec  #作成されているrspecをここで実行しています！
      env: 
        RAILS_ENV: test

```

ここで、実際にデータベースを作成した後、rspecを実行する記述をしています！
<br>

```ruby:.github/workflows/rails.yml
- name: Archive rspec result screenshots
      if: failure()
      uses: actions/upload-artifact@v1
      with:
        name: rspec result screenshots
        path: tmp/screenshots/
```
ここでは、RSpecを行っている際に、エラーが起きた時点でのスクリーンショットを保存する設定をしています！
この設定があると、ローカル環境では起きなかったエラーが起きた際に原因を探りやすくなるので、記述することをおすすめします！！！（必須ではありません）
<br>

```ruby:.github/workflows/rails.yml
- name: Set up
      env:
        PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
        USER_NAME: ${{ secrets.USER_NAME }}
        HOST_NAME: ${{ secrets.HOST_NAME }}
      run: |
        echo "$PRIVATE_KEY" > private_key && chmod 600 private_key  
        ssh -o StrictHostKeyChecking=no -i private_key ${USER_NAME}@${HOST_NAME} 'cd アプリケーション名 &&  
        git pull origin main &&  
        ~/.rbenv/shims/bundle install &&
        ~/.rbenv/shims/bundle exec rails assets:precompile RAILS_ENV=production &&  
        ~/.rbenv/shims/bundle exec rails db:migrate RAILS_ENV=production && #migrateしています！
        if [[ -e tmp/pids/puma.pid ]];then kill $(cat tmp/pids/puma.pid); echo kill puma process;fi && 
        ~/.rbenv/shims/rails s -e production' #アプリケーションを再起動しています。
```
ここでは、自動デプロイの設定をしています。
env:に続く環境変数は、この後設定していきます！

##GitHub上で、Secretsを作成する。

次に、GitHub上で使用する、環境変数を設定します！
設定を反映させたいリポジトリの画面から、設定できます。

![スクリーンショット 2021-04-02 15.40.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911580/918bcfce-4595-a346-52e6-5c7f69fb0af7.png)

設定する環境変数は、以下の三つになります。

HOST_NAME :EC2のパブリックIPアドレスの指定
USER_NAME :EC2のユーザ名（デフォルトでは、「ec2-user」です）
PRIVATE_KEY： ~/.ssh/id_rsa　にある、秘密鍵の中身

この三つを設定しましょう！

##ローカルにある公開鍵をEC2側に送信する。

先ほど、Github上に、秘密鍵を登録しました。
しかし、このままではEC2上に対応する公開鍵がないため接続することができません。
よって、今からEC2上に、公開鍵の情報を送る作業をします。

```ruby:ローカル環境
$ scp -i "EC２作成時のキーペアのパス" ~/.ssh/id_rsa.pub 'EC2のユーザ名'@ipアドレス:.ssh/id_rsa.pub
```

コピーができたら、次はEC2サーバー側でauthorized_keysに公開鍵を許可するように設定していきます。

```ruby:EC2サーバー側
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
```

##動作確認
ここまでで、一旦準備は完了です！
では試しに、完成したアプリケーションをmain以外ブランチにpushして、プルリクして、マージして、確かめてみましょう！

うまくいけば、したのような画面が出て、自動的にデプロイまでできているはずです！

![スクリーンショット 2021-04-02 16.14.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911580/8c4585e3-1a23-54e4-5e5b-1cd4787425b9.png)

また、Rspecがうまく通らなかった場合は、したのような画面になり、デプロイがされていないことがわかります！!

![スクリーンショット 2021-04-02 16.18.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911580/a3392fbf-a77e-0c9f-6796-f1db503b07e0.png)

##最後に

長々と読んで下さった方々、本当にありがとうございました！
初めてのQiitaの投稿で、わかりにくいところ、また間違っているところがあるかもしれません、、、そしたら遠慮なくコメントまでお願いします！
また、実際に記事を書くことで、いかに自分が理解を中途半端にしているかということの確認にもなりました。これからはもっと積極的に記事を書いていきたいと思います！！

この記事を通じてエンジニア転職を目指している人の手助けに少しでもなればとても嬉しいです、、、！！！

##参考にした記事
以下のサイトは、自分が実装する時、またQiitaを書く時にとても参考にさせてもらいました！
ありがとうございました！

[GitHub Actions でプルリクのマージでワークフローを実行する](https://qiita.com/okazy/items/7ab46f2c20ec341a2836)

[GitHub ActionsでCI導入(Rails+RSpec+MySQL)](https://qiita.com/eskgoend/items/8f57a2aff502dbe23fca)

[【SSH】公開鍵認証とEC2について]
(https://qiita.com/aiandrox/items/98ad9b7551481d890916)