optimise-github-actions について
GitHub Actions の利用状況を測定し、CI 時間や課金分数を安全に削減する変更を導くスキルです。ワークフローを編集する前に、削減量、時間への影響、リスクを見積もります。
主な機能
- 01課金分数と実行時間の測定
- 02ワークフローとジョブの無駄の特定
- 03削減量・速度・リスクの見積もり
- 04ワークフロー変更と検証の案内
活用シーン
- 01時間や費用のかかる CI ジョブの特定
- 02プルリクエストと main の重複実行の確認
- 03キャッシュ、フィルター、ジョブ統合の計画
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ enesgules/ dotfiles --skill optimise-github-actionsインストール後、Claude Code で/optimise-github-actionsを入力して読み込まれたか確認します。
同梱ファイルscripts/measure.mjs
詳細
GitHub Actions を最適化する
請求対象時間と実時間は異なり、CI の無駄の大半はその差にあります。5 分割のマトリックスが 2 分で終わっても、請求時間は 10 分以上になります。5 秒のジョブでも、丸々 1 分が請求されます。main へのマージによって、プルリクエストですでに合格したすべてのテストスイートを再実行することもあります。まず計測し、最も大きな項目から削減しつつ、出荷するものを保護するチェックは維持しましょう。
速度とコストは通常ともに改善しますが、そうならないこともあります。キャッシュや重複作業の削除は、どちらにも効果があります。長いジョブを並列のシャードに分割すると、各シャードでセットアップを再度行うため、CI は速くなりますが、コストは高くなります。小さなジョブを統合すると逆の効果があります。ユーザーがどちらを重視するのかを確認するか、各変更がどちらに影響するのかを明示してください。
1. 計測する
このスキルのフォルダーにあるスクリプトを実行します。
node <skill-dir>/scripts/measure.mjs OWNER/REPO --days 14 --out jobs.json
読み取りアクセス権のある gh だけが必要です。それ以外は必要ありません。次の内容が出力されます。
- 請求対象の合計分数、月間の推定分数、端数処理で失われた分数、キャンセルおよび失敗した実行の分数
- ワークフローとイベント別の表、および各ジョブが実行された割合を示すジョブ別の表
- 成功した実行の実時間の中央値と p90
- 各 PR ブランチが開始する実行数
jobs.json には、追加の質問に対応するための生データが保存されます。実行が多いリポジトリでは、数分かかります。パブリックリポジトリでは標準ランナーは無料なので、数値はランナーの実行時間として扱い、速度の改善に取り組んでください。
ジョブ内で時間がどこにかかっているかを確認するには、典型的な実行のステップごとの所要時間を出力します。
gh api repos/OWNER/REPO/actions/runs/RUN_ID/jobs --paginate \
-q '.jobs[] | .name, (.steps[] | select(.started_at) | " \((.completed_at|fromdate)-(.started_at|fromdate))s \(.name)")'
組織のプランによって、含まれる分数とマージキューを利用できるかどうかが決まります。gh api orgs/ORG -q .plan.name で確認してください。
2. 各ジョブが何を保護しているかを把握する
変更を提案する前に、以下を確認してください。
- 各ワークフローのトリガー、
concurrency、パスフィルター、needs:の依存関係グラフ。最長のneeds:チェーンがクリティカルパスであり、CI を高速化できるのはクリティカルパスを短くした場合だけです。 - 必須のステータスチェック。
gh api repos/OWNER/REPO/rulesetsを実行して、各ルールセットを ID で読み込み、gh api repos/OWNER/REPO/branches/main/protectionを実行します。必須チェックの名前を変更したり削除したりすると、すべてのマージがブロックされます。 - 「ブランチを最新の状態にすることを必須とする」設定が有効かどうか。API では
strictと呼ばれます。マージ後に main での実行がどの程度の検出力を維持するかが決まります。 - ワークフローファイルを解析するテスト。
grep -rln "workflows/" --include='*.test.*' .で探します。多くのリポジトリでは、ユニットテストで CI の構成を検証しており、最初の変更でそれらのテストが失敗します。 - イメージタグ、リリース成果物、「CI passed」ステータスなど、デプロイで使用するもの。CI では、デプロイが依存するものをすべて引き続きビルドしてチェックする必要があります。
3. 無駄を見つける
手順 1 の数値で優先順位を付けます。以下の各パターンには、見つけ方と改善方法が記載されています。
メインブランチでプルリクエストのスイートを再実行している。 同じジョブが push と pull_request の両方で実行されています、すべてのマージがすでにチェックに合格した PR から行われるなら、push では高速チェックとビルドおよび公開のステップを残し、負荷の大きいスイートを削除します。何が実行されなくなるのかをユーザーに伝えてください。strict がオフだと、誰もテストしていないマージ結果によってメインブランチが壊れる可能性があり、次の PR でそれが明らかになります。
ほとんどすべての PR に一致するパスフィルター。 PR 実行の 80〜100% で実行されるジョブのフィルターは、何も絞り込めていません。gh api repos/OWNER/REPO/pulls/N/files で実際の PR のファイルリストにフィルターを適用し、どのパターンが最も頻繁に一致するかを数えます。よくある原因は、バージョン更新のたびにすべての PR で変更されるマニフェストやロックファイル、限定的なジョブのルールにある広すぎる src/**、そしてワークフローファイル自体です。バージョンだけの更新を見つけるには、マージベースとヘッドのファイルを比較し、version フィールドを削除して確認します。paths-ignore を使うと、ドキュメントのみの変更では CI をスキップできます。
小さなジョブが多すぎる。 どのジョブでもチェックアウト、ツールチェーン、依存関係のインストールに時間がかかり、多くの場合 30〜60 秒を要し、その後、実行時間は 1 分単位に切り上げられます。切り上げによる増加が約 10% を超えるなら、ジョブが細かすぎます。セットアップとほぼ同じ時間がかかるマトリックスの各実行を、順番に実行するステップを持つ 1 つのジョブにまとめ、各ステップに if: ${{ !cancelled() }} を付けて、1 つが失敗してもすべてのケースの結果が報告されるようにします。時間のかかる実行は並列のままにします。1 ステップだけのジョブは、すでにコードをチェックアウトしている隣接ジョブに移します。
依存関係のインストールが遅い。 ステップの実行時間で、インストールステップとジョブの残りの部分を比較します。セットアップアクションのキャッシュを有効にします。たとえば、actions/setup-node では cache: npm、actions/setup-python では cache: pip を指定するか、ロックファイルをキーにして actions/cache を使います。ジョブで使うパッケージだけをインストールします。ジョブで Git の履歴を読み取らない限り、デフォルトの fetch-depth: 1 を維持します。
PR への push のたびにすべてを実行している。 ブランチごとの実行回数が多く、キャンセルされた実行時間も多い場合、作業が無駄になっています。PR ごとに concurrency のキーを設定し、cancel-in-progress: true を指定します。ドラフトでは負荷の大きいスイートを if: ... && !github.event.pull_request.draft でスキップし、PR の準備ができたときに実行されるよう pull_request の types に ready_for_review を追加します。チームがドラフトを一切作成しないなら、これは何の節約にもなりません。効果を約束する前に確認してください。
ジョブがハングしている。 timeout-minutes が設定されていないジョブは、6 時間実行される可能性があります。最長実行時間が平均を大きく上回るジョブを探し、通常の p90 より少し長いタイムアウトを設定します。
Docker イメージのビルド。 時間のかかるビルドステップと、キャッシュのエクスポートである長い Post Set up Docker Buildx ステップに注目します。COPY . . の前に依存関係をインストールします。多くのスコープで cache-to: mode=max を使うのは避けてください。リポジトリの 10 GB のキャッシュが、それ自体を退避させることになります。PR のビルドで、メインブランチのビルドと同じ内容を繰り返していないか確認します。適切な妥協案は、Dockerfile、ロックファイル、または Dockerfile が名前を指定してコピーするファイルに変更があった場合に限って PR でイメージをビルドし、リリース用のタグを付ける前に、メインブランチが公開するものとまったく同じイメージをテストすることです。そうすれば、テストされていないものが公開されることはありません。
Windows と macOS のランナー。 Windows の料金は Linux の 2 倍、macOS は 10 倍です。プラットフォーム固有のコードでのみ実行し、メインブランチで再実行しないでください。
ボットとスケジュール。 Copilot のコードレビューと Dependabot は dynamic イベントで実行され、cron ワークフローは schedule で実行されます。どちらも同じ実行時間を使用します。cron の頻度と、レビューが再リクエストされる頻度を確認します。
セルフホストランナー。 既存のセルフホストグループで実行されるジョブは、請求対象から外れます。ジョブを移す前に、そのマシンを管理している人に、容量、アーキテクチャ(arm64 または x64)、パッケージレジストリへのアクセスを確認してもらう必要があります。移行を提案し、回答を待ちます。
マージキュー。 PR への push ごとではなく、マージごとにフルスイートを 1 回実行するため、多くの場合、単独では最大の節約になります。プライベートリポジトリで利用するには GitHub Enterprise Cloud が必要なので、まずプランを確認してください。
4. 編集前に見積もる
測定データに変更を1つずつ適用して再現します。削除したジョブ数に課金対象の実行時間(分)を掛け、フィルターの選択率を変更前と変更後で比較し、統合によって削減できるセットアップ時間を合計し、クリティカルパスを変更前と変更後で比較します。変更内容、削減分数、削減時間、リスクを記載した表を示し、ユーザーに選んでもらいます。見積もりは控えめにします。ドラフトのようにチームの作業方法に左右される削減分は、未測定として明記します。
5. ワークフローを安全に変更する
- 各変更は小さく保ちます。次の担当者が元に戻さないよう、理由をワークフロー内のコメントに記載します。
- ワークフローの構成を検証するテストを更新します。バージョンのみのフィルターや、ドラフトによる負荷の高いテストスイートのスキップなど、壊れる可能性のある動作に限ってテストを追加します。YAML の内容をそのまま繰り返すテストは追加しません。
actionlintでリントします。見つからない場合はリリースバイナリをダウンロードし、リポジトリの CI テストをローカルで実行します。- プッシュして PR を監視します。通常、ワークフローを変更するとすべてのジョブが開始されるため、初回の実行に最もコストがかかります。
レポート
まず数値を示し、次に計画を説明します。
## Where the minutes and time go (last N days)
Total billed, monthly estimate, included minutes if known, median and p90 run time.
| Area | Minutes | Share | (by workflow and event)
| Job | Share | (top 5 jobs)
## Why
Numbered causes, each tied to a number from the data.
## Changes
| # | Change | Saves (min) | Saves (time) | Risk |
## Not done
What you skipped and why, such as required check names, runner capacity nobody confirmed, or plan limits.