サーバ側に存在するリソースと同等のファイルをアプリ内部で抱え持つことは度々ある。
手動だと都度サーバ側のリポジトリから最新リソースファイルをアプリ側のリポジトリにコピーする必要があり、
この運用は大抵忘れられがちになるし事故の元。
そこでGitHub Actionsを使って、サーバ側リポジトリの特定ディレクトリを監視して更新されたらアプリ側リポジトリで通知を受け取りファイル群を差し替えてプルリクエストを作る、というのをやってみた。(マージまで自動で行うこともできそうだが流石に確認がないと怖いのでプルリク)
構文についてはGitHub Actionsのワークフロー構文を見ると便利。
サーバ側にワークフローを用意する
リポジトリのActionsタブ > New workflowから新しいワークフローを追加する。
テンプレートは使わないので「set up a workflow yourself」を選択する。
デフォルトでこのようなYAMLができるが、
やりたいことと全然違うので内容は以下のように書き換える。
説明は↓のコード中にコメント。
勝手に追加したらチームに怒られる場合は ローカルリポジトリ/.github/workflows/hogehoge.yml
を追加してプルリクすればOK。
# リポジトリのアクションページに表示される名称
name: Dispatch assets files updated
on:
# masterブランチのAssets以下へのpushを監視する
push:
branches:
- master
paths:
- Assets/*
jobs:
# ジョブID(英字または_で始まり、英数字と-、_で構成されていたらなんでもOK)
dispatch-directory-changes:
strategy:
matrix:
# 様々なジョブの設定を定義しておける。ここでは通知を受け取るリポジトリ一覧を定義しておく。
repo: ['<オーナー名>/<アプリ側リポジトリ名>']
name: Do dispatch-directory-changes
# ジョブが実行されるマシンの種類。
runs-on: ubuntu-latest
steps:
# アプリ側リポジトリで `repository_dispatch` を使って通知を受け取るので `peter-evans/repository-dispatch` を使用
- name: Do repository-dispatch
uses: peter-evans/repository-dispatch@v1
with:
# 対象がPrivateなリポジトリのためtokenをセット(内容は後述)
token: ${{ secrets.<GitHubシークレットキー名> }}
# 定義しておいた通知対象リポジトリを指定
repository: ${{ matrix.repo }}
# イベントタイプを `directory-changes` にしておく
event-type: directory-changes
repository_dispatch
は複数のワークフローを実行でき、カスタムイベントやイベント型を作成可能という特徴があり、
似たようなのにworkflow_dispatch
があり、これは単一の特定ワークフローの実行、ブランチやタグの指定が可能というものらしい。
詳しくはワークフローをトリガーするイベント
挙動としては、
Assets以下の変更がmasterブランチにpushされることをトリガーとして、
matrix.repoに指定したリポジトリに対してdirectory-changes
イベントを発行する。
アプリ側にもワークフローを用意する
ymlの内容は以下のように書き換える。
説明は↓のコード中にコメント。
# リポジトリのアクションページに表示される名称
name: Copy Assets from <サーバ側リポジトリ名>
on:
# repository_dispatchでサーバ側のymlで指定したevent-type `directory-changes`をフックする
repository_dispatch:
types: [directory-changes]
jobs:
directory-changes:
name: Copy Assets
runs-on: ubuntu-latest
steps:
# アプリ側のリポジトリをclone
- name: Clone
uses: actions/checkout@v2
# サーバ側リポジトリをclone
- name: Clone <サーバ側リポジトリ名>
uses: actions/checkout@v2
with:
repository: <オーナー名>/<サーバ側リポジトリ名>
path: <サーバ側リポジトリ名>
token: ${{ secrets.<GitHubシークレットキー名> }}
# サーバ側リポジトリ/Assets以下のファイルをアプリ側リポジトリ/Assetsへコピー
- name: Copy assets files
run: cp <サーバ側リポジトリ名>/Assets/* Assets
# コピーが済んだためcloneしたサーバ側リポジトリを削除
- name: Clean <サーバ側リポジトリ名>
run: rm -rf <サーバ側リポジトリ名>
# プルリク作成
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.<GitHubシークレットキー名> }}
commit-message: 'Update Assets'
branch: feature/asset-files-changes
base: master
# 同一ブランチ名にならないよう後ろにタイムスタンプを付加
branch-suffix: timestamp
delete-branch: true
# レビュワーの指定
reviewers: <ユーザ名 or グループ名など>
例ではプライベートリポジトリにアクセスするために個人アクセストークンをサーバ側/アプリ側それぞれのリポジトリ > Settings > Secretsに登録する。
キー名はGITHUB_
から始まるものは使えないので適当に考える必要がある。
登録したキー名を<GitHubシークレットキー名>
の部分に使う。
例では以下も適宜ご自身のものに変更が必要。
<オーナー名>
-
<サーバ側リポジトリ名>
、 - 各
name
や - コミットメッセージ:
commit-message
、 - ブランチ名:
branch
- 監視対象ディレクトリ:
Assets
- レビュワー:
<ユーザ名 or グループ名など>
peter-evans/create-pull-request を見るとプルリクを作る際にtitleやbody、labelやmilestoneなどなどいろいろ設定できる!便利
実行
サーバ側でAssetsディレクトリの中にhoge.htmlを入れて内容変更した時にアプリ側でうまくプルリクが作られるか検証。
- サーバ側リポジトリでAssets/hoge.htmlを編集してcommit & push。リポジトリ > Actionsタブを見ると走り出した。
- 数秒でエラーなく終わったようだ。
- アプリ側のActionsを見てみるとこちらも数秒で完了。
- アプリ側でプルリクが作られてた。
- hoge.htmlの変更内容も正しい。
素晴らしい!
余談
因みに監視対象のディレクトリ名(例でいうAssets)をリネームするとイベントはハンドリングされるのでアプリ側のワークフローは実行されるけど、
directory-changesのstepsで単に固定ディレクトリ名の内容をcpだけしか行っていないのでエラーになるはず。