🧩

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 側を編集すればメインリポジトリに反映されます。

https://github.com/iwamot/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 から呼び出す構成が素直だと思います。

https://github.com/iwamot/actions

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",
]

独立したリポジトリに切り出したことで、タスクの内容や、実行に必要なツールを一元管理できるようになりました。

https://github.com/iwamot/mise-tasks

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 側で一元管理できるので、事故が起きにくくなります。

https://github.com/iwamot/renovate-config

repo-template

repo-template は、GitHubのテンプレートリポジトリ機能を有効化したリポジトリです。運用中のメインリポジトリをDRYに保つためのものではなく、新規リポジトリを作る時のテンプレートとして使います。

この repo-template を指定してリポジトリを作ると、以下のようなファイルを含んだ状態で始められます。

  • workflows を呼び出すための .github/workflows/*.yml
  • mise-tasksincludes した mise.toml
  • renovate-configextends した .github/renovate.json

「機能特化リポジトリ」構成のベースラインが整ったリポジトリを手軽に用意できるようになり、初期設定の手間が減りました。

https://github.com/iwamot/repo-template

実際の利用例

これらの機能特化リポジトリを実際に使っている例として、以下の2つがあります。

https://github.com/iwamot/collmbo
https://github.com/iwamot/marp-agent-mcp

また、個々の機能特化リポジトリでも、他の機能特化リポジトリを便利に使っています。たとえば、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でも、下記のリポジトリに切り出しています。

https://github.com/Shopify/github-workflows

おわりに

複数のGitHubリポジトリを運用していたら、いつしか自分なりの型ができてきました。具体例として「miseタスクによるコードの検証」「Renovateによる依存関係の自動更新」といったワークフローがあります。

その型をDRYに実装した結果、今回ご紹介した「機能特化リポジトリ」構成が生まれました。miseにも、Renovateにも、GitHubにも、便利な設定共有機能があったおかげです。

実際に試している感想としては、メインリポジトリ側で考えることが減って、楽になったように思います。さらに副次的な効果として、新しいリポジトリを作るハードルが下がったため、OSSを公開するモチベーションが高まりました。あとは実践あるのみです。

この記事が、複数リポジトリの運用を軽くしたい方の参考になれば幸いです。

Discussion