CI と手元検査の選び方に迷っている、1〜3 人でデータ処理や社内ツールのリポジトリ(コードやファイルを、変更の記録ごとまとめて置く場所)を持つ方向けの記事です。GitHub Actions の料金表から月額を試算し、筆者が CI をやめて手元の検査に替えた後のつまずきを紹介します。読み終わると、自分のチームがどちらを選ぶべきかを、費用と検査の抜けの両面から判断できるようになります。
この記事は、CI(継続的インテグレーション:コードの変更を取り込む前に、決まった検査を自動で動かす仕組み)を GitHub Actions で動かす場合を扱います。これに対して、この記事でいう手元検査(ローカル検査)は、変更を作った人が自分のパソコンで検査のスクリプトを動かし、その結果を取り込みの条件にするやり方です。
この記事で分かること
- GitHub Actions の CI を続けると、月にいくらかかるのか(実行時間と回数別の試算)
- CI をやめて手元検査に替えた時に、検査の抜けがどう起き、どう気づけたのか
- CI と手元検査を 5 つの項目で比べた違いと、人数や変更を出す人の範囲で選ぶ判断フロー
ざっくり言うと:費用より「何を動かしているか」が品質を決めた
筆者の試算では、小さいチームの CI の費用は、多くの場合プランに含まれる月の利用額(いわゆる無料枠)に収まりました。仮定した 9 通りのうち 6 通りは、追加の請求が 0 ドルです。
一方で、手元検査に替えた後に、検査の工程の 1 つが、直した時点で 13 本あったテストのファイルのうち 1 本しか動かしていなかったことが分かりました。何を動かすかを書くのは CI でも手元でも人なので、この抜けは CI のままでも起きえたと筆者は考えています。
CI をやめるかどうかは費用だけで決めず、検査が何を動かしているかを数えてから決めるのが安全です。なぜ CI をやめたか:170 回動いて問題を見つけた回が 0 回
筆者がこのサイトの運用で試した記録です。このサイトのリポジトリでは、2026-10-30 に GitHub Actions の CI を使わないと決めました。理由は、CI が 170 回動いて、本当の問題を見つけた回が 0 回だったことです。
PR(プルリクエスト:変更を本流に取り込む前に、確認を依頼する仕組み)の push(手元の変更を GitHub へ送ること)のたびに CI が動き、料金だけがかかっていました。実際の請求額の記録は無いため、費用は料金表からの試算で示します。
CI の代わりに、次の 2 つを merge(変更を本流に取り込むこと)の条件にしました。
| 条件 | 中身 |
|---|---|
| 手元検査の合格 | PR を作る担当が手元で scripts/check-local.sh を動かし、合格した結果を PR の本文に書く |
| 独立レビュー | 実装していない担当がレビューし、直すべき指摘が残っていない |
すべての自動検査をやめたわけではありません。本番へ出す時の ビルド(記事やコードからサイトを組み立てる処理)は残しています。ビルドに失敗した時は本番に出ず、前の版のまま残ります。
構成図:CI と手元検査では、誰がいつ検査を動かすか
CI では、PR に関する出来事を合図に、GitHub がワークフロー(自動で動かす処理の定義)を動かします(Events that trigger workflows)。
手元検査では、PR を作る担当が、最後のコミット(変更を 1 まとまりとして記録したもの)の後に 1 回だけスクリプトを動かします。図 1 は、その検査スクリプトの 7 つの工程と、合格の記録の位置を示したものです。
| 工程 | 名前 |
|---|---|
| 1 | lint |
| 2 | test-rules |
| 3 | test |
| 4 | actionlint |
| 5 | astro build |
| 6 | rule-sync |
| 7 | gitleaks |
この記事で中身を扱うのは、テストのファイルを動かす工程 3 です。工程 5 の astro build は、サイトを組み立てられるかを確かめる工程で、本番へ出す時の自動のビルドと同じ種類の検査です。
どれか 1 つでも失敗すると、スクリプトは終了コード(処理が成功したかを表す数字。0 が成功)1 で終わります。同じコミットに合格の記録がある時は、検査を省いて終わります(環境変数 CHECK_LOCAL_FORCE=1 を付けると、記録を使わずに検査し直せます)。
費用の試算:GitHub Actions の料金表から、実行時間と回数別の月額
ここからがオリジナルの分析です。GitHub Actions の料金は、リポジトリが公開か非公開かで大きく変わります(GitHub Actions billing、2026-11-11 時点)。
| 条件 | 料金表の内容 |
|---|---|
| 公開リポジトリの標準ランナー | 無料 |
| 非公開リポジトリ | プランに含まれる月の利用額から引かれ、超えた分は請求される |
| 含まれる月の利用額 | GitHub Free 12 ドル、Pro と Team 18 ドル、Enterprise Cloud 300 ドル |
| Linux 2 コアの単価 | 1 分 0.006 ドル(Windows は 0.010 ドル、macOS は 0.062 ドル) |
| 自前のマシン(セルフホストランナー) | 含まれる利用額を減らさない |
ランナーとは、CI の検査を実際に動かすマシンのことです。料金表の例では、Linux で 10 分かかるワークフローは 0.06 ドルが引かれます。
試算の仮定
CI の実行時間と回数の記録が無いため、次の仮定で筆者が計算しました。
- 非公開リポジトリで、Linux 2 コアの標準ランナーを使う
- 1 回の実行時間は 3 分・10 分・20 分の 3 通り
- 月の実行回数は 50 回・200 回・500 回の 3 通り
- 式は「1 回の分数 × 月の回数 × 0.006 ドル」
- 1 回の実行はジョブ(ワークフローの中で、1 台のランナーが動かす処理のまとまり)1 つとする
GitHub は、ジョブごとに分の端数を 1 分に切り上げます(Actions runner pricing、2026-11-11 時点)。ジョブが複数あるワークフローは、ジョブごとに切り上げた分の合計で引かれるため、実際の額はこの試算より多くなることがあります。
試算の結果
図 2 は 9 通りの月額です。手元検査には追加の料金はかかりません。
| 条件 | 月額 | Free 超過 | Pro・Team 超過 |
|---|---|---|---|
| 3 分 × 50 回 | 0.90 | 0 | 0 |
| 3 分 × 200 回 | 3.60 | 0 | 0 |
| 3 分 × 500 回 | 9.00 | 0 | 0 |
| 10 分 × 50 回 | 3.00 | 0 | 0 |
| 10 分 × 200 回 | 12.00 | 0 | 0 |
| 10 分 × 500 回 | 30.00 | 18.00 | 12.00 |
| 20 分 × 50 回 | 6.00 | 0 | 0 |
| 20 分 × 200 回 | 24.00 | 12.00 | 6.00 |
| 20 分 × 500 回 | 60.00 | 48.00 | 42.00 |
金額の単位はドルです。「条件」は 1 回の実行時間 × 月の回数です。「Free 超過」と「Pro・Team 超過」は、含まれる月の利用額(Free 12 ドル、Pro と Team 18 ドル)を超えて請求される分です。
含まれる利用額を分に直すと、Free の 12 ドルは 2,000 分、Pro と Team の 18 ドルは 3,000 分です(筆者が 12 ÷ 0.006 と 18 ÷ 0.006 で計算)。1 回 10 分の CI なら、Free で月 200 回、Pro と Team で月 300 回までは追加の請求が出ない計算です。
月の合計の分数が 2,000 分(Free)か 3,000 分(Pro・Team)に収まるなら、費用は CI をやめる理由になりにくいです。試算で見落としやすい 3 つの点
- 含まれる利用額は、アカウントや組織の全体で共有されます。ほかのリポジトリの CI も同じ枠を使います。
- 失敗した実行も、動いた分が課金されます。5 分で失敗し、直して 10 分で成功すると合計 15 分です。
- 料金は、実行を起こした人ではなく、リポジトリの持ち主に請求されます。
このサイトの CI の 170 回を料金に直すと、1 回 3 分で 3.06 ドル、10 分で 10.20 ドル、20 分で 20.40 ドルです(筆者計算。期間が不明なので月額ではありません)。
CI の回数そのものを減らす方法は、GitHub Actions の CI コストを paths filter で抑える設計で説明しています。毎日の定期実行をどこで動かすかの費用比較は、手元の Mac・Cloud Run Jobs・GitHub Actions の月額の比較が参考になります。
つまずきやすい点 1:13 本のテストのうち 1 本しか動いていなかった
手元検査に替えた後、工程 3 のテストに大きな抜けがありました。工程 3 は、記事の仕組みのテストのファイルを、直した時点で 13 本あったうち seo-checks.test.mjs の 1 本しか動かしていませんでした。
テストは、Node.js に標準で入っているテストの仕組み(node:test)で書いています。直す前と後のコマンドは次のとおりです(筆者の記録)。
# 直す前:1 本だけ
node --test scripts/ai-articles/seo-checks.test.mjs
# 直した後:13 本すべて
node --test scripts/ai-articles/*.test.mjs
この抜けは、4 つの PR の担当が別々に同じ内容を報告して見つかりました。
| 時点 | 工程 3 が動かしたファイル | 割合 |
|---|---|---|
| 直す前 | 1 本 | 13 本中 1 本(ファイル数で約 7.7%、筆者計算) |
| 直した後 | 13 本 | 13 本中 13 本 |
つまずきやすい点 2:全部動かすと、依存が無い作業場所で 2 件が失敗した
13 本すべてを動かすように直す時に、もう 1 つの問題が見つかりました。依存パッケージ(自分のコードが使う、ほかの人が作った部品のライブラリ)を入れていない作業場所で 13 本すべてを動かすと、164 件中 2 件が失敗したのです。
失敗したのは、js-yaml を使うテストと、@astrojs/mdx を使うテストです。どちらも部品が見つからない(ERR_MODULE_NOT_FOUND)ため失敗しました。直す前の工程 3 は 1 本しか動かしていなかったので、この 2 つのテストはそもそも動いていませんでした。
直す前の検査には、依存パッケージがあるかを確かめる仕組みがありませんでした。手元検査は、作業する場所の状態に結果が左右されると分かりました。
似た問題として、呼び出し側の環境変数(プログラムに外から渡す設定の値)が混ざり、コードが正しくても失敗したこともあります。
| 状態 | テストの件数 | 合格 | 失敗 |
|---|---|---|---|
| 13 本を依存なしで動かした時 | 164 件 | 162 件 | 2 件 |
| 依存を入れて直した後 | 188 件 | 188 件 | 0 件 |
合格の 162 件は、164 から 2 を引いた筆者の計算です。164 件から 188 件に増えた理由の内訳は、今回の資料からは確かめられませんでした。直す前の 1 本のファイルが何件のテストを持っていたかも、記録がありません。
直した内容:全部動かす、無ければ止める、合格の記録、環境変数を 7 件に
図 3 のとおり、依存を入れて直した後は、テスト 188 件が合格・失敗 0 件でした。筆者の記録では、このとき検査の 7 工程もすべて合格しています。直した内容は次の 4 つです。
- 工程 3 で、テストのファイルを 1 本ではなく、すべて動かすようにした
- 依存パッケージがあるかを先に確かめ、無い時は入れ方(
pnpm install --frozen-lockfile)を示して終了コード 1 で止まるようにした - テストには、許可した環境変数 7 件(PATH・HOME・TMPDIR・LANG・LC_ALL・LC_CTYPE・TEST_TMPDIR)だけを渡すようにした
- 同じコミットに合格の記録があれば、検査を省くようにした
2 つ目では、依存が無いテストを案内だけ出して省く作りも選べました。しかし省く作りでは、動かなかったテストがあっても検査全体は合格と表示されます。
依存が無い時は、テストを省かずに検査ごと止める作りにすると、抜けが合格に見えるのを防げます。その後、工程 3 が動かすテストの置き場所は 3 か所に広がりました。
CI と手元検査を 5 項目で比べる
図 4 は、ここまでの試算と記録をもとに、CI と手元検査を 5 つの項目で比べた筆者の整理です。
| 項目 | CI(GitHub Actions) | 手元検査 |
|---|---|---|
| 費用 | 公開リポジトリは無料。非公開は 1 分 0.006 ドルを含まれる利用額から引く | 追加の料金なし |
| 待ち時間 | 筆者の実測の記録なし。失敗して再実行すると時間が合計される | 1 回に数分〜10 分。同じコミットの 2 回目は記録で省ける |
| 動かし忘れ | PR の出来事で自動に動く。ただし衝突のある PR では動かない | 人や AI が動かす。合格した SHA を PR 本文に書き、merge の条件にする |
| 抜けへの気づき方 | 何を動かすかを書くのは人なので、同じ抜けは起こりうる(筆者の考え) | 4 つの PR の担当が別々に気づいた |
| 新しい作業場所 | 筆者の実測の記録なし | 依存が無いと 2 件が失敗した。確かめて止める作りに直した |
SHA は、コミット 1 つずつに付く識別の文字列です。
動かし忘れを減らす仕組みは、どちらの側にもあります。手元検査では、git の pre-push フック(push の直前に git が呼び出すスクリプト)で、検査に通らない push を止められます(githooks)。
CI では、ブランチ保護(大事なブランチへの変更に条件を付ける GitHub の設定)の必須チェック(指定した検査がすべて合格するまで、PR の merge を止める設定)が使えます(About protected branches)。
CI も必ず自動で動くとは限りません。公式ドキュメントでは、マージの衝突がある PR ではワークフローが動かないと説明されています(Events that trigger workflows)。
選び方のフロー:人数・外部からの PR・検査にかかる時間
図 5 は、4 つの質問でどちらを選ぶかをたどる、筆者の整理した判断フローです。分数は先ほどの試算から取っています。
| 順 | 質問 | はいの時 | いいえの時 |
|---|---|---|---|
| 1 | リポジトリは公開か | CI を続ける(標準ランナーは無料) | 2 へ |
| 2 | 書き込み権限の無い人から PR が来るか | CI を残す | 3 へ |
| 3 | 月の CI の合計が 2,000 分(Free)か 3,000 分(Pro・Team)に収まるか | 費用は理由にならない。CI を続けるか両方 | 4 へ |
| 4 | 手元検査を 1 回 10 分ほどで回し、合格の記録を merge の条件にできるか | 手元検査に移す | CI を残す |
2 つ目で CI を残すのは、外部の人の手元で検査が動いたかを確かめられないからです。
手元検査に移すなら、4 つの直し方を最初から入れると、同じつまずきを避けやすいと考えられます。本番に出す経路の検査の設計は、AI の成果物を人の確認なしで本番へ出す経路の設計で説明しています。
まとめ
- 筆者の試算では、9 通りのうち 6 通りが含まれる利用額に収まり、追加の請求は 0 ドルでした。小さいチームでは、費用だけで CI をやめる理由になりにくいです。
- 手元検査に替えた後、工程 3 は 13 本中 1 本のテストしか動かしていませんでした。13 本すべてを依存なしで動かすと、164 件中 2 件が失敗しました。合格の表示より、何を動かしたかを数えることが大切です。
- 手元検査を選ぶなら、全部動かす・依存が無ければ止める・合格の記録を残す・環境変数を絞る、の 4 つを入れてから移すと安全です。
自分のチームで CI を残すか手元検査に移すかを相談したい方は、お問い合わせからご連絡ください。データ処理の SQL の書き方や検査の観点に不安がある場合は、BigQuery SQL レビューパックも用意しています。