GIthub Actions で Git Submodule を 最新に更新して処理する
はじめに
ポートフォリオサイトを、Github Actionsでビルド・Github Pagesで公開というように運用しているんですが、他のリポジトリにあるプロジェクトもGithub Pagesで公開したくなることがありました。Github Pagesのリポジトリで、公開したいプロジェクトのリポジトリをGit Submoduleとして参照することで、これは実現できます。しかしこのままでは、Github PagesのリポジトリでSubmoduleを更新しないと、参照先のリポジトリへの変更が適用されません。これは面倒なので、参照先リポジトリが変更されたタイミングで、自動でSubmoduleを更新してビルドをするようなものを作りました。
WebhookでWorkflowをトリガーする
Github ActionsのWorkflowは、特定の条件でそれが起動するように記述します。例えば、「masterブランチにpushされた」などです。前述のようなことを実現するには「リポジトリAのmasterブランチにpushされた」をトリガーに、リポジトリBのWorkflowを起動できれば良さそうです。しかし、直接そのようなトリガーを記述することはできません。
そこで使うのが repository dispatch event です。repository dispatch event を使えば、リポジトリ外部からのAPI呼び出しをトリガーにすることができます。
参考:Github Actions を API から実行する - Qiita
以下、Submodule参照元のリポジトリをsubmod_action_main、Submodule参照先のリポジトリをsubmod_action_sub とします。
GitHub - w-haibara/submod_action_main
GitHub - w-haibara/submod_action_sub
参照元リポジトリ submod_action_main に、repository dispatch event でトリガーするWorkflowを作成します。
下記のWorkflowは「このリポジトリに対してAPI呼び出しがあったとき、Github Actions上でecho "Hello!" を実行する」ものです。
name: Update Submodule on: repository_dispatch: types: [update] jobs: build: runs-on: ubuntu-latest steps: - name: Hello run: | echo "Hello!"
このWorkflowを実行するためのAPI呼び出しは、以下のようにcurlで行うことができます。
この際、指定するURLは、
https://api.github.com/repos/<ユーザー名>/<リポジトリ名>/dispatches
となります。
また、環境変数 DISPATCH_TOKEN は、API呼び出しの対象とするリポジトリのシークレットです。
ターミナルで下記のcurlを実行してみます。
curl -vv \[f:id:w_haibara:20200613025711p:plain] -H "Authorization: token ${{ DISPATCH_TOKEN }}" \ -H "Accept: application/vnd.github.everest-preview+json" \ "https://api.github.com/repos/w-haibara/submod_action_main/dispatches" \ -d '{"event_type": "update"}'
実行すると、Status: 204 No Content が帰ってくると思います。
Workflowの実行結果を見てみると、echo "Hello!" が実行されていることを確認できます。
これで、Web APIを通して外部からトリガーできるWorkflowを作ることができました。
WorkflowからAPI呼び出し
次に、先ほどターミナル上のcurlで行ったAPI呼び出しを、Workflowから行います。
下記に、「masterブランチにpushがあったとき、API呼び出しを行う」Workflowを示します。
ここで ${{ secrets.DISPATCH_TOKEN }} としている部分は、Github内に DISPATCH_TOKEN という名前で登録した、API呼び出しの対象とするリポジトリのシークレットです。
name: Dispatch on: push jobs: build: runs-on: ubuntu-latest steps: - run: | curl -vv -H "Authorization: token ${{ secrets.DISPATCH_TOKEN }}" -H "Accept: application/vnd.github.everest-preview+json" "https://api.github.com/repos/w-haibara/submod_action_main/dispatches" -d '{"event_type": "update"}'
submod_action_sub/dispatch.yml at master · w-haibara/submod_action_sub · GitHub
このWorkflowと、先ほどのrepository dispatch event を組み合わせると、冒頭で言っていた「リポジトリAのmasterブランチにpushされたら、リポジトリBでビルドをする」ということが可能となります。
(リポジトリAのmasterブランチにpush --> Web API 呼び出し (リポジトリAのWorkflow) --> repository dispatch eventが発火 (リポジトリBのWorkflow) --> リポジトリBのビルド)
Submoduleの更新
後は、参照元のリポジトリ(repository dispatch event を使ったリポジトリ)で、Submoduleを更新してビルドするだけです。Workflowは下記のようになります。
name: Update Submodule on: repository_dispatch: types: [update] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 with: submodules: true - name: Update submodule run: | git submodule update --remote ./submod_action_sub/ - name: Git commit run: | git config --local user.name "w-haibara" git config --local user.email "hwhaibarawataru@gmail.com" git add -A git status git commit -m "update submodule (by update_submodule.yml)" - name: Git push uses: ad-m/github-push-action@v0.5.0 with: branch: master github_token: ${{ secrets.GITHUB_TOKEN }} - name: Main process run: | bash ./main.sh
submod_action_main/update_submod.yml at master · w-haibara/submod_action_main · GitHub
やっていることは
Submoduleの更新 --> それに伴う変更をステージング --> 変更をコミット --> メイン処理
という流れです。
ここでは、メイン処理としてシェルスクリプトmain.sh を実行しています。
完成形を試す
さて、完成したシステムを動かしてみます。
初期状態として、submod_action_subには、Helloという文字列が書き込まれたtext.txtが置かれています。
また、submod_action_mainには下記のシェルスクリプトmain.shが置かれています。これは ./submod_action_
sub/text.txtの内容を出力するものです。
#!/bin/bash while read line do echo $line done < ./submod_action_sub/text.txt
まず、submod_action_mainをクローンし、submod_action_subをSubmoduleとして取り込みます。
$ git clone https://github.com/w-haibara/submod_action_main $ cd submod_action_main $ git submodule add https://github.com/w-haibara/submod_action_sub
こうすることで、現時点で最新のsubmod_action_subの内容が取り込まれます。
試しに、main.shを実行すると、現在の./submod_action_sub/text.txtの内容である「Hello」が出力されるはずです。
$ bash ./main.sh Hello
次に、submod_action_subを別にクローンし、text.txtに変更を加えます(「Yeah!」という文字列を書き込みます)。
$ git clone https://github.com/w-haibara/submod_action_sub $ cd submod_action_sub $ echo "Yeah!" > ./text.txt $ git add . $ git commit -m "Update text.txt" $ git push origin master
プッシュを終えたら、Githubでsubmod_action_subのActionsのページを確認します。
API呼び出しのWorkflowが完了しています。
次に、Githubでsubmod_action_mainのActionsのページを確認します。
こちらもWorkflowが完了しているようです。
Workflowの詳細を見てみます。
先ほど書き込んだ「Yeah!」が出力されています!無事にSubmoduleの更新が行われていることを確認できました。