Github ActionsでFTP経由でデプロイしてSlackに通知する

# 背景
業務でFTPしか使えないサーバーにデプロイすることが多々あり、その度にCircleCIなどの外部サービスを使っていました。
新たにCI環境を構築する際に、去年リリースされた[GitHub Actions](https://github.co.jp/features/actions)を使いワークフローを自動化してみました。
この記事では、ビルドしたファイルのFTP経由でのデプロイと**GitHub Actions**の実行結果をSlackに通知する方法について紹介します。

# やりたいこと
- FTP経由でのデプロイの自動化
- ビルド
- 実行結果をSlackに通知する

# ワークフローを構築する
それでは実際にワークフローを構築していきます。

## トリガーと特定のブランチのみの指定
`push`をトリガーとし、`staging`ブランチのに対してのみ起動させる。

```.github/workflows/main.yml
# ワークフローをトリガーする
on:
  # pushでトリガーする
  push:
    # stagingブランチに対してのみ
    branches:
      - staging
```

## ワークフローとジョブの設定
ワークフローとジョブをそれぞれ設定します。
今回は、ジョブを実行する環境に`ubuntu-latest`を指定し、最新バージョンのUbuntuを使います。

```.github/workflows/main.yml
# ワークフローの名前
name: Publish Website

# 実行するジョブ
jobs:
  # ジョブのID
  Build-and-Deploy:
    # ジョブの名前
    name: Build and Deploy
    # ジョブを実行するマシン（仮想環境）
    runs-on: ubuntu-latest
```


## GitHubで環境変数を設定する
GitHub上でワークフローで使う環境変数を設定していきます。

[Setting]→[Secrets]のページで設定します。
[Add a new secret]から追加していきます。
![スクリーンショット 2020-01-15 10.44.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243815/27b83e0b-b13f-2a30-6deb-cece56f35bfb.png)

今回設定する環境変数は以下の通りです。

|Name  |Value  |
|---|---|
|FTP_SERVER  |サーバーアドレス  |
|FTP_USERNAME  |FTPユーザーネーム  |
|FTP_PASSWORD  |FTPパスワード  |
|FTP_REMOTE_DIR  |FTP上のパス  |
|SLACK_WEBHOOK  |SlackのWebhookのURL（取得方法は後述）  |

`SLACK_WEBHOOK`で設定するSlackのWebhookのURLの取得方法については次で説明します。

## Slackで通知を受け取れるように設定する
[Incoming Webhook](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks)を使い設定する。

以下にアクセスして設定していきます。
https://slack.com/apps/A0F7XDUAZ-incoming-webhooks

![add_app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243815/34fa7b0b-650b-91b6-b558-ccd3626959b8.png)
「Slackに追加」をクリック

![incoming.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243815/4557abab-e160-0239-f491-2e926cf67b31.png)
追加したいチャンネルを選択

![webhook.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243815/a57188b7-2471-55c3-6c43-5cdab2192520.png)
Webhook URLを上述のGithubの環境変数に設定する。



## ステップの設定
今回はNode.jsの単一バージョンの`10.x`を使います。
`10.x`の`x`は、バージョンで利用可能な最新のマイナーリリースとパッチリリースに一致するワイルドカード文字です。

デプロイとSlackへの通知には、以下のGitHub Marketplaceにあるアクションを利用します。

- [FTP Deploy](https://github.com/marketplace/actions/ftp-deploy)
- [Slack Notify](https://github.com/marketplace/actions/slack-notify)

[FTP Deploy](https://github.com/marketplace/actions/ftp-deploy)の中身はlftpですが、SSHが使えるならrsyncなどでも良いと思います。

```.github/workflows/main.yml
# 実行するタスク
steps:
# 実行されるアクション（ワークフロー、パブリックリポジトリ、公開されているDockerコンテナイメージ）
- uses: actions/checkout@master

# ステップの名前
- name: Use Node.js 10.x
  # ステップの一部として実行されるアクションを選択
  uses: actions/setup-node@v1
  with:
    node-version: '10.x'
- run: npm install
- run: npm run build

- name: FTP-Deploy-Action
  uses: SamKirkland/FTP-Deploy-Action@2.0.0
  # ステップが使う環境変数
  env:
    FTP_SERVER: ${{ secrets.FTP_SERVER }}
    FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
    FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
    LOCAL_DIR: dist
    REMOTE_DIR: ${{ secrets.FTP_REMOTE_DIR }}
    ARGS: --delete

- name: Slack Notification
  uses: rtCamp/action-slack-notify@master
  env:
    SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
```

### 実行する環境を複数設定したい場合
環境のバリエーションを指定する場合は、以下のようにする。

```.github/workflows/main.yml
# 各ジョブを実行する環境のバリエーションを定義
strategy:
  # 使用したい環境を設定
  matrix:
    node-version: [10.x, 12.x]

steps:
- uses: actions/checkout@master

- name: Use Node.js ${{ matrix.node-version }}
  uses: actions/setup-node@v1
  with:
    node-version: ${{ matrix.node-version }}
```

# 出来上がった`YAML`

```.github/workflows/main.yml
on:
  push:
    branches:
      - master
name: Publish Website

jobs:
  Build-and-Deploy:
    name: Build and Deploy
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@master

    - name: Use Node.js 10.x
      uses: actions/setup-node@v1
      with:
        node-version: '10.x'
    - run: npm install
    - run: npm run build

    - name: FTP-Deploy-Action
      uses: SamKirkland/FTP-Deploy-Action@2.0.0
      env:
        FTP_SERVER: ${{ secrets.FTP_SERVER }}
        FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
        FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
        LOCAL_DIR: public
        REMOTE_DIR: ${{ secrets.FTP_REMOTE_DIR }}
        ARGS: --delete

    - name: Slack Notification
      uses: rtCamp/action-slack-notify@master
      env:
        SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

```

ワークフローを設定する`YAML`ファイルの細かい設定や書き方については、以下を参照してください。
[GitHub Actionsのワークフロー構文 - GitHub ヘルプ](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions)

Node.jsを使ったプロジェクトについては以下を参照。
[Using Node.js with GitHub Actions
](https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/using-nodejs-with-github-actions)[Node.jsワークフローテンプレート](https://github.com/actions/starter-workflows/blob/master/ci/node.js.yml)


# 実行されると
プッシュしてジョブが完了すると、以下のようなメッセージがSlackに通知されます。
![slack_notice.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243815/10691328-e8f2-26be-bc1d-055b5b73253f.png)

# まとめ
反映に少し時間がかかるが、FTPでしかアップできない制限下で使う分にはいまのところ問題ない。
GitHubで完結するので、外部のCIサービスを使うより簡単で楽に実装できた。
今後はGithub Actionsで十分なものは、Github ActionsでCIを構築していきたい。