feat(cli): CLI のリリースバイナリ配布と --json 出力を追加 - #7
Merged
Conversation
利用側リポジトリが CI で毎回 vrt CLI をソースからビルドしていた(初回 15〜20 分、 mold や apps/backend ワークスペースといった内部事情も漏れていた)ため、リリース バイナリ配布と機械可読出力を追加する。 - .github/workflows/release-cli.yml を新規追加。`cli-v*` タグ(と手動実行)で 4 ターゲット(x86_64/aarch64 の linux-gnu と apple-darwin)をネイティブランナーで ビルドし、`vrt-<target>.tar.gz`(バイナリ vrt 1 本)と `.sha256` を GitHub Release へ添付する。クロスコンパイルは mold と相性が悪いので避けた。action はすべて 40 桁 SHA でピン留めし、既存ワークフローの SHA を再利用した。 - vrt upload に `--json` を追加。build_id / build_number / tenant_slug / project_slug / status / exit_code を stdout へ 1 行 JSON で出す。GitHub Action などの呼び出し元が結果をパースできるようにする。build_number 用に CLI 側の BuildResponse へ number フィールドを追加した。 - tracing のログ出力先を stderr に変更(`--json` の有無に関わらず)。stdout を 結果専用に空け、機械可読出力とログが混ざらないようにする。進捗ログと人間向け サマリも `--json` 時は stdout に出さない。終了コードと --wait の挙動は不変。 - README にリリースバイナリの入手手順(推奨)と `--json` の説明を追記。
`number` は BuildResponse の必須フィールド(OpenAPI の required に含まれる) なので `#[serde(default)]` を外す。 default が付いていると、サーバー側の契約が変わって欠落した場合に黙って 0 に なり、`--json` の build_number が 0 として出る。呼び出し元がこれで `/builds/0` という存在しないレビュー URL を組み立ててしまうため、 契約違反は deserialize の失敗として顕在化させる。 cargo test -p vrt-cli は 18 件とも PASS。
|
ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing |
actions/runner-images で現在提供されている macOS イメージは 15 / 26 系のみで、 14 は deprecated、13 は既に一覧から消えている。macos-13 のままではリリース ジョブが「該当ランナー無し」で起動できない。 Intel 版は `-intel` サフィックスの macos-15-intel、Apple Silicon は macos-15 を 使う。あわせて macos-latest の使用をやめてラベルを固定する。-latest は 1〜2 か月 かけて新しい OS へ段階移行するため、リリース成果物の再現性が保てないため。 larger runner(`-large` / `-xlarge`)は public リポジトリでも課金対象になるので 選ばない。標準ランナーは public リポジトリでは無料。
- release ジョブに `if: startsWith(github.ref, 'refs/tags/cli-v')` を追加。 action-gh-release は tag_name 未指定だと GITHUB_REF をタグとして扱うため、 workflow_dispatch をブランチから手動実行すると必ず失敗していた。 手動実行はビルドの素振り用と位置づけ、その旨を on: にもコメントで書く。 - README のダウンロード例を、チェックサム検証が実際に通る形に直す。 .sha256 はアーカイブ名込みで記録されるため、配布時のファイル名のまま 取得しないと `shasum -a 256 -c` が通らない。検証の一行も例に含める。 - README に `--json` の失敗時の挙動を明記。ビルド作成前に失敗した場合は stdout が空のまま終了コード 2 で終わるため、呼び出し元は「stdout が空で 非ゼロ終了」を処理する必要がある。 - poll_until_terminal の doc コメントが「進捗ログを stdout に流す」のまま だったのを、`--json` 時は stderr になる旨を含めて修正。 - exit_code_for と is_settled のユニットテストを追加(3 件)。終了コードは CI の合否判定そのものなので 8 状態すべてを固定し、未知の状態が黙って 0(成功)に倒れないことも明示的に押さえる。 cargo test -p vrt-cli は 21 件 PASS、clippy / fmt もクリーン。
finalize 成功後の poll_until_terminal が一時的な通信失敗や 30 分タイムアウトで Err を返すと、run_upload の `?` が早期リターンして stdout に JSON が 1 行も 出なかった。README は「finalize まで到達すれば JSON が出る」契約を謳うため、 呼び出し元が build_id すら取れなくなっていた。 --wait && --json のときは poll の Err を明示的に処理し、finalize 済みの既知情報 (build_id/build_number/slug/finalize 直後の status) に exit_code=2 と失敗理由の error フィールドを添えて JSON を 1 行出す。エラーは従来どおり stderr に tracing で 残し、終了コード 2 で終わる。--json でない場合は従来どおり Err を伝播する。 JSON 値の組み立てを json_result_value 純関数に切り出してユニットテスト可能にした。
PR #7 のレビュー指摘 3 件に対応する。 - --json のビルド終端パスが error_message を落としていた。run_upload の poll 成功後の print_json_result に final_build.error_message.as_deref() を 渡し、failed / rejected で終わったビルドの失敗理由を人間向け report() と 同様に JSON の error にも載せる。成功時は error キーが出ない契約は維持。 ユニットテストを 1 件追加し、README の --json 説明にこの経路を追記した。 - release-cli.yml の dtolnay/rust-toolchain に toolchain: 1.95.0 を明示。 action は rust-toolchain.toml を読まないため、無指定だと stable と 1.95.0 の 2 本をダウンロードしていた。コメントも実態に合わせて修正した。 - release-cli.yml から Swatinem/rust-cache を削除。GitHub Actions キャッシュは default ブランチから子 ref に読めるため、細工されたエントリがリリース バイナリに混入しうる。再現性も損なうため、リリースはクリーンビルドにする。
cargo build の成功だけを根拠に tar → Release へ進むと、リンクは通ったが 起動時に落ちる類の破損(動的リンク先の欠落など)が捕まらないまま配布される。 4 ターゲットともネイティブランナーでビルドしているため、パッケージ直前に vrt --version を実行して起動確認する。
sousuke0422
approved these changes
Jul 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
vrtCLI をリリースバイナリとして配布できるようにし、あわせて機械可読な--json出力を追加する。動機
CLI がリリース配布されていないため、利用側のリポジトリが CI で毎回ソースからビルドする必要があり、初回で 15〜20 分かかっていた(実測: koyori-app/task の PR #491)。さらに利用側のワークフローに「Cargo ワークスペースが
apps/backendにある」「mold リンカが必要」といった VRT 内部の事情が漏れていた。CLI は公開インターフェースなので、成果物として配るのが筋。--jsonは GitHub Action などプログラムから呼ぶ側のために必要になる。現状 CLI は人間向けのログしか出さないため、呼び出し元が build ID や結果を取得するにはログを正規表現で削るしかない。変更内容
1. リリースワークフロー(
.github/workflows/release-cli.yml)トリガー:
cli-v*タグの push(バックエンド本体のリリースと分離するための prefix)。workflow_dispatchはビルドの素振り用で、Release は作らない(後述)ターゲット: 4 種をすべてネイティブランナーでビルド(クロスコンパイルは mold との相性が悪いため避けた)
x86_64-unknown-linux-gnuubuntu-latestaarch64-unknown-linux-gnuubuntu-24.04-armx86_64-apple-darwinmacos-15-intelaarch64-apple-darwinmacos-15macOS のラベルは明示的に固定している。
macos-latestは 1〜2 か月かけて新しい OS へ段階移行するため、リリース成果物の再現性が保てない。-large/-xlargeは larger runner で public リポジトリでも課金対象になるので使わない(標準ランナーは public リポジトリでは無料)。成果物:
vrt-<target>.tar.gz(バイナリ 1 本のみ、ディレクトリで包まない)とvrt-<target>.tar.gz.sha256。ダウンロード側が URL を組み立てられるよう命名を固定しているpermissionsはトップでcontents: read、Release 作成ジョブだけcontents: writemold は Linux ランナーのみ導入(
apps/backend/.cargo/config.tomlが Linux ターゲットで要求するため)2.
vrt upload --json指定すると stdout に 1 行の JSON を出力する。
{"build_id":"...","build_number":123,"tenant_slug":"koyori","project_slug":"task","status":"changes_detected","exit_code":1}statusは--wait指定時は最終状態、非指定時は finalize 直後の状態exit_codeは CLI の終了コードと同じ(passed/approved=0、changes_detected=1、その他=2)--jsonの有無に関わらず常に stderr へ出す。CLI のログは stderr に出すのが一般的で、これにより stdout を結果専用に空けられる--waitの挙動は変えていない3. README
リリースバイナリの入手手順を推奨として先に置き、ソースビルドの記述も残した。
--jsonの説明と失敗時の挙動も追記。レビュー対応(コミット dc216fe)
いただいた指摘 5 件すべてに対応した。
workflow_dispatchで release ジョブが失敗する — release ジョブにif: startsWith(github.ref, 'refs/tags/cli-v')を追加し、on:側にも手動実行の位置づけ(ビルドの素振り、Release は作らない)をコメントで書いた--json時のエラー経路 — README に「ビルド作成前の失敗では JSON を出さない」旨を明記poll_until_terminalの doc を--json時は stderr になる旨を含めて修正.sha256はアーカイブ名込みで記録されるため、配布時のファイル名のまま取得しないとshasum -cが通らない。例を修正し検証の一行を追加macos-13→macos-15-intel)あわせて
exit_code_for/is_settledのユニットテストを 3 件追加した(推奨いただいた分)。終了コードは CI の合否判定そのものなので 8 状態すべてを固定し、未知の状態が黙って 0(成功)に倒れないことも明示的に押さえている。経緯(レビュー前に自分で直した分)
BuildResponse.numberの#[serde(default)]を外した。OpenAPI のrequiredに含まれる必須フィールドで、default があると契約変更時に黙って0になり、呼び出し元が/builds/0という存在しないレビュー URL を作ってしまうためmacos-13はactions/runner-imagesで提供が終了していた(現在の提供は macOS 15 / 26 系、14 は deprecated)。そのままではリリースジョブが「該当ランナー無し」で起動できなかった確認したこと
cargo test -p vrt-cli21 件 PASS(既存 18 + 新規 3)、cargo clippy -p vrt-cli --all-targets -- -D warnings/cargo fmt --all -- --check通過vrt upload --helpに--jsonが出ることを確認uses:すべて 40 桁 SHA でピン留めactions/download-artifactv7.0.0 /softprops/action-gh-releasev2.4.1 /actions/upload-artifactv7.0.1)actions/runner-imagesの README で確認(ubuntu-24.04-arm/macos-15/macos-15-intel)未検証: リリースワークフロー自体は実行していない。タグを切って初めて動く。
後続
マージ後に
cli-v0.1.0タグを切ると Release が作られる。それを koyori-app/vrt-actions#1 がダウンロードして使う。