GitHub Actionsを使ったFTPの自動デプロイ


この記事は [SnowRobin Advent Calendar 2019](https://qiita.com/advent-calendar/2019/snowrobin) の7日目の記事です。

こんにちは。
先日、ようやくGitHub Actionsの正式版がリリースされました。
GitHubは業務でもプライベートでもよく使っているサービスなので、
これをうまく使えば色々と効率化ができるのでは？といろいろ模索していました。

普段業務ではまだまだFTPでサーバーにアップロードをすることが多いため、
こいつを自動化することに挑戦しました。

## GitHub Actionsとは何か？
そもそもGitHub Actionsとは何かというと、
GitHubのイベント（プッシュとかプルリク発行など）をトリガーにして、GitHub内の仮想環境で任意の処理を実行することができるサービスです。
開発時のワークフローを設定することで、さまざまな作業の自動化を図ることができます。

## 他のCIサービスと何が違うの？
同様のサービスで「Circle CI」や「Travis CI」などがありますが、内容は殆ど同じようなものだと思います。
通常、これらはGitHubなどのリポジトリと連携して使用しますが、GitHub Actionsだとこれらのワークフローの設定をGitHubのサービス上だけで完結できるというのがメリットになると思います。

## ワークフローを設定してみよう
それでは、実際にワークフローを設定してみましょう。
今回のゴールとしては、タイトルにもあるように、 
`特定のブランチにデータがプッシュされたら、FTPでサーバーに自動的にアップロードを行う` ということをゴールとして設定したいと思います。

[GitHub Marketplace](https://github.com/marketplace?type=actions) には、すでにいろいろな人が作成したActionが公開されており、今回は、[FTP Deploy](https://github.com/marketplace/actions/ftp-deploy)を元にして、ワークフローの作成を行います。


### ワークフローの定義ファイルの作成
GitHub Actionsを使うには、リポジトリのルート直下に `.github/workflows/main.yaml` というファイルを作成します。
この `main.yaml` にGitHub Actionsで自動化させたい処理を記述していきます。

#### トリガーの設定
まずはアクションが実行されるトリガーの設定を行います。

``` main.yaml
on:                     # トリガーの設定
  push:                 # プッシュした時に実行
    branches:           # ブランチを指定
      - feature/test    # feature/testブランチ
```

上記だと `push:` を設定しているので、ブランチにpushされたタイミングでアクションが実行されます。
さらに、`branches:` で `- feature/test` と指定しています。
これで、 `feature/test ブランチにプッシュされたタイミングでアクションを実行する` という設定になります。
 
トリガーには `push` の他にも `delete` や `create` など色々な種類があります。
詳しくは下記のURLを参考にしてください。
https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows

#### 仮想環境の設定
次に使用する仮想環境の設定を行います。

``` main.yaml
jobs:
  FTP-Deploy-Action:
    name: FTP-Deploy-Action     # JOBの名前
    runs-on: ubuntu-latest      # 仮想環境の種類を指定
```
`runs-on:` で使用したい仮想環境の指定をします。
今回はサーバーとしてlinux/ubuntuの最新バージョンを使用するようにします。
他にもmacOS、Windows環境も指定することが可能です。

#### 実行したいアクションの設定

``` main.yaml
    steps:
      - uses: actions/checkout@master   # リポジトリのデータを仮想環境にチェックアウトしてくるアクションを実行する

      - name: Use Node.js 12.13
        uses: actions/setup-node@v1     # Node.jsの環境をセットアップする
        with:
          node-version: '12.13'         # v12.13のバージョンのNode環境を使用する

      - name: Build Project
        run: |
          npm install                     # npm install のコマンドを実行する
          npm run generate --if-present   # npm run generate のコマンドを実行する

      - name: List output files
        run: ls                           # ファイルリストを表示

      - name: FTP-Deploy-Action
        uses: SamKirkland/FTP-Deploy-Action@2.0.0   # FTPを使ってサーバーにDeployするアクションを実行
        env:                                        # FTP環境の設定を行う
          FTP_SERVER: ${{ secrets.FTP_SERVER }}     # FTPサーバーのURLを設定
          FTP_USERNAME: ${{ secrets.FTP_USERNAME }} # FTPのユーザー名を設定
          FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }} # FTPのパスワードを設定
          LOCAL_DIR: dist                           # どのディレクトリのデータをアップロードするか
          REMOTE_DIR: home/frontnote/www/demo       # リモートのどのディレクトリにアップロードするか
          ARGS: --delete
```

`steps:` 以下で実行したいアクションを順番に指定していきます。

今回実行する処理としては、

- リポジトリからデータをチェックアウト
- Node.js環境の設定
- npmでプロジェクトに必要なパッケージをインストール
- プロジェクトファイルのビルドの実行
- ファイルリストの表示 ※これは別になくても良いです。
- FTPでファイルをアップロード

というものになります。

各処理の記述の中で出てくる `- uses:` では、GitHub内で公開されているActionを指定することで、そのActionを利用することができます。
そしては、 `run:` では、コマンドを指定することで、そのコマンドを実行することができます。


#### FTPの設定
今回、FTPでアップロードを行う処理は、GitHub Marketplaceで公開されている以下のアクションを使用します。
 [SamKirkland/FTP-Deploy-Action](https://github.com/marketplace/actions/ftp-deploy)

``` main.yaml
      - name: FTP-Deploy-Action
        uses: SamKirkland/FTP-Deploy-Action@2.0.0   # FTPを使ってサーバーにDeployするアクションを実行
        env:                                        # FTP環境の設定を行う
          FTP_SERVER: ${{ secrets.FTP_SERVER }}     # FTPサーバーのURLを設定
          FTP_USERNAME: ${{ secrets.FTP_USERNAME }} # FTPのユーザー名を設定
          FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }} # FTPのパスワードを設定
          LOCAL_DIR: dist                           # どのディレクトリのデータをアップロードするか
          REMOTE_DIR: home/frontnote/www/demo       # リモートのどのディレクトリにアップロードするか
          ARGS: --delete
```
通常、FTPでアップロードする際に必要な情報として、

- FTPサーバーのURL
- FTPユーザー名
- FTPパスワード

が必要になりますが、これらを直接ファイルに記述してしまうと、
機密情報が他のユーザーから見えてしまい情報漏えいしてしまいます。

そのため、これらの気密情報はリポジトリの `secrets` に設定をしておき、
それをアクションから参照することで、直接内容を見られずに設定を行うことができます。

#### Secretsで見られたくない情報を設定
Secretsを設定するには、GitHubリポジトリの画面から設定を行います。
[Settings] > [Secrets] > [Add a new secret] から設定画面が開くので、
そこから設定する `Name` と `Value` を設定します。

<img width="1043" alt="スクリーンショット 2019-12-06 3.05.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61548/0f5d0766-8ef9-9f47-daeb-70c2f9036b17.png">

ここで設定した値はActionの設定の中で `${{ secrets.FTP_SERVER }}` といった形式で呼び出すことができます。



## 最終的なワークフローのファイル
最終的にはこんな設定になりました。

``` main.yaml
on:
  push:                 # プッシュした時に実行
    branches:           # ブランチを指定
      - feature/test    # feature/testブランチ
name: Build and Deploy  # アクションの名称
jobs:
  FTP-Deploy-Action:
    name: FTP-Deploy-Action     # JOBの名前
    runs-on: ubuntu-latest      # 仮想環境の種類を指定
    steps:
      - uses: actions/checkout@master   # リポジトリのデータを仮想環境にチェックアウトしてくるアクションを実行する

      - name: Use Node.js 12.13
        uses: actions/setup-node@v1     # Node.jsの環境をセットアップする
        with:
          node-version: '12.13'         # v12.13のバージョンのNode環境を使用する

      - name: Build Project
        run: |
          npm install                     # npm install のコマンドを実行する
          npm run generate --if-present   # npm run generate のコマンドを実行する

      - name: List output files
        run: ls

      - name: FTP-Deploy-Action
        uses: SamKirkland/FTP-Deploy-Action@2.0.0   # FTPを使ってサーバーにDeployするアクションを実行
        env:                                        # FTP環境の設定を行う
          FTP_SERVER: ${{ secrets.FTP_SERVER }}     # FTPサーバーのURLを設定
          FTP_USERNAME: ${{ secrets.FTP_USERNAME }} # FTPのユーザー名を設定
          FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }} # FTPのパスワードを設定
          LOCAL_DIR: dist                           # どのディレクトリのデータをアップロードするか
          REMOTE_DIR: home/frontnote/www/demo       # リモートのどのディレクトリにアップロードするか
          ARGS: --delete
          # --delete arg will delete files on the server if you've deleted them in git
```
これで、 `feature/test` にプッシュされたタイミングで、Actionが実行されます。
Actionが実行されている様子は、GitHubリポジトリの`Actionsタブ`から確認できます。

今回は基本的なアップロードのみを設定しましたが、
今回使用したアクションでは、FTPの設定する時に色々なオプションを付けられるみたいなので、
詳しくは下記のURLを参照してください。
[SamKirkland/FTP-Deploy-Action](https://github.com/marketplace/actions/ftp-deploy)


## 使ってみてどうだったか
今回始めてGitHub Actionsを使ってみての感想ですが、自動的にFTPでアップロードされるのは非常に楽だなと思いました。
が、アクションを実行してからアップロードが完了するまでに結構時間がかかってしまいました。（約10分くらい。。。ファイルの数によってはもっとかかるかも。）
なので、開発時のテストアップで頻繁にアップロードが発生する場合にはちょっと使用するのは厳しいかな。。という印象でした。

ただ、今回の設定だと、ビルドしたファイルをすべてアップロードするような感じになっていたので、
これを差分ファイルを抽出してアップロードを行うといったような、細かいアクションが設定できれば、
もう少し時間を短縮することができるかもしれません。