LoginSignup
2
2

More than 3 years have passed since last update.

GitHub Actionを使って複数レポジトリ間でファイルを同期する

Last updated at Posted at 2020-12-08

GitHubの複数レポジトリで使用している共通のスクリプトやworkflowなど、メンテの際にPRして回るのが面倒だったので自動でPRが作られる様にしてみた。

検討したけど没にした案たち

採用案

便利なライブラリoctopullを見つけたのでこれを使ってGitHub Workflowでやる :octocat:

サンプルコード

インラインで解説コメントしてあります。

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))

実行例

注意事項

  • Personal Access Tokenを作る際に、repoだけだと.github/workflows以下のファイルのコミットで権限足りなくて404エラーになってしまうのでworkflowの権限が必要image.png

  • Organizationのレポジトリの場合、GH_TOKENはOrganization Secretsへ登録しておくとどのレポジトリでも使えて便利

オマケ

ローカル環境でGitHub Actionの動作確認をするにはactが便利です。

  • pull_request-closed.jsonにwebhookで飛んでくるJSONを保存しておいて、イベントデータとして-eで指定。
  • jqactがデフォルトで使う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
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2