GitHubの複数レポジトリで使用している共通のスクリプトやworkflowなど、メンテの際にPRして回るのが面倒だったので自動でPRが作られる様にしてみた。
検討したけど没にした案たち
- git submodule / git subtree: 特定ディレクトリにまとまってないので
- post-commit hook: ローカル環境に依存するので
- 良さげなgithub action: https://medium.com/@adrianjost/how-to-sync-github-actions-across-repositories-f0b09dc9a9d8
- masterに直コミットされるぽいので
採用案
便利なライブラリoctopullを見つけたのでこれを使ってGitHub Workflowでやる
サンプルコード
インラインで解説コメントしてあります。
GitHub Action
.github/workflows/octopull.yml
name: レポジトリ共通ファイルの同期
on:
pull_request:
branches:
- main
types: [closed]
paths: # 同期対象のファイルが含まれている場合のみ起動する
- 'hello.sh'
- 'scripts/**'
- '.github/workflows/**'
jobs:
octopull:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true # PRのclose時には発動させない
steps:
- uses: actions/checkout@v2
- name: sync files
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} # 他レポジトリを操作するのでpersonal access tokenをsecretsに登録して使う
run: |
npm install octopull
# npmに登録されてるのが壊れてるので無理やりmv
mv node_modules/octopull/lib/api/ node_modules/octopull/
mv node_modules/octopull/lib/index.js node_modules/octopull/
# PRのdescriptionの複数行をシェルスクリプトで使える様にjqでバラす
# 参考: https://medium.com/agorapulse-stories/how-to-work-with-multiline-string-variables-in-github-actions-23f56447d209
pr_body=$(jq '.pull_request.body' $GITHUB_EVENT_PATH)
pr_body="${pr_body%\"}"
pr_body="${pr_body#\"}"
node scripts/octopull.js '${{ github.event.pull_request.head.repo.name }}' '${{ github.event.pull_request.head.ref }}' '${{ github.event.pull_request.title }}' "$pr_body\n\n---\n\nCreated via ${{ github.event.pull_request.html_url }}"
GitHub Actionで実行するスクリプト
scripts/octopull.js
const octopull = require('octopull')
const current_repo = process.argv[2]
const repos = [ // 同期したいレポジトリが増えたらここに追加していく
'sandbox',
'sandbox2',
].filter(repo => repo != current_repo).map(repo => { // 自分のレポジトリに再帰的にPR作られない様に除外
return {
owner: 'pomu0325',
repo: repo,
defaultBranch: 'main',
platform: 'github'
}
})
const branch = process.argv[3]
const title = process.argv[4]
const message = process.argv[5]
const options = {
files: [ // 同期したいファイルをここに追加していく
'hello.sh',
'scripts/octopull.js',
'.github/workflows/octopull.yml',
],
branch: branch, // autogenerated if blank
message: title, // autogenerated if blank
// OPTIONAL
pullRequest: {
title: title, // autogenerated if blank
body: message.replace(/\\n/g, '\n'), // autogenerated if blank
// OPTIONAL
// assignees: ['username1', 'username2']
// reviewers: ['username3', 'username4']
}
}
repos.forEach((config) => octopull.commit(config, options))
実行例
- マージしたPR: https://github.com/pomu0325/sandbox/pull/3
- 起動されたGitHub Action: https://github.com/pomu0325/sandbox/runs/1516555378?check_suite_focus=true
- 作られたPR: https://github.com/pomu0325/sandbox2/pull/2
注意事項
-
Personal Access Tokenを作る際に、
repo
だけだと.github/workflows
以下のファイルのコミットで権限足りなくて404エラーになってしまうのでworkflow
の権限が必要 -
Organizationのレポジトリの場合、
GH_TOKEN
はOrganization Secretsへ登録しておくとどのレポジトリでも使えて便利
オマケ
ローカル環境でGitHub Actionの動作確認をするにはactが便利です。
-
pull_request-closed.json
にwebhookで飛んでくるJSONを保存しておいて、イベントデータとして-e
で指定。 -
jq
がact
がデフォルトで使うDockerイメージに入ってないのでデカいけどGitHub Actionで使われるイメージに近いやつを-P
で指定(参考: https://github.com/nektos/act#alternative-runner-images )
act -s GITHUB_TOKEN=hogehoge -v -e pull_request-closed.json -P ubuntu-latest=nektos/act-environments-ubuntu:18.04 pull_request