📚

GitHub ActionsとPull Requestを活用した、フロントエンドとの同期の自動化

2023/01/03に公開約7,100字

あけまして、おめでとうございます。神社のおみくじで、人生はじめて大吉を引きました、silverbirder です。

普段の業務で、FigmaのデザイントークンやAPIのスキーマファイル、i18nのメッセージファイルなどを、フロントエンドへ同期するコミュニケーションが不毛に感じています。そこで、GitHub ActionsとPull Requestを活用して、同期コミュニケーションを削減する仕組みを紹介します。

目新しい情報はないかもしれませんが、同じお困りごとを持つ人へ助けになれば、幸いです。

GitHub Actionsで使用するもの

今回紹介する仕組みの核となるのが GitHub Actionsのrepository-dispatch トリガーです。

https://docs.github.com/ja/rest/repos/repos?apiVersion=2022-11-28#create-a-repository-dispatch-event

このトリガーは、GitHub APIを経由して、GitHub Actionsのワークフローを起動することができます。そのため、次のように 異なるリポジトリでのGitHub Actionsワークフローを連携できます。

repository-dispatchとcreate-pull-requestは、次のGitHub Actionsです。

https://github.com/peter-evans/repository-dispatch
https://github.com/peter-evans/create-pull-request

  • respository-dispatch
    • repository-dispatch-eventをdispatchするAction
  • create-pull-request
    • Pull Requestを作成するAction

これらのGitHub Actionsを使わずに gh などを使って代替できますが、便利なモノを使って楽をします。

GitHubリポジトリ以外からのトリガー

GitHubのリポジトリ(username/other)からトリガーだけでなく、他のサービスからでもトリガーできます。例えば、Google Sheets からだと、Google Apps ScriptからGitHub APIを呼べばよいです。

他にも、Kibelaのoutgoing webhookを、Serverが受けて、ServerがGitHub APIを呼び出す方法があります。

Serverは、IFTTTやZapierのようなサービスでも良いですし、自前のサーバーでも良いでしょう。

自動commit

schemaファイルから、型を生成したい(yarn codegen)こともあると思います。そういうときは、次のフローを追加します。

git-auto-commit-actionは、変更したファイルをgit commitするだけのActionです。

https://github.com/stefanzweifel/git-auto-commit-action

create-pull-requestだけでも、自動commitすることができます。私は、次のケースで使用しました。

  • FigmaのDesign Tokensで、Figma上からPull Requestを作成する。
    • GitHub Actionsで、style dictionaryのbuildしたものをcommitしたい
on:
  pull_request:
    types: [opened]
jobs:
  update:
    if: startsWith(github.head_ref, 'figma/')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm ci
      - run: npx style-dictionary build
      - uses: stefanzweifel/git-auto-commit-action@v4

Preview

Figmaのデザイントークンや、i18nのメッセージファイルを更新したとき、Previewできる仕組みがあると、画面の確認ができて、良いです。

例えば、vercelやchromaticのpreviewです。

https://vercel.com/docs/concepts/deployments/preview-deployments
https://www.chromatic.com/docs/review

サンプルコード

i18nのメッセージファイルをフロントエンドへ同期するGitHub Actionsを、紹介します。

repository やること
username/frontend i18nのメッセージファイルを利用
username/message i18nのメッセージファイルを管理
# <username/message>/.github/workflows/main.yml
on:
  push:
    branches:
      - main
    paths:
      - 'i18n/**'
jobs:
  dispath:
    name: Setup
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: peter-evans/repository-dispatch@v1
        with:
          repository: username/frontend
          token: ${{ secrets.PAT }}
          event-type: create-pull-request-message
          client-payload: '{"ref": "${{ github.ref }}"}'
# <username/frontend>/.github/workflows/main.yml
on:
  repository_dispatch:
    types: [create-pull-request-message]
jobs:
  createPullRequest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/checkout@v3
        with:
          repository: username/message
          ref: ${{ github.event.client_payload.ref }}
          path: "tmp/"
      - run: |
          mv tmp/message.json src/message.json
          rm -rf tmp
      - uses: peter-evans/create-pull-request@v4

受け入れテストをマークダウンで管理

安心してマージできるように、受け入れテストを整備しておきましょう。

具体的には、cucumberで仕様書をMarkdown(MARKDOWN_WITH_GHERKIN)で管理します。

例えば、次のような仕様書です。

# Feature: Staying alive

This is about actually staying alive,
not the [Bee Gees song](https://www.youtube.com/watch?v=I_izvAbhExY).

## Rule: If you don't eat you die

![xkcd](https://imgs.xkcd.com/comics/lunch_2x.png)

`@important` `@essential`
### Scenario Outline: eating

* Given there are <start> cucumbers
* When I eat <eat> cucumbers
* Then I should have <left> cucumbers

#### Examples:

  | start | eat | left |
  | ----- | --- | ---- |
  |    12 |   5 |    7 |
  |    20 |   5 |   15 |

このMarkdownも、GitHub ActionsでPull Requestするフローに載せましょう。新しいシナリオが追加された場合、(cucumberのライブラリ上) テストコードが存在しないとエラーとなります。

機能で担保したいシナリオをMarkdownで管理していくことで、次のメリットがあります。

  • 仕様が明確になる
  • CIで受け入れテスト(cucumber)を動かし成功すると、仕様を満たす状態 となる

ハマったこと

GitHub Actions Botのcommitで、他のワークフローをトリガーできない

https://github.com/orgs/community/discussions/27028

tokenに、PATを渡すように変更すれば解決します。

他の解決策としては、workflow_run のトリガーを使えます。

https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#workflow_run

ただし、デフォルトブランチでのみ動作します。

repository-dispatchのPOSTは、JSONで制限がある

https://github.com/peter-evans/repository-dispatch#client-payload

同期したいファイルをjsonに変換して、dispatchするeventペイロードに含めようと、当初考えていました。ただ、次の懸念があったため、却下しました。

  • jsonにしてしまうとコメントが消える
  • JSONのバイトサイズに上限がある

そこで、同期したいリポジトリのgithub.refをeventペイロードに含めて、eventを受けた側がソースコードをチェックアウトして使う方針に切り替えました。

終わりに

GitHub ActionsとPull Requestを活用することで、自動的にアプリケーションのソースコードを更新する仕組みを簡単に組み立てられます。
このようなOpsがあれば、Slackでのメッセージラリーをする回数が減らせられます。ぜひ、ご活用ください。

Discussion

ログインするとコメントできます