Help us understand the problem. What is going on with this article?

GitHub Actions(v2;yaml)でプルリクエスト毎に確認用アプリ(Review Apps)を立ち上げる(PaaS: Zeit Now)

この記事で説明・提供していること

  • GitHub Actionsの基礎知識:かんたんな用語整理(Actions, Workflow, Job, Step)
  • Pull Requestのオープン(opened)と追加コミット・プッシュ(synchronize)時だけ実行されるWorkflowの書き方
  • CI(test)が成功したときだけDeployが実行されるWorkflow (Job)の書き方
  • 実行するアクションの中でPull Request(PR)のNumber(#99)やRepository名を取得する方法
  • Zeit NowにPR毎のアプリ(Review Apps)をPR NumberをURLに含むかたちでDeployする方法
  • ↑でDeployされたReview AppのURLをPRにコメントとして書き込む方法
  • これらが書かれたGitHub Actions(v2)設定yamlの完成コード

Change Log

  • 2019/09/10 13:00:初稿として全体コードだけ載せました。詳細は後で書きます(ストックしておくと更新通知が来るので良かったらどうぞ)
  • 2019/12/04 20:00:全体コードに加えて各パートの解説を書きました

GitHub Actionsの基礎知識

  • Actions: あるRepositoryに存在するWorkflowの集まり
  • Workflow: Repositoryに対する特定の行動(Push, Pull Request, etc.)に対して実行されるJobの集まり
  • Job: 複数(または単一)のStepを含むWorkflowの実行単位。 各Jobは並列で実行されるが依存関係を設定することもできる。 実行されるプラットフォーム(Ubuntu etc.)の指定もここで行う
  • Step: Job内で順番に実行される一つ一つの処理。前の処理の成功・失敗に応じて実行有無を変えることも可能

設定yamlの完成コード

パーツ毎の説明は後述するので、まずは最初に設定ファイル全体を載せます。( 説明は後で書きます 書きました)

また、完成コードを含むExampleをGitHubに置きました。
noriaki/gh-actions-example-with-zeit-nextjs-and-now: Example of GitHub Actions v2 with Zeit Next.js and Now
設定yamlコードの場所は~/.github/workflows/pull_request.ymlです。

on:
  pull_request:
    types: [opened, synchronize]

name: Test and Deploy with PR number alias and comment apps URL

jobs:
  test:
    name: CI Test
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v1
        with:
          fetch-depth: 1

      - name: "[INFO] Versions"
        run: |
          echo "node: `node --version`"
          echo "npm:  v`npm --version`"
          echo "yarn: v`yarn --version`"

      - name: Install packages
        run: >-
          yarn install
          --frozen-lockfile
          --ignore-optional
          --no-progress
          --non-interactive

      - name: Test
        run: yarn test

  deploy_to_zeit_now_staging:
    name: Deploy and Alias with PR number
    runs-on: ubuntu-latest
    needs: test

    steps:
      - uses: actions/checkout@v1
        with:
          fetch-depth: 1

      - name: "[INFO] Versions"
        run: |
          echo "node: `node --version`"
          echo "npm:  v`npm --version`"
          echo "yarn: v`yarn --version`"
          echo "now:  v`now --version`"

      - name: Deploy
        env:
          ZEIT_TOKEN: ${{ secrets.ZEIT_TOKEN }}
        run: >
          now deploy
          --build-env NODE_ENV=production
          --env NODE_ENV=production
          --public
          --no-clipboard
          --token ${ZEIT_TOKEN}
          > ${HOME}/deployment-url.txt

      - name: Alias with PR number
        env:
          ZEIT_TOKEN: ${{ secrets.ZEIT_TOKEN }}
        run: >
          now alias
          --token ${ZEIT_TOKEN}
          `cat ${HOME}/deployment-url.txt`
          ${{ github.event.repository.name }}-pr-${{ github.event.number }}.now.sh

  post_comment_review_app_url:
    name: Post comment that review app URL when PR opened
    runs-on: ubuntu-latest
    needs: deploy_to_zeit_now_staging

    steps:
      - name: Post comment review app URL by GitHub API
        if: github.event_name == 'pull_request' && github.event.action == 'opened'
        run: >
          curl
          -X POST
          -H "Authorization: token $GITHUB_TOKEN"
          -H "Accept: application/vnd.github.v3+json"
          --data "{ \"body\": \"Review-App was deployed.\nhttps://${{ github.event.repository.name }}-pr-${{ github.event.number }}.now.sh\" }"
          ${{ github.event.pull_request.comments_url }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

以下、完成コードから一部抜粋するかたちで解説していきます。

Pull Requestのオープン(opened)と追加コミット・プッシュ(synchronize)時だけ実行されるWorkflowの書き方

on:
  pull_request:
    types: [opened, synchronize]

冒頭のこの部分でpull_requestの「opened:プルリクオープン時」と「synchronize:オープン済みプルリクに追加プッシュ時」を指定しています。

CI(test)が成功したときだけDeployが実行されるWorkflow (Job)の書き方

jobs:
  test: # <- (a)
    name: CI Test
    runs-on: ubuntu-latest

# ...中略...

  deploy_to_zeit_now_staging: # <- (b)
    name: Deploy and Alias with PR number
    runs-on: ubuntu-latest
    needs: test
#   ↑`needs`で指定した値(この場合`test`)をIDに持つJob(a)が
#    正常終了した場合だけこのJob(b)が実行される

コメントに書いたとおりですが、needs:に指定したJob IDが正常に終了したら実行されます。
ちなみにJob IDは同じWorkflow内で重複しなければ任意のものを指定できます。また、配列で指定すれば複数のJobの正常終了を条件にすることも可能(GitHub Help)です。

実行するアクションの中でPull Request(PR)のNumber(#99)やRepository名を取得する方法

${{ github.event.repository.name }}にリポジトリの名前が、${{ github.event.number }}にプルリクNumberが入っていて、以下のようにRunコマンドの中に書くと実行時に展開されます。

      - name: Alias with PR number
        env:
          ZEIT_TOKEN: ${{ secrets.ZEIT_TOKEN }}
        run: >
          now alias
          --token ${ZEIT_TOKEN}
          `cat ${HOME}/deployment-url.txt`
          ${{ github.event.repository.name }}-pr-${{ github.event.number }}.now.sh

その他に取得できる情報は以下のページに書いてあります。
Contexts and expression syntax for GitHub Actions - GitHub Help

ちなみに、上記コードのrun: >というのは、それ以降のヒアドキュメント文字列を半角空白()で連結するYAMLの記法です。

Zeit NowにPR毎のアプリ(Review Apps)をPR NumberをURLに含むかたちでDeployする方法

プルリク内容を本番に近い状態で確認できるようにすると、コードに加えて動作もレビューすることができます。これは、個人的にHerokuのキラー機能と思っているHeroku Review Appsで実現されているものですが、同じことをZeit Nowで実現するためのJobです。

  deploy_to_zeit_now_staging:
    name: Deploy and Alias with PR number
    runs-on: ubuntu-latest
    needs: test

    steps:
      - uses: actions/checkout@v1
        with:
          fetch-depth: 1

      # (1)
      - name: "[INFO] Versions"
        run: |
          echo "node: `node --version`"
          echo "npm:  v`npm --version`"
          echo "yarn: v`yarn --version`"
          echo "now:  v`now --version`"

      - name: Deploy
        env: # (2)
          ZEIT_TOKEN: ${{ secrets.ZEIT_TOKEN }}
        run: > # (3)
          now deploy
          --build-env NODE_ENV=production
          --env NODE_ENV=production
          --public
          --no-clipboard
          --token ${ZEIT_TOKEN}
          > ${HOME}/deployment-url.txt

      - name: Alias with PR number
        env:
          ZEIT_TOKEN: ${{ secrets.ZEIT_TOKEN }}
        run: >
          now alias
          --token ${ZEIT_TOKEN}
          `cat ${HOME}/deployment-url.txt`
          ${{ github.event.repository.name }}-pr-${{ github.event.number }}.now.sh

この設定コードのポイントとしては、以下3点です。

  1. Zeit Nowのデプロイ等のコマンドラインツールnowは、nodeyarnと同じく(1)でバージョン表示しているようにubuntu-latestに最初からインストールされています1
  2. (2)の部分で指定しているsecrets.ZEIT_TOKENZeitのTokensページで発行したものを、対象のリポジトリ設定(settings/secrets)にZEIT_TOKENという名前で保存すれば使えます
  3. 同一Job内のStep間で値を受け渡ししたいときは、(3)> ${HOME}/deployment-url.txtのように${HOME}ディレクトリ以下にファイルとして保存し、以降のStepで`cat ${HOME}/deployment-url.txt`のように読み出すことが可能です

DeployされたReview AppのURLをPRにコメントとして書き込む方法

  post_comment_review_app_url:
    name: Post comment that review app URL when PR opened
    runs-on: ubuntu-latest
    needs: deploy_to_zeit_now_staging

    steps:
      - name: Post comment review app URL by GitHub API
        if: github.event_name == 'pull_request' && github.event.action == 'opened'
        run: >
          curl
          -X POST
          -H "Authorization: token $GITHUB_TOKEN"
          -H "Accept: application/vnd.github.v3+json"
          --data "{ \"body\": \"Review-App was deployed.\nhttps://${{ github.event.repository.name }}-pr-${{ github.event.number }}.now.sh\" }"
          ${{ github.event.pull_request.comments_url }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

プルリクのオープン時のみ実行されるJob

冒頭でプルリクのオープン時・追加Push時に実行されるWorkflowについて説明しましたが、以下の部分ではjob毎に実行条件を指定しています。以下の場合、プルリクでオープン時のみ実行されます。2

        if: github.event_name == 'pull_request' && github.event.action == 'opened'

GitHub Actionsの中からGitHub APIを叩く

GitHub Actions実行時に自動でセットされているsecrets.GITHUB_TOKENには書き込み権限があるため、curlGitHub APIのコメント投稿(Issue Comments)のエンドポイント${{ github.event.pull_request.comments_url }}にPOSTしてあげればOKです。

        run: >
          curl
          -X POST
          -H "Authorization: token $GITHUB_TOKEN"
          -H "Accept: application/vnd.github.v3+json"
          --data "{ \"body\": \"Review-App was deployed.\nhttps://${{ github.event.repository.name }}-pr-${{ github.event.number }}.now.sh\" }"
          ${{ github.event.pull_request.comments_url }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  1. その他に使えるSoftwareの一覧:Software installed on GitHub-hosted runners - GitHub Help 

  2. その他if:に指定できる条件:Workflow syntax for GitHub Actions - GitHub Help 

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away