項目32:CIシステムを設定しよう
LT;DR
すべてのテストは CI 上で実行しよう
CI は素早く、決定的に動作し、偽陽性 がゼロでなければならない Protocol Buffers などからコードを自動生成する場合、CI 上でも自動生成して元のコードベースと整合するかチェックしよう
コードベースに秘密情報が含まれていないことのチェックは、CI 上ではなく Pre-commit 時にチェックしよう
チェックは実行頻度によって分割しよう
偽陽性 であっても CI の失敗は許容しないようにしよう プロセスの問題を修正する前に、問題を検出する CI ステップを追加しよう
Rust
rust-toolchain.toml で CI 上の Rust のバージョンを固定しよう
radish-miyazaki.icon が個人的に API 開発で CI 上で Must で実行したいツール群
cargo test
cargo clippy
cargo tarpaulin
cargo-deny / cargo-udeps
Rust は特に依存関係が肥大化しがちなので
以下は任意または一部で実行する
cargo doc
cargo bench
hr.icon
大まかには以下の 2 つ
クレート に フィーチャ がある場合は「CI でフィーチャのすべての有効な組み合わせ(2N)に対してビルドしよう」 no_std 互換の場合は「CI で no_std であることをテストしよう」 MSRV を設定する場合は「MSRV をCI でチェックしよう」 2. コードに対してテストを実行する
「すべてのテストは CI で実行しよう」
どちらのステップも、素早く 決定的 に動作 し、偽陽性 がゼロ でなければならない 具体的には、rust-toolchain.toml の [channel] テーブルに以下を指定する
バージョン(e.g. 1.70)
チャンネル(stable、beta、nightly)
nightly の場合は、日付を付けることもできる(e.g. nightly-2023-09-19)
上記以外にも、コードの品質を改善するステップを追加することもできる
「CI で Clippy(cargo clippy --Dwarnings)を実行しよう」 --Dwarnings オプションを付けると、警告が見つかったときにビルドが失敗するようになる
ドキュメント生成: cargo doc
CI で cargo doc を実行して、ドキュメントが生成されることと ハイパーリンク がリンク切れしていないことを確認しよう 問題のあるクレートの検出: cargo-deny / cargo-udeps
--check を用いると問題点が分かりやすくなる
また、コードのある性質を測定するステップも追加できる
外部要因に大きく依存ため、信頼性 の高い結果を得るには専用の環境が必要 warning.icon
これら 2 つの測定は 前回の結果と比較する必要 がある
∵ テストが不十分だったり、パフォーマンスに悪影響が出ることを検出できるようにするため
プロジェクトによっては入れる必要のあるステップ
クレートライブラリの場合
Cargo.lock を使わずにビルドする
ユーザはライブラリの Cargo.lock を必要としないため、Cargo.toml の依存ライブラリのバージョン指定でうまく機能するか確認する
リソースを再生成して、既存のものと整合するか確認する
プラットフォーム固有(#[cfg(target_arch = "arm"])の処理がある場合
コードがビルドできることと(可能なら)そのプラットフォーム上で動作することを確認する
秘密情報が誤ってチェックインされていないことを確認する
warning.icon このステップは CI 上ではなく、 Git フック を用いてコミット前に行うこと CI チェックは Cargo や Rust のツールチェーンを使わずに、シェルスクリプトでも良い
特にコードベースが独自の慣習に従っている場合
e.g.
TODO コメントには所有者を付ける
公開されている Rust のプロジェクトのCI を参考にしよう
CI の原則
CI の最も基本的な原則は「人間の時間を無駄使いするな」
CI が不必要にエンジニアの時間を浪費すると、回避する方法を探し始める
よくある時間を無駄にするパターン
完了までに時間がかかる(レビュー依頼後も走る) CI
CI で検出できたはずの問題を Reviewer が指摘することで時間が無駄になる
解決策
Flaky test
初期投資 として、原因を調査して修正する時間をとる 完了までに時間がかかる(レビュー依頼後も走る) CI
1. CI 上で動かしているチェックを手動で実行できるようにする
ローカル環境や IDE に組み込む
2. チェックを頻度に応じて分割する
一般的には、以下のように分割する
各エンジニアの開発環境に統合されたチェック(e.g. rustfmt)
PR 作成時に実行され、手動でも簡単に実行できるチェック(e.g. cargo clippy、cargo build) メインブランチを変更するたびに行うチェック(e.g. すべてのサポート環境を対象とした cargo test)
現在のコードに常時実行されるチェック(e.g. ファズテスト) また、偽陽性 であっても CI の失敗を認めてはいけない 認めてしまうと、新しいリグレッションエラーを見つけるのが困難になる
「プロセスの問題を修正する前に、問題を検出する CI ステップを追加しよう」
e.g.
なんらかの自動生成されるコードが元のコード整合していない場合、整合性をチェックする CI ステップを追加すべきである
パブリックな CI システム
OSS として公開しているコードベースの場合、いくつか知っておくべきことがある コードが他のものに依存する場合、CI システムは事前条件 のセットアップ方法を示すガイドとして機能する e.g. データベースや FFI コード用のツールチェイン、設定 これをスクリプトとしてまとめておくと、ユーザと CI の両方が簡単にセットアップできるようになる
悪用や攻撃の可能性がある
e.g.
これを防ぐために、以下のガイドラインを検討すること
既知のコラボレータに対してのみ CI が自動的に実行するようにアクセスを制限し、新しい コントリビュータ については手動で実行する すべての外部スクリプトのバージョン(ハッシュ)を固定する
コードベースへの Read 権限以上を必要とするステップについては、厳重に監視する