GitHub Actionsでprivateなgolang packageのupdate PullRequestをいい感じに自動作成したい
記事のターゲット
- GitHub Actionsで複数repositoryに対してPullRequestを作成したい人
- private repositoyでgolangの共通ライブラリを取り扱いたい人
背景
- 外部APIのラッパーをclientライブラリとしてgolangで実装した
- 社内で使う用途なのでGitHubのprivate repositoryで管理した
- clientライブラリを利用したいprivate repositoryは10以上存在している
private repositoryとは言えgo get
できるような状態を作った上で、clientライブラリ側の更新時にいい感じに利用者に更新したことを伝えたい…
(とは言えshell芸を披露したいわけではない)
概要
いろいろ考えた結果、以下が良いのではないかという結論に至りました
- clientライブラリ側のGitHub Actionsでrepository dispatchを使うことで利用者側に変更があったことを伝える
- 利用者側のGitHub Actionsで変更を受け取ったらGOPRIVATEを使ってprivate repositoryでも
go get
によるpackageの更新を行う - 2.で更新した内容をPullRequestにする
GitHub Actions
GitHub利用者なら一度は聞いたことのあるCI/CDワークフローのツールです
GitHubの操作をトリガーに起動できるところに大きな特徴があります
社内で利用することもありGitHub Organizationと合わせると相性が良かったので採用しています
今回のユースケースだと1回の起動あたり1分もかからないので費用面での心配もなかったです
repository dispatch
基本的にGitHub Actionsでは他のrepositoryに影響するジョブを組むことが難しいのWebhookイベントとしてトリガーできるrepository_dispatch
を利用することになります
動作確認の際にもcurlで実行することもできるので今回のようなケースでおすすめです
$ curl -X POST -H "Authorization: token $TOKEN" -H "Accept: application/vnd.github.everest-preview+json" -d '{"event_type": "event_name"}' -i https://api.github.com/repos/{user_name}/{repository_name}/dispatches
GOPRIVATE
golangv1.13
から追加された環境変数でプライベートな環境に配置したモジュールを取得するために設定します
$GOPRIVATE
にマッチするパスの場合、プロキシ(proxy.golang.org)もチェックサムのDB(sumdb)も使用されません
それ故にprivate repositoryのモジュールをgo get
できるということです
実際の設定
基本的な設定項目については明らかになったので、実際に設定していきます
今回はclientライブラリ側と利用者側にGitHub Actionsのworkflowを設定することで「privateなgolang packageのupdate PullRequestをいい感じに自動作成」します
clientライブラリ側
タグ打ちを行った際に更新を通知するようなworkflowを組みます
repository_dispatchを行うためのactionはMarketplaceから提供されているのでそれを利用します
name: dispatch-update
on:
push:
tags:
- 'v*'
jobs:
release:
strategy:
matrix:
repo: ['{repository1}','{repository2}','{repository3}']
name: dispatch
runs-on: ubuntu-latest
steps:
- name: dispatch update module
uses: peter-evans/repository-dispatch@v1
with:
repository: {user_name}/${{ matrix.repo }}
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: update-client
注意点としてはREPO_ACCESS_TOKEN
にはpersonal access tokenを指定する必要がある点です
GITHUB_TOKEN
などにはdispatchを行う権限がないため、repo
の権限を付与したpersonal access tokenを用意してrepositoryのsecretsに登録します
利用者側
dispatchのイベントを受け取ってPRを作成するworkflowを組みます
pull requestを作成するためのactionもMarketplaceから提供されているのでそれを利用します
name: update-client
on:
repository_dispatch:
types:
- update-client
jobs:
create-pull-request:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: 1.16.3
- name: Set up github token
run: git config --global url."https://${{ secrets.GO_MODULES_TOKEN }}:x-oauth-basic@github.com/".insteadOf "https://github.com/"
- name: Update client
run: GOPRIVATE="github.com/{user_name}/*" go get github.com/{user_name}/{client_repository_name}@latest
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
title: "✨ Update API Client"
base: staging
branch: update-client
git config --global url."https://${{ secrets.GO_MODULES_TOKEN }}:x-oauth-basic@github.com/".insteadOf "https://github.com/"
のコマンドを使用して
GitHub(https://github.com/)にアクセスする際にGO_MODULES_TOKEN
のpersonal access tokenを利用したアクセスに切り替えます
更にGOPRIVATE
を設定することでprivate repositoryからgo get
できるようにします
全体の流れ
- clientライブラリのprivate repositoryでタグ打ちを行う
- GitHub Actionが発火する(tag push trigger)
- jobから利用者側のrepositoryに対して
repository_dispatch
を行う - 利用者側のrepositoryのGitHub Actionが発火する(repository dispatch trigger)
- job内で
go get
によりpackageのupdateを行い、PullRequestを作成する
所管
このシンプルな設定により利用者側のrepositoryに更新の通知をすることができました
PullRequestを作成することで更新後のCI実行も行えるのが良いと感じています
しかし、publisherであるclientライブラリ側が利用者一覧を管理しなければならないところはちょっとイケてない気がしています(いい方法があったら教えて欲しい…)
Discussion