ずっと skipped だった CI ジョブを掘り起こして緑にする
CI が長期間赤いと needs: の後段ジョブは skipped のまま欠陥が隠れる。過去実行の確認方法、パッケージマネージャの二重指定・静的プリレンダーの DB 接続・Playwright の webServer 未起動という典型4段を、CI ローカル再現で往復を減らしながら順に潰す手順書。
約3.7万トークンの節約 (API料金換算で約55円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「ずっと skipped だった CI ジョブを掘り起こして緑にする」は、開発プロセスカテゴリのAI指示書(MDファイル)です。CI が長期間赤いと needs: の後段ジョブは skipped のまま欠陥が隠れる。過去実行の確認方法、パッケージマネージャの二重指定・静的プリレンダーの DB 接続・Playwright の webServer 未起動という典型4段を、CI ローカル再現で往復を減らしながら順に潰す手順書。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約3.7万トークン(API料金換算で約55円)・88%のトークンを節約できます。
- カテゴリ
- 開発プロセス
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約4.2万トークン
- この巻物使用時
- 約5,200トークン
- 節約量
- 約3.7万トークン (約55円)
- 更新日
- 2026-08-29
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/skipped-ci/raw を読み込んで、この指示書どおりに実装して"
中身
「ずっと skipped だった CI ジョブ」を掘り起こして緑にする手順
これは何の指示書か
CI が長期間 red なリポジトリを引き継いだとき、赤いジョブを直すだけでは終わらない。
needs: で後ろに繋がったジョブは前段が落ちている間ずっと skipped になり、
skipped は PR のチェック欄で赤くも緑にも見えないため、そのジョブ自体の欠陥が何ヶ月も隠れる。
この指示書は「前段を直す → 隠れていた次の障害が出る」を想定内として連続で回し切るための手順書。 GitHub Actions + Node/pnpm + Next.js + Playwright を例にするが、考え方は CI 一般に効く。
前提
- リポジトリの CI が赤い、または「テストが通っているはずなのに壊れたコードがマージされた」状態
ghCLI が認証済み(gh auth statusで確認)- 対象 PR / ブランチが分かっている
手順 0: 着手前に「そのジョブは過去に一度でも成功したか」を確認する
最重要。これをやらないと「E2E は通っている」という誤った前提で作業してしまう。
REPO=<owner>/<repo>
JOB_PATTERN='E2E' # 疑っているジョブ名の一部
for r in $(gh run list --repo "$REPO" --branch main --limit 10 --json databaseId -q '.[].databaseId'); do
gh run view "$r" --repo "$REPO" --json jobs \
-q ".jobs[] | select(.name|test(\"$JOB_PATTERN\")) | .conclusion"
done
出力が全部 skipped なら、そのジョブは「通っている」のではなく「一度も検証されていない」。
success が1つも無いジョブは、これから初めて動く=落ちる前提で計画する。
手順 1: 失敗ログの「本当のエラー行」だけを抜く
--log-failed は Git の内部コマンドや Node 廃止警告で数百行に膨れる。ノイズを落とす:
gh run view <RUN_ID> --repo "$REPO" --log-failed \
| grep -viE "node 20|node\.js 20|post job|orphan|git config|git submodule|git version|safe\.directory|extraheader|Pruning|overriding HOME|##\[group|##\[endgroup" \
| tail -40
エラーだけ拾いたい場合:
gh run view <RUN_ID> --repo "$REPO" --log-failed \
| grep -iE "error:|refused|timeout|failed to|ELIFECYCLE" | head -20
手順 2: よくある「前段を8秒で殺す」設定バグ
2-1. パッケージマネージャのバージョン二重指定
pnpm/action-setup の with.version と package.json の packageManager を両方書くと即死する:
Error: Multiple versions of pnpm specified:
- version 9 in the GitHub Action config with the key "version"
- version pnpm@9.15.0 in the package.json with the key "packageManager"
直し方: packageManager を唯一の情報源にし、workflow 側の version: を消す。
# Before
- uses: pnpm/action-setup@v4
with:
version: 9
# After
- uses: pnpm/action-setup@v4
corepack や actions/setup-node の cache: 'pnpm' と併用する場合も同じ。
このステップが死ぬとそれ以降の全ステップが飛ぶので、 lint も typecheck も build も「一度も実行されていない」状態になる。
手順 3: next build がビルド時に DB へ繋ぎに行って落ちる
症状
Error occurred prerendering page "/admin/audit"
[AggregateError: ] { code: 'ECONNREFUSED' }
Export encountered an error on /(admin)/admin/audit/page, exiting the build.
原因
サーバコンポーネントで DB を参照しているページに動的レンダリング宣言が無く、 Next.js がビルド時に静的プリレンダーしようとして実 DB へ接続する。 ホスティング側(Vercel 等)は本番 env があるため成功し、CI だけが落ちるので気付きにくい。
直し方(重要: ページ個別に付けない)
ルートグループの layout.tsx に置く。配下の全ページに効くので付け漏れが出ない。
// app/(admin)/layout.tsx
export const dynamic = 'force-dynamic';
認証必須のルートグループすべて((admin) (member) 等)とルート直下の app/page.tsx に入れる。
これらは元々ユーザーごと・常に最新であるべき画面なので、静的化しない方が意味的にも正しい。
検出コマンド
for f in $(find app -name "page.tsx"); do
grep -qE "from '@/db/client'|await db\." "$f" && \
printf "%-55s dynamic=%s\n" "$f" "$(grep -c 'export const dynamic' "$f")"
done
注意: この grep は「ヘルパー経由で間接的に DB を触るページ」を取りこぼす。 一覧に頼らず、下の手順4でCI と同じ env でローカル build を回して実際に落ちる場所を出すこと。
手順 4: CI をローカルで再現する(往復を減らす最大の武器)
workflow の env: をそのままシェルに並べてローカル実行する。CI を1回回すより桁違いに速い。
<認証シークレット環境変数>=<ダミー値> \
<アプリURL環境変数>=http://localhost:3000 \
<DB接続環境変数>=<ダミー値> \
<他のダミー env> \
pnpm build 2>&1 | tail -25
pnpm format:check / pnpm lint / pnpm typecheck も先に回して、CI を1往復で済ませる。
偽陽性に注意(Windows)
core.autocrlf=true の環境では、git checkout したファイルが CRLF になり
Prettier(既定 endOfLine: lf)が「未整形」と報告する。
git diff --stat が空ならローカル表現だけの差で、LF でチェックアウトする CI では通る。整形し直さないこと。
恒久対策は .gitattributes に * text=auto eol=lf。
手順 5: Playwright E2E が CI で「一度も動いていない」典型
症状
全 spec が net::ERR_CONNECTION_REFUSED at http://localhost:3000/... で落ちる。
原因
// playwright.config.ts —— これが犯人
webServer: process.env.CI
? undefined // ← CI ではサーバを起動しない
: { command: 'pnpm dev', url: 'http://localhost:3000' },
CI のときサーバ起動を無効にしているのに、workflow 側でもサーバを起動していない。
「CI では外部で起動する前提」で書かれた設定が、起動ステップの実装忘れとセットで放置されているパターン。
直し方
webServer: {
command: process.env.CI ? 'pnpm build && pnpm start' : 'pnpm dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 300_000, // CI ではビルド時間を含むので長めに
},
workflow の E2E ステップにはbuild ジョブと同じダミー env を渡す(無いとサーバが起動できない):
- name: Run E2E
run: pnpm test:e2e
env:
CI: true
<DB接続環境変数>: <ダミー値>
# build と同じ env 一式
手順 6: 初回実行で出る「テスト側の欠陥」を直す
一度も走っていないテストは、アプリではなくテスト自身が壊れていることが多い。
典型: getByRole('alert') の strict mode violation
strict mode violation: getByRole('alert') resolved to 2 elements:
1) <div role="alert"> …アプリのエラー表示… </div>
2) <div role="alert" id="__next-route-announcer__"></div>
Next.js のルートアナウンサーも role="alert" を持つ。アプリ側の要素だけに絞る:
const APP_ALERT = '[role="alert"]:not(#__next-route-announcer__)';
await expect(page.locator(APP_ALERT)).toContainText(/…/);
アプリの表示自体は正しいケースなので、アプリ側を書き換えないこと。
ローカルでブラウザが無くて落ちるのは無視してよい
devices['iPhone 15'] を使う spec は webkit を要求する。
ローカルに未インストールなら Executable doesn't exist at …webkit-XXXX で落ちるが、
CI が playwright install --with-deps chromium webkit していれば CI では通る。
ローカルの1件失敗を CI の失敗と混同しない。
手順 7: 「緑になった」の定義
gh run watch <RUN_ID> --repo "$REPO" --compact
gh pr checks <PR> --repo "$REPO"
前段が緑になった時点では終わっていない。needs: の後段が初回実行されて pass になるまで見届ける。
そこまで確認して初めて「CI が通った」と報告してよい。
マージ後は配信先の実体も確認する:
curl -s -o /dev/null -w "health=%{http_code}\n" https://<本番ホスト>/api/health
curl -s https://<本番ホスト>/<公開ページ> | grep -c "<新機能の目印テキスト>"
つまずきポイントまとめ
| 症状 | 真因 | 対処 |
|---|---|---|
| CI が数秒で死ぬ | パッケージマネージャのバージョン二重指定 | workflow の version: を消す |
| lint/format が急に大量に落ちる | 前段死亡で長期間走っていなかっただけ | --write で一括整形して1コミット |
| build だけ CI で落ちる(本番は通る) | DB 参照ページの静的プリレンダー | route group の layout に force-dynamic |
E2E 全滅 ECONNREFUSED | CI で webServer を起動していない | webServer を CI でも有効化+env を渡す |
| ローカルだけ format:check が落ちる | Windows の CRLF | git diff が空なら無視。.gitattributes で恒久対策 |
role="alert" が2件に一致 | フレームワークのアナウンサー要素 | :not(#__next-route-announcer__) で絞る |
作業ログの残し方
1つ直すごとに独立したコミットにし、何が隠れていたかをメッセージに書く。 「緑にするための一括修正」にすると、次に同じ罠を踏んだ人が原因を追えない。
ci: <PM> のバージョン二重指定を解消して CI を復旧
fix(build): DB 参照ページを静的プリレンダー対象から外す
fix(ci): E2E が CI で一度も実行されていなかった問題を修正
よくある質問
+「ずっと skipped だった CI ジョブを掘り起こして緑にする」とは何ですか?
CI が長期間赤いと needs: の後段ジョブは skipped のまま欠陥が隠れる。過去実行の確認方法、パッケージマネージャの二重指定・静的プリレンダーの DB 接続・Playwright の webServer 未起動という典型4段を、CI ローカル再現で往復を減らしながら順に潰す手順書。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約4.2万トークンかかりますが、この巻物を使えば約5,200トークンで済みます。差し引き約3.7万トークン(API料金換算で約55円)・88%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
ドキュメント駆動開発プロセス CLAUDE.md — 作るものを固めてから書かせる
「AIが暴走して意図と違うものを作る」を根絶する開発プロセス指示書。UI仕様→機能設計→実装の順をAIに強制し、1ファイルごとに承認ゲートを挟む。受託開発・チーム開発向け。
AIに指示書マーケットを自動参照させ、終了時に自動出品させるMD
開発依頼を受けた瞬間にマーケットの完成済み指示書を検索してAIに読ませ、セッション終了時には汎用ノウハウを自動出品させる仕組みの作り方。全台配布・秘密情報スキャン・実際に踏んだ配布バグ3つの回避込み。
「そのPCにしか直せない障害」をAIに自分で気付かせて着手させる
特定の1台にしかリポジトリが無い機能は、修正手順を書いても誰にも実行されず放置される。SessionStart hook で当該PCのAIだけに指示を出し、完了後は指示書へ状態を書き戻して再実装事故を防ぐ型。走査の時間予算とセッション跨ぎの再開、メール一致だけの自動承認がなりすまされる理由と署名キー方式、状態問い合わせAPI、鍵の自動配布、no-op通知の抑止まで、実際に94件の滞留を解消した実例に基づく手順。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア