GitHub Actionsで静的Webサイトのリリース手順を簡略化した話

こんにちは、freeeのアクセシビリティーおじさんの中根です。

先日から紹介しているfreeeアクセシビリティー・ガイドラインですが、一般公開に当たって、リリース作業をいかに簡単にするかというところで少しがんばってみたので、今日はそのことについて紹介します。

タイトルの通り、GitHub Actionsを活用しています。

リリースに当たって必要な作業

まず、今ガイドラインの新バージョンをリリースする際の手順をまとめておきます。

  1. 検討用に社内向けに公開しているソースを、一般公開用のリポジトリーに反映
  2. リリースのタグを追加
  3. そのソースからHTMLファイルを生成
  4. そのHTMLを公開サイトにコピー (サイトはAmazon S3)
  5. そのHTMLファイルをまとめたzipファイルを作成
  6. GitHubのリリース・ページでリリースを作成
  7. 5のzipファイルを添付
  8. リリース・ノートを追加

ざっとこんな感じです。 このうち、2の実行をトリガーにして、3~7を自動化しています。

GitHub Actionsでの実装

では、以下本稿執筆時に実際に使っているGitHub Actionsの設定ファイルを見ながら説明します。

name: Publish HTML

ワークフローの名前です。 GitHub Actionsのページに表示されます。

ちょっと実体と一致しない名前になっていますが、最初は上記の4までやれれば良いと思って始めたのでこういう名前になっています。 いずれ変えます。

on:
  push:
    tags: [ "*" ]

このワークフローが実行される条件です。 ここで指定することで、特定のブランチにpushされた場合だけとか、特定のパターンにマッチするタグがpushされた場合といった条件を指定することができます。 ただ、ブランチとタグの両方を指定した条件はここでは書けないらしいです。 そういう指定をしたい場合については後述します。

jobs:
  build:
    runs-on: ubuntu-latest

ここから具体的なタスクの記述が始まります。 "build" というIDのジョブを定義していて、ubuntu-latest上で実行することを指定しています。

1つのワークフローの中には、複数のジョブを記述できます。 複数のジョブがある場合は、基本的には並列に実行されるということですが、今回の場合はそういう込み入ったことは必要ないので、単一ジョブの中に順番にstepを記述していきます。

    steps:
    - name: Extract Branch/Tag Names
      run: |
        echo "::set-env name=NAME::${GITHUB_REF#refs/*/}"
        echo "::set-env name=BRANCH::${GITHUB_REF#refs/heads/}"
        echo "::set-env name=TAG::${GITHUB_REF#refs/tags/}"

最初のステップでは、ブランチ名やタグを環境変数に保存しています。 同じジョブ中であれば、先のステップで設定した環境変数を後のステップ中で参照することができます。

ここで設定した環境変数の値をチェックすることで、以後のステップについて特定のタグやブランチのときだけ実行するようにする、といったことが可能になります。

具体的には、

if: startsWith({{ env.BRANCH }}, "master")

のような感じで指定します。

    - uses: actions/checkout@v2

一般に公開されているactionを使用して、実行環境にリポジトリーをチェックアウトしています。

    - uses: actions/setup-python@v1
      with:
        python-version: '3.7.x'

Python 3.7.xを使うことを指定しています。

    - uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-1

awscliを実行するために必要な認証手順です。

${{ secrets.AWS_ACCESS_KEY_ID }}${{ secrets.AWS_SECRET_ACCESS_KEY }} はそれぞれ、リポジトリーのSettingsの中のSecretsの画面で登録している値と置き換えられます。 Secretsを活用することて、公にできない認証情報を埋め込むことができます。

    - name: Install the Latest pip
      run: python -m pip install --upgrade pip

    - name: Install required modules
      run: python -m pip install -r requirements.txt

最新のpipをインストールして、必要なモジュールをインストールしています。 ここまでで環境設定は完了です。

run: で、シェル・コマンドを指定して実行させることができます。 Ubuntuの場合は、bashが使われます。

    - name: Build HTML with Sphinx
      run: make html

    - name: Publish to S3
      env:
        AWS_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
      run: aws s3 sync build/html/ s3://${AWS_BUCKET}/ --quiet

SphinxでHTMLファイルを生成して、amazon S3のファイルをawscliで更新しています。

    - name: Prepare the HTML Archive
      run: |
        mv ./build/html ./freee-a11y-guidelines-${TAG}
        zip -r ${GITHUB_WORKSPACE}/freee-a11y-guidelines-${TAG}-html.zip ./freee-a11y-guidelines-${TAG}

リリースに添付するために、生成したHTMLファイルをzipファイルにまとめています。

    - name: Create Release
      id: create_release
      uses: actions/create-release@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        tag_name: ${{ github.ref }}
        release_name: Ver. ${{ github.ref }}
        body: |
          Release note here
        draft: true
        prerelease: false

GitHub上で公開するリリースのドラフトを作成します。 リリース名はタグから自動的に付けられます。

リリース本文 (というかbody) には、固定で"Release note here"と入れています。 本当は、リポジトリー中の更新情報から当該リリースの情報を入れ込みたかったのですが、固定でない複数行のテキストを入れる方法がどうにも分からず断念しました。

ちなみに、このステップには id の指定がありますが、この次のステップの中でこのステップの実行結果を参照するために必要なものです。

    - name: Upload Release Artifact
      id: upload_artifact
      uses: actions/upload-release-asset@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        upload_url: ${{ steps.create_release.outputs.upload_url }}
        asset_path: ${{ github.workspace }}/freee-a11y-guidelines-${{ env.TAG }}-html.zip
        asset_name: freee-a11y-guidelines-${{ env.TAG }}-html.zip
        asset_content_type: application/zip

前のステップで作ったリリースに、作っておいたzipファイルを添付しています。

実際のリリース時の作業

ということで、このワークフロー導入後は、リリース時の作業はこうなりました:

  1. 検討用に社内向けに公開しているソースを、一般公開用のリポジトリーに反映
  2. リリースのタグを追加
  3. リリース・ノートを追加してリリースを公開

zipを作ったりファイルをアップロードしたりという部分は、ぼんやりしているとミスが混入しやすい部分だと思うので、この部分を自動化できたのは実に良かったと感じます。 リリース作業が面倒だから、という理由でリリース頻度が下がるというようなことも起こらないですし。 (他の理由で頻度が下がることはもちろんあるでしょうけど。)

フィードバック歓迎です

手探りで使ってみたGitHub Actionsのワークフローの改善案、そしてなによりガイドラインの改善案などありましたら、GitHubリポジトリーのIssuesやPull Requestsからお知らせください。