GitHubの運用をDRYにする「機能特化リポジトリ」構成
AIでコードを量産した結果、管理するGitHubリポジトリが増えて、手間に悩んでいる方も多いのではないでしょうか。いくつものリポジトリで似たような設定変更をくり返すのは、つらいですよね。
運用をDRYにしたくて考えたのが、今回ご紹介する「機能特化リポジトリ」構成です。小さな役割を果たすリポジトリをいくつか配置して、メインとなるリポジトリを支えます。
実装したばかりで、まだ調整が必要かもしれませんが、今のところ気に入っているので紹介させてください。
機能特化リポジトリ
現在、5つの機能特化リポジトリを配置しています。
- workflows:再利用可能なワークフロー
- actions:複合アクション
- mise-tasks:miseの共通タスク
- renovate-config:Renovateの共通設定
- repo-template:リポジトリ作成時のテンプレート
それぞれ簡単に説明します。
workflows
workflows は、再利用可能なワークフロー (reusable workflow) を提供するリポジトリです。
たとえば、コードの書式や動作を検証するための validate.yml を置いておくと、メインリポジトリ側では次のように uses: で呼び出すだけで済みます。
jobs:
validate:
uses: iwamot/workflows/.github/workflows/validate.yml@33f77c21f5d0189c92454aa0b8b2a809549bc598 # v1.0.0
再利用可能なワークフローを使うことで、コードのチェックアウト、ツールのセットアップ、検証スクリプトの実行といった具体的な手順は、workflows 側に定義するだけで済みます。改善したいときも、workflows 側を編集すればメインリポジトリに反映されます。
actions
actions は、複合アクション (composite action) を提供するリポジトリです。
複合アクションは、ワークフローで使う複数のステップをひとつにまとめて呼び出せる仕組みです。たとえば mise-validate という複合アクションには「コードのチェックアウト → miseによるツールのセットアップ → 検証スクリプトの実行」という一連のステップがまとめてあります。
前述の workflows では、次の2種類のワークフローで、この mise-validate を呼び出しています。
-
validate.yml:テストカバレッジの計測を含まない -
validate-with-coverage.yml:テストカバレッジの計測を含む
steps:
- uses: iwamot/actions/mise-validate@ede7d3fc079a3d2eda26b5c285dfa4b11d78b672 # v0.3.0
このように、ワークフロー間で共通する手順があれば、複合アクションにまとめてDRYに保てます。
なお、初めは workflows に複合アクションを置く案も考えました。が、そうしてしまうと、コミットSHAへのピン留めが難しくなります。そのためリポジトリを分けました。actions のコミットSHAにピン留めし、workflows から呼び出す構成が素直だと思います。
mise-tasks
mise-tasks は、開発で使うコマンドをmiseのタスクとして提供するリポジトリです。
たとえば gha-lint というタスクには、GitHub Actionsワークフローを検査するツール群 (pinact, zizmor, actionlint, ghalint) のコマンドをまとめています。
pinact run
zizmor --fix .github/workflows/
actionlint
ghalint run
メインリポジトリの mise.toml に以下のように書けば、mise run gha-lint コマンドで各ツールによる検査が実行できます。
[task_config]
includes = [
"git::https://github.com/iwamot/mise-tasks.git//.mise/tasks?ref=v1.0.0",
]
独立したリポジトリに切り出したことで、タスクの内容や、実行に必要なツールを一元管理できるようになりました。
renovate-config
renovate-config は、Renovateの共通設定を提供するリポジトリです。
Renovateは依存関係のバージョン更新を自動化するツールで、動作ルールをJSONで細かく設定できます。各リポジトリに似たような設定をコピペする運用はつらいので、共通の設定をリポジトリに切り出しました。
メインリポジトリの .github/renovate.json では、次のように extends します。
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>iwamot/renovate-config#v0.10.0"]
}
自動マージの対象や、サプライチェーン攻撃を見越したセキュリティポリシーなどを renovate-config 側で一元管理できるので、事故が起きにくくなります。
repo-template
repo-template は、GitHubのテンプレートリポジトリ機能を有効化したリポジトリです。運用中のメインリポジトリをDRYに保つためのものではなく、新規リポジトリを作る時のテンプレートとして使います。
この repo-template を指定してリポジトリを作ると、以下のようなファイルを含んだ状態で始められます。
-
workflowsを呼び出すための.github/workflows/*.yml -
mise-tasksをincludesしたmise.toml -
renovate-configをextendsした.github/renovate.json
「機能特化リポジトリ」構成のベースラインが整ったリポジトリを手軽に用意できるようになり、初期設定の手間が減りました。
実際の利用例
これらの機能特化リポジトリを実際に使っている例として、以下の2つがあります。
また、個々の機能特化リポジトリでも、他の機能特化リポジトリを便利に使っています。たとえば、mise-tasks で使うツールのバージョンを更新するために renovate-config を使う、などです。
依存関係を表にすると、次のようになります。
| リポジトリ名 | workflows |
actions |
mise-tasks |
renovate-config |
|---|---|---|---|---|
collmbo |
✅ | ✅ | ✅ | |
marp-agent-mcp |
✅ | ✅ | ✅ | |
workflows |
✅ | ✅ | ✅ | ✅ |
actions |
✅ | ✅ | ✅ | |
mise-tasks |
✅ | ✅ | ✅ | |
renovate-config |
✅ | ✅ | ✅ | |
repo-template |
✅ | ✅ | ✅ |
始めるなら
もし「機能特化リポジトリ」構成を試してみたい方は、まず workflows から始めてはいかがでしょうか。
miseやRenovateはともかくとして、GitHub Actionsのワークフローを使っていないリポジトリは少ないはずです。再利用可能なワークフローを切り出すだけでも、運用が軽くなったと感じられると思います。
ちなみにShopifyでも、下記のリポジトリに切り出しています。
おわりに
複数のGitHubリポジトリを運用していたら、いつしか自分なりの型ができてきました。具体例として「miseタスクによるコードの検証」「Renovateによる依存関係の自動更新」といったワークフローがあります。
その型をDRYに実装した結果、今回ご紹介した「機能特化リポジトリ」構成が生まれました。miseにも、Renovateにも、GitHubにも、便利な設定共有機能があったおかげです。
実際に試している感想としては、メインリポジトリ側で考えることが減って、楽になったように思います。さらに副次的な効果として、新しいリポジトリを作るハードルが下がったため、OSSを公開するモチベーションが高まりました。あとは実践あるのみです。
この記事が、複数リポジトリの運用を軽くしたい方の参考になれば幸いです。
Discussion