CIが失敗すると、多くの場合はSlackの通知からWeb UIを開き、パイプラインからワークフロー、ジョブへと画面をたどり、失敗したステップを展開してログをスクロールすることになります。エラーの箇所を見つけたら、その内容をエディタに持ち帰って修正を書きます。修正を書く場所はターミナルとエディタであり、原因を探すためだけにブラウザへ移動している状態です。
CircleCI CLIのv1 previewには、この移動を省くためのコマンドが用意されています。失敗したrunの検知から原因行の取得までに使うコマンドは3つで、circleci run watch、circleci run get --failure-report、circleci job output getです。
前提条件
本記事で使うコマンドはv1 preview版のCLIで利用できます。0.1.x系をお使いの方は、v1へのアップグレードをお願いします。
macOSでHomebrewを使う場合、preview版は次のようにインストールします。安定版がインストールされている場合は、先に削除する必要があります。
brew uninstall circleci # 安定版が入っている場合
brew install circleci-public/circleci/circleci@next
インストール後、認証を行います。v1 previewのcircleci auth loginはブラウザ経由のOAuthに対応しているため、Personal API Tokenを発行してターミナルに貼り付ける操作は不要です。
circleci auth login
その他の環境でのインストール手順はリポジトリの READMEを参照してください。
CI の失敗を検知する
circleci run watchは、対象のrunが終了状態になるまでコマンドが終了しません。引数を省略すると、現在いるブランチの最新runを監視します。
git push origin main
circleci run watch
実行中は、ワークフローとジョブの状態が更新され続けます。
Watching run 82d26617-4bc3-4c94-8904-32fd7d022f93 (main)
build ● running
build ● running build
Elapsed: 18s
ジョブが失敗すると、失敗した旨と次に実行すべきコマンドの候補が表示されます。
build ✗ failed 23s
build ✗ failed build
✗ Run 82d26617-4bc3-4c94-8904-32fd7d022f93 failed (34s)
error: Run 82d26617-4bc3-4c94-8904-32fd7d022f93 failed.
Suggestions:
• View logs for failed job "build": circleci job get <job-id>
push直後に実行する場合は--shaを指定します。pushからrunの作成までにわずかな時間差があるため、--shaを付けると該当コミットのrunが現れるまでポーリングされます。リファレンスでは最大2分間ポーリングすると記載されています。
git push && circleci run watch --sha $(git rev-parse HEAD)
run watchの終了コードは結果を反映します。すべてのワークフローが成功した場合は0、1つ以上が失敗した場合は1、キャンセルは6、タイムアウトは8です。シェルスクリプトからCIの結果で分岐させる場合は、この終了コードを条件に使えます。
失敗したステップを特定する
run watchが提示する候補はcircleci job get <job-id>です。ジョブのUUIDはcircleci run get <run-id>のJobs表に含まれているため、そこから取得して実行します。
circleci job get 0c8a14b6-8f1d-46fe-ab76-50d08716595e
しかしjob getが返すのはステップの一覧と、それぞれの実行時間・終了コードまでで、ステップの出力そのものは含まれません。
# │ Name │ Status │ Duration │ Exit Code │ Command
─────┼─────────────────────────────────┼──────────────┼──────────┼───────────┼──────────────
0 │ Spin up environment │ ✅ succeeded │ 5.5s │ - │ -
99 │ Preparing environment variables │ ✅ succeeded │ 12ms │ - │ -
101 │ Checkout code │ ✅ succeeded │ 1.1s │ - │ -
102 │ system │ ✅ succeeded │ 11.7s │ 0 │ …
103 │ install │ ❌ failed │ 2.1s │ 1 │ … pnpm install
この出力から、installステップが終了コード1で失敗したことは分かります。一方で、なぜ失敗したのかは分かりません。job getのSuggestionsにも、出力を取得するコマンドへの案内は含まれていません。
失敗の内容まで一度で得られるのはcircleci run get --failure-reportです。このフラグは、runに含まれるすべての失敗ステップについて、要約された出力を印字します。
circleci run get --failure-report
別のコミットでcorepackの呼び出しに失敗したrunでは、次の出力が得られました。
## workflow: build
### job: build
#### step 102: enable pnpm [exit: 127]
/bin/bash: line 1: corepack: command not found
ワークフロー名、ジョブ名、ステップ番号、終了コード、そして原因の行がこれだけで揃います。job getで見たSpin up environmentのような成功ステップは含まれません。CIの失敗調査で最初に叩くコマンドは、job getではなくこちらです。
--failure-reportはリファレンス上で、エージェントによる利用を想定したもの(intended for agent consumption)と説明されています。人が読む用途でも、失敗ステップだけが返るという性質はそのまま有効です。
原因行を取り出す
--failure-reportの出力にはステップ番号は含まれますが、ジョブのUUIDは含まれません。ステップ単位で出力を取得するコマンドはUUIDを必須の引数に取るため、ここでUUIDを取得する手順が1つ挟まります。
circleci run getは--jsonに対応しており、--jqがCLIに内蔵されているため、jqコマンドを別途インストールしていなくてもフィルタできます。失敗したジョブのUUIDは次のように取得します。
circleci run get e1d2c207-5273-43c2-8202-f14b7c375c57 --json \
| jq '.workflows[].jobs[] | select(.outcome=="failed").id'
"6bde3c42-8312-4297-be30-57e10dd84d18"
取得したUUIDとステップ番号を指定すると、そのステップのstdoutとstderrが印字されます。ステップ番号は連番ではないため、--failure-reportまたはjob getの出力に現れた番号をそのまま渡します。
circleci job output get 6bde3c42-8312-4297-be30-57e10dd84d18 --step-num 102
/bin/bash: line 1: corepack: command not found
Exited with code exit status 127
--condensedを付けると、エラーに関係する行がサーバ側で絞られます。上記のステップは出力が2行しかないため、両者の差は末尾のExited with code exit status 127の有無だけでした。
circleci job output get 6bde3c42-8312-4297-be30-57e10dd84d18 --step-num 102 --condensed
/bin/bash: line 1: corepack: command not found
リファレンスでは、--condensedはエラーに関連する行のみをサーバ側でフィルタするものとして説明されており、experimentalと明記されています。依存解決やテストのように出力が数百行に達するステップでどの程度絞られるかは、対象のジョブで確認してください。
全ステップの出力を扱う
失敗したステップ以外も確認したい場合はcircleci job output listを使います。ジョブに含まれる全ステップと、それぞれの出力を一覧します。
circleci job output list 6bde3c42-8312-4297-be30-57e10dd84d18
Job Output
• ID: 6bde3c42-8312-4297-be30-57e10dd84d18
• Name: build
• Execution: 0
## 0: Spin up environment
• Status: ✅ succeeded
• Duration: 6.1s
### Output
Using the v2 container runtime. For more details see: …
docker-agent version: 1.0.84357-d6a4f55
task-agent version 1.0.343908-3d36a710
…
このコマンドは失敗ステップを絞り込まないため、Spin up environmentのコンテナ起動ログやイメージのレイヤー取得ログも含まれます。今回のジョブでは、最初のステップだけで数十行が出力されました。原因の特定だけが目的であれば、前節のjob output getの方が短時間で済みます。
--jsonを付けると、各ステップの出力を保持したJSONが返ります。
circleci job output list 6bde3c42-8312-4297-be30-57e10dd84d18 --json --jq "."
{
"execution": 0,
"id": "6bde3c42-8312-4297-be30-57e10dd84d18",
"name": "build",
"steps": [
{
"name": "Spin up environment",
"num": 0,
"outcome": "succeeded",
"output": "Using the v2 container runtime. …"
}
]
}
steps[]の各要素がnum、outcome、exit_code、outputを持つため、失敗したステップの出力だけを取り出すこともできます。リファレンスには次の例が掲載されています。
circleci job output list <job-id> --json \
--jq '.steps[] | select(.exit_code != 0) | .output'
--jsonは--tailの制限を受けず全出力を保持します。ステップ数の多いジョブでそのまま流すと出力量が大きくなるため、上記のような絞り込みと組み合わせて使ってください。
エージェントに渡す前提で設計されている
ここまでのコマンドは、いずれも人が読む前提と、プログラムが読む前提の両方を満たすように作られています。CircleCIの公式ブログは、v1がGoによる全面的な書き直しであり、書き直しの理由としてコーディングエージェントを挙げています。エージェントは、人間のように曖昧な出力を推測で補って回り道することができないため、予測可能なJSON、安定した終了コード、次に取るべき行動を含むエラーメッセージが必要になる、という説明です。
その方針は、本記事で使ったコマンドの仕様に現れています。
- データを返すすべてのコマンドが
--jsonに対応する -
run watchの終了コードが結果ごとに定義されている -
--failure-reportが、失敗ステップの要約出力だけを返す -
--condensedで、取得する行数をサーバ側で絞れる
最後の2点はエージェント利用で特に効きます。ログの全文をコンテキストに流し込むと上限を消費し、途中で文脈を失う可能性があるため、取得段階で絞れることが前提条件になります。
CLIにはさらにMCPサーバーが内蔵されており、circleci mcpからClaude Desktop、Cursor、VS Codeへの登録が行えます。ここまで実行したコマンド群と同じ情報にエージェントからアクセスできる導線が、追加のインストールなしで用意されています。
まとめ
CircleCI CLIのv1 previewでは、CIが失敗した直後の調査をターミナル内で完結できます。circleci run watchで結果を受け取り、circleci run get --failure-reportで失敗したステップと原因行を取得し、より詳しく見る必要がある場合にcircleci job output getでステップ単位の出力を取ります。circleci job getはステップの終了コードまでしか返さないため、出力が必要な場面ではこの3つを使い分けてください。
今回は失敗ログの取得のみを扱いましたが、CLIにはジョブのCPUとメモリの使用状況を扱うcircleci job resource-usage、アーティファクトを取得するcircleci artifactなども含まれています。失敗の性質に応じて、ログ以外の情報も同じ経路で取得できます。
各コマンドのフラグと出力形式はCircleCI CLI Referenceにまとまっています。
