テストだけでなく、デプロイもGithubで！SlackとGithub Deploymentを使ったGithub Actionsの実行方法

# はじめに

[GithubActions](https://github.co.jp/features/actions)がリリースされ、CircleCIや、TravisCIから段々とGithubActionに移行している中、CircleCIで出来た「Approve」機能が使えなくて困っている人も多いはず。

`git push` してActionを起動できるのはわかったけど、任意のタイミングでDeployのために、Github Actionsを実行したいと思うようになってきたのではないでしょうか？

そんな時に使えるのが「Github Deployment」!
任意のタイミングでActionを起動して、Deployを効率化することができます。
Slackの連携もGithubの公式Integrationから可能です。

# Github Deployment とは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/fc9749ef-42db-480e-ccc7-7575d8ae5c3b.png)

- [GithubDeploymentAPI](https://developer.github.com/v3/repos/deployments/)
- GithubDeplomentとは、指定したタグやブランチに対してGithubActionや、外部連携のDeploy機能を実行できるものです。
- **デプロイメントは現在ベータ版であり、変更される可能性があります。**

# 本日紹介する最終構成

- slackからGithub deploymentを作成し、Github Actionを通じて、各環境へデプロイする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/4b2c5a57-4b2e-0a33-76e7-16bcfac0b7e4.png)

以下、順を追って説明します。

# Github Development の表示方法

Github Deploymentを一度でも実行すると、リポジトリのバーに `emvironment` タブが表示されます。
こちらで、deployの簡単な実行履歴と結果を確認することができます。

- 実行前のタブ
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/b8a0a758-7c4f-dd4c-cf1f-2134744b1a9d.png)
- deploymentsの作成コマンド実行

```sh
curl -X POST \
  -H "Authorization: token xxxxxxxxxxxxxxxx" \
  -d '{"ref": "master"}' \
  https://api.github.com/repos/${username}/${reponame}/deployments
```
 
- 実行後のタブ
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/2c5fbc9f-cfc8-7b29-0193-3a43bfe8abf7.png)


ここで増えている `environment` がdeploymentsの項目です。
envirommentの中身は以下のようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/8ee5a832-0634-9c00-1df0-d37affc7d7a8.png)

# Github Deploymentでできること

[GithubDeploymentAPI](https://developer.github.com/v3/repos/deployments/)には以下のオプションがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/cedb0f77-8411-1a80-e679-9391b890e0b8.png)

環境、タスク、ref、payloadなどを渡して実行できるので、比較的柔軟なdeployをすることが可能です。
例えば、 `検証環境に、masterをデプロイする` みたいなこともできますし、モノレポ環境であれば、
`検証環境に、masterのxxxというサービスをxxxという引数でデプロイする` といったことも可能です。

# 実際にDeploymentをGithub Actionsで実行してみる

何もトリガー実行を設定しない場合、上記の方法でdeploymentを作成しても `pending` のままです。
ですので、GithubActionsを利用して、deploymentの作成をトリガーし、実行完了したら、
environmentのdeploymentステータスをsuccessに変更してみようと思います。

- リポジトリのSecretにGithubTokenを登録する(Github -> Repository -> Settings -> Secrets)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/aa92bcd0-a6d5-5742-270f-657a01e415c2.png)

- GithubActionsをリポジトリに配置してpushする

```yaml:.github/workflows/deployment.yml
name: DEPLOYMENT
on: 
  # https://developer.github.com/v3/repos/deployments/#update-a-deployment
  deployment
jobs:
  deploy:
    name: DEPLOY ${{ github.event.deployment.environment }} ${{ github.event.deployment.task }}
    runs-on: ubuntu-18.04
    steps:
    - name: deploy
      run:  echo "Execute the deproy script here."
    - uses: 'sadayuki-matsuno/github-deployment-status@v1'
      with:
        status: '${{ job.status }}'
        token: '${{ secrets.TOKEN }}'
      if: always()
```

`sadayuki-matsuno/github-deployment-status` -> actions内のstatusをそのままdeploymetsに反映させるために作りました。
`github.event.deployment.environment` -> deploy時に指定したenvironment
`github.event.deployment.task` -> deploy時に指定したtask

- deployment作成

```sh:console
curl -X POST \
  -H "Authorization: token xxxxxxxxxxxxxxxx" \
  -d '{"ref": "master"}' \
  https://api.github.com/repos/${username}/${reponame}/deployments
```

- Actionsの実行結果を確認(Github -> Repository -> Actions)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/6c8be0c9-0e65-636b-dfb2-741e66ec0533.png)

- environment表示確認(Github -> Repository -> Environment)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/517c9b48-fb91-400c-3b9f-3ee4267126e0.png)

curlでの実行の場合、envはdefaultで `production` となります。
この結果はPRの下の方にも表示されます。

# Github Development をSlackから利用する

実はこのGithubDeploymentはSlackの[Github公式Integration](https://slack.com/intl/ja-jp/help/articles/232289568-GitHub-%E3%81%A8-Slack-%E3%82%92%E9%80%A3%E6%90%BA%E3%81%95%E3%81%9B%E3%82%8B)にも実装されています。
コマンドとしては `/github deploy ${username}/${repo}` となっています。

- slackに github integrationの追加
- `/github deploy ${username}/${repo}`
- `Connect Github Account` をクリックして設定する
  - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/dd06d10f-f1d7-5d7a-3d16-81ede2c3564a.png)
- `/github deploy ${username}/${repo}` を再度実行
- ダイアログに必要項目を追加して `Create` をクリックする
  - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/3ee476b3-c69d-5060-fbec-29e5b6dbd7b0.png)
- deployment作成完了！
  - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/aeeb7f75-55a1-40df-7899-3956bf9944e3.png)

以上のフローとなります。これでcurlでapiを実行するのと同等のコマンドが実行されます。
ダイアログにある `Branch or tag to deploy` の項目は、プルダウンで選択できるようになっています。
ここでエラーが発生する場合は、後述の注意点を確認してください。

# Github Development 利用の注意点

Github DeploymentをSlackで実行する場合、
エラー要因はいろいろあるけど、エラーメッセージが単一とにかくエラーがわかりにくいです。

- 対象のタグ、ブランチでCI(GithubAction)が全て成功していない場合はエラー( `We had some trouble connecting.` )
  - すでにGithubActionsでCIを回してテストを実行している方も多いと思いますが、対象のタグと、ブランチのCIでエラーが発生している場合は、Github Deploymentは失敗します。
- Autoマージが実行されて、エラー( `We had some trouble connecting.` )
  - Github Deploymentには `AutoMerge` という項目があります。
  - SlackのGithub Integrationではこの項目を選択することができず、常にdefaultで `AutoMerge=true` で実行されます。
  - AutoMergeとは上記のオプションにも説明がありますが、 `default branch` が対象のブランチよりも進んでいる場合、自動でMergeされる機能です。
  - AutoMergeが完了し、テストも全て通ると、Deployできるようになります。

# 私が利用している実際のAction紹介

このGithub Deployment を利用すると、Github Actionを任意のタイミングで実行することが可能です。
`Approve` がなくてCircleCIなどから移行できなかった方もこれを使えば、デプロイの実行もGithubに寄せることができるのではないかともいます。
最後に私が実際に利用している `deployment.yml` を紹介して終わります。

```yaml:.github/workflows/deployment.yml
name: DEPLOYMENT
on: 
  # https://developer.github.com/v3/repos/deployments/#update-a-deployment
  deployment
jobs:
  deploy:
    name: DEPLOY ${{ github.event.deployment.environment }} ${{ github.event.deployment.task }}
    runs-on: ubuntu-18.04
    steps:
    - name: Production Deploy Check
      if: github.event.deployment.environment == 'production'
      run: |
        permittedUser=('sadayuki-matsuno')
        [[ " ${permittedUser[@]} " =~ " ${{github.actor}} " ]] || exit 1
        echo 'User is ok'
        [[ ${{github.ref}} = *'refs/tags/v'* ]] || exit 1
        echo 'Branch is ok'
    - uses: actions/checkout@v1
    - uses: actions/setup-go@v1
      if: github.event.deployment.task == 'backend'
      with:
        go-version: 1.13
    - uses: actions/setup-node@v1
      if: github.event.deployment.task == 'web'
      with:
        node-version: 12.x
    - uses: actions/setup-java@v1
      if: github.event.deployment.task == 'android'
      with:
        java-version: 1.8
    - name: deploy
      if: success()
      run: sh deployment/deploy.sh ${{ github.event.deployment.environment }} ${{ github.event.deployment.task }}
    - uses: 'sadayuki-matsuno/github-deployment-status@v1'
      with:
        status: '${{ job.status }}'
        token: '${{ secrets.TOKEN }}'
      if: always()
    - uses: 8398a7/action-slack@v2
      with:
        only_mention_fail: here
        status: ${{ job.status }}
        author_name: DEPLOY ${{ github.event.deployment.environment }} ${{ github.event.deployment.task }}
      env:
        GITHUB_TOKEN: ${{ secrets.TOKEN }}
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
      if: always()
```

- `/github` コマンドが実行できるchannelをslackで制御しています。 `#deploy` channelだけで実行できるようにして、誰がいつ実行したのかslackで追いやすくしています。
- `Production Deploy Check` では、誤操作で本番にデプロイされないように本番デプロイできるユーザとタグを設定しています
- ブランチだと、最新しかデプロイできないので、切り戻しなども想定して、ブランチではなくタグでデプロイするようにしています。
- 各種setupのところでは、deployするサービスに合わせて、setupの有無を制御しています
- 実際のdeploy作業は全てshellで書いてあり、 `environment` と `task` を引数にして実行しています。(slackではpayloadが打ちづらいので、使っていません)
- `sadayuki-matsuno/github-deployment-status` でdeploymentの成功失敗をGithubに登録しています
- 最後にSlackに通知して終了です

以上です。もっとこうすればいいよ！みたいなコメントあればお願いします！

# 最後に

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55672/4d3594c0-34a2-79d4-53a5-afc69710a77e.png)
**[omeroid株式会社](https://www.omeroid.com/)ではエンジニアを募集しています!**
**是非興味のある方はお声がけください！**

|:office:|[omeroid HomePage](https://www.omeroid.com/)|
|---|---|
|:couple_mm:|**[Wantedly](https://www.wantedly.com/companies/company_5409883)**|
|:thumbsup:|**[Facebook](https://fb.me/omeroid)**|
|:hatched_chick:|**[Twitter](https://twitter.com/omeroid_inc)**||