Github Actions で他のリポジトリからの変更通知を受け取ってPRを作成する Workflow

5 min読了の目安(約4900字TECH技術記事
Likes25

やりたいこと

  • リポジトリ A は npm package を publish したことを リポジトリ B に通知したい
  • リポジトリ B は 通知を受けたら package.json を更新する PR を作成したい

個人のリポジトリでの依存ならこの需要は少ないかもしれませんが、社内でリポジトリを分割してたりすると、更新漏れが発生したりします。それを機械的に防ぎたい。でも手動マージはしたくないのでPR作成まで。そのぐらいの温度感を実現したい、という感じ。

また、リポジトリ B は リポジトリ A の通知によらず、手動でそのタスクを実行できるようにしておきたいです。

(ネタバレすると、先に手動のタスクがあって、その上でリポジトリ間通知を実装しました)

(構成要素とレシピ紹介がメインで、コード自体は動いてたコードからの切り貼りなので、そのままは動かないかも。後で要確認)

実装方法

GitHub Actions の Trigger として、 Workflow Dispatch と Repository Dispatch があります。Workflow Dispatch は Actions の管理画面から手動での実行、 Repository Dispatch は GitHub API からの通知を受けてトリガーを実行します。

どちらも引数を取れます。Workflow Dispatch なら管理画面からの入力、Repositry Dispatch なら client_payload の引数で渡します。

通知を受け取って package.json を更新する側の workflow

.github/workflows/update-packages.yaml

name: Update Packages
on:
  repository_dispatch:
    types: [update-packages] # with client_payload.packages
  workflow_dispatch:
    inputs:
      packages:
        description: ''
        required: true
        default: ''
jobs:
  update-packages:
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: setup Node
        uses: actions/setup-node@v1
      - name: Install
        run: npm install
      - Update packages by workflow_dispatch
        if: ${{ github.event.inputs.packages != null }}
        run: npm update ${{ github.event.inputs.packages }}
      - Update packages by repository_dispatch
        if: ${{ github.event.client_payload.packages != null }}
        run: npm update ${{ github.event.client_payload.packages }}
      - name: Create Pull Request
        id: cpr
        uses: peter-evans/create-pull-request@v3
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: 'Update packages'
          committer: GitHub <noreply@github.com>
          author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
          signoff: false
          branch: feature/update-package
          branch-suffix: timestamp
          delete-branch: true
          title: 'Update Packages by CI'
          body: |
            @${{ github.actor }}
            ```
            ${{ github.event.inputs.packages }}
	    ${{ github.event.client_payload.packages }}
            ```
      - name: Check Pull Request
        run: |
          echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
          echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"

通知する側の workflow

.github/workflows/publish-and-notify.yaml

Github Private Token を発行して、 ↑ で定義した Repository に向けて次の curl を叩くことで更新できます。

個人アクセストークンを使用する - GitHub Docs

Repo 権限が必要です。

curl  -v  -H "Authorization: token <GITHUB_PRIVATE_TOKEN>" -H "Accept: application/vnd.github.everest-preview+json" "https://api.github.com/repos/<name>/<repo>/dispatches" -d '{"event_type": "update-packages", "client_payload": {"packages": "lodash@4.17.20"}}'

これを repository_dispatch したい側の merge trigger で、 repostitory dispatch を実行します。
注意点として、 secrets.GITHUB_TOKEN は権限が足りず repository_dispatch がトリガーできません。トークンを発行する必要があります。

今回は github package registry に publish してます。npm トークンが不要で、社内のリポジトリ間という事情です。 npm に publish したい場合、 npm の token が必要です。

Publish to npm · Actions · GitHub Marketplace

name: publish-and-dispatch
on:
  push:
    branches:
      - master
jobs:
  release:
    name: Setup
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: setup Node
        uses: actions/setup-node@v1
        with:
          registry-url: "https://npm.pkg.github.com"
      - name: install
        run: npm install
      - name: build
        run: npm run build
      - name: publish
        run: |
          npx can-npm-publish --verbose && npm publish || echo "Does not publish"
        env:
          NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: package-version-to-git-tag
        uses: pkgdeps/action-package-version-to-git-tag@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          github_repo: ${{ github.repository }}
          git_commit_sha: ${{ github.sha }}
          git_tag_prefix: "v"
      - name: dispatch update-packages
        uses: peter-evans/repository-dispatch@v1
        with:
          repository: github_name/repo
          token: ${{ secrets.GITHUB_PERSONAL_TOKEN }}
          event-type: update-pkgs

secrets に GITHUB_PERSONAL_TOKEN を設定してあるのを前提としてます。dispatch 対象は自分ではなく、対象です

色々サボってて、本当は変更があったときだけ publish したいんですが、それはまあなんとでもなるので…