チームが公開APIの名前を変更しても、ローカルのプロジェクトはコンパイルできる一方、文書内に残った旧シンボルへのリンクは壊れていることがあります。この問題は、リリース直前に人が文書を確認するまで表面化しないのが一般的です。より確実な方法は、クラウドMac上のマージチェックごとにDocCビルドを実行し、解決できない参照、重複トピック、コンパイル警告を失敗として扱い、静的サイトと診断ログも保存することです。
まず品質ゲートの範囲を定義する
DocCの品質ゲートですべての文書チェックを担うべきではありません。DocCが特に得意とするのは、Swiftシンボル、記事の構成、トピック階層、内部参照の検証です。外部URLにアクセスできるか、文体が統一されているかといった確認は、独立したジョブに分けるのが適しています。そうしなければ、一時的なネットワークタイムアウトだけでコードのマージが妨げられる可能性があります。
まず、結果を次の3種類に分類します。
| 結果 | 処理方法 | 代表的なケース |
|---|---|---|
| エラー | 即時ブロック | 解決できないシンボル、無効なカタログ構造 |
| 警告 | メインブランチでブロック | 壊れたトピック参照、識別子の重複 |
| 提案 | 記録して通過 | 概要が短すぎる、サンプルを追加できる |
文書の品質ゲートは、あらゆる通知をゼロにするためのものではありません。同じ入力から、固定された環境で同じ結論が得られるようにすることが目的です。すべてのルールは、開発マシンとCIノードの両方で同じコマンドを使って再現できなければなりません。
文書の配置にも、単一の信頼できる情報源を設けます。モジュール文書は対応するtargetの.doccディレクトリに置き、モジュール横断のガイドは集約を担当する文書targetに配置します。同じ記事を複数のcatalogへ複製してはいけません。改訂時に一方しか更新されない事態が起こりやすくなります。
Xcodeとビルド入力を固定する
リモートノードで最もよく起きる環境差異は、Xcodeのデフォルトパスに由来します。ジョブの開始時にバージョンを出力し、開発者ディレクトリを明示的に検証します。チームで複数のバージョンを管理している場合は、以前の対話セッションで選択された状態に依存せず、完全なパスをCI変数から渡します。
set -euo pipefail
: "${DEVELOPER_DIR:?set DEVELOPER_DIR}"
: "${SCHEME:?set SCHEME}"
test -x "$DEVELOPER_DIR/usr/bin/xcodebuild"
xcodebuild -version
swift --version
git status --short
ビルド前にはリポジトリの状態も確認します。CIはクリーンなチェックアウトから開始し、依存関係の解決ファイルをバージョン管理に含めなければなりません。文書生成に必要なリソースファイルも、開発者ディレクトリ内のローカルコピーに依存させないでください。スクリプトがMarkdownを生成する場合は、まず一時ディレクトリに生成して結果を比較し、コミットされていない差分が見つかったらジョブを失敗させます。
暗黙のワークスペース状態を避ける
長期間残るDerivedDataを再利用してはいけません。古いシンボルグラフによって削除済みの型が文書に残り続けたり、リソース不足が隠されたりする可能性があります。ジョブごとに独立したディレクトリを使用し、終了後は必要な診断情報とDocC成果物だけをアーカイブします。
再現可能なdocbuildを実行する
次のスクリプトは、ジョブごとに分離されたディレクトリを作成し、DocCの警告をエラーへ昇格させ、完全なログを保存します。generic/platform=iOSは、起動済みの特定のシミュレータに依存しません。そのため、シンボルグラフと文書のコンパイルだけが必要なチェックに適しています。
set -euo pipefail
ROOT="$PWD/.build/docs"
DERIVED="$ROOT/DerivedData"
LOG="$ROOT/docc-build.log"
rm -rf "$ROOT"
mkdir -p "$ROOT"
set -o pipefail
xcodebuild docbuild \
-scheme "$SCHEME" \
-destination "generic/platform=iOS" \
-derivedDataPath "$DERIVED" \
OTHER_DOCC_FLAGS="--warnings-as-errors" \
2>&1 | tee "$LOG"
ARCHIVE="$(find "$DERIVED/Build/Products" -name '*.doccarchive' -print -quit)"
test -n "$ARCHIVE"
printf '%s
' "$ARCHIVE" > "$ROOT/archive-path.txt"
schemeに文書生成が不要なtargetも含まれている場合は、ログから警告を除外するのではなく、プロジェクト設定で文書のコンパイル範囲を明示します。テキストをフィルタリングすると、本物のリグレッションまで見落とすおそれがあります。--warnings-as-errorsを初めて導入するときは、まず非ブロッキングのジョブとして一度実行し、既存の問題を修正してからマージゲートへ昇格させると安全です。
静的サイトをエクスポートして成果物を検証する
.doccarchiveは後続処理に適していますが、レビュー担当者には通常、そのまま開ける静的ファイルが必要です。archiveを見つけたら、DocCに組み込まれた変換コマンドでサイトを生成します。
set -euo pipefail
ARCHIVE="$(cat .build/docs/archive-path.txt)"
OUTPUT="$PWD/.build/docs/site"
xcrun docc process-archive transform-for-static-hosting \
"$ARCHIVE" \
--output-path "$OUTPUT" \
--hosting-base-path docs
test -s "$OUTPUT/index.html"
find "$OUTPUT" -type f | sort > .build/docs/site-files.txt
--hosting-base-pathは、最終的なデプロイ先のサブパスと一致させる必要があります。サイトを実際にはルートパスへ配置する場合、docsをそのまま流用してはいけません。パスが一致していないと、ローカルでトップページを直接開いたときは正常に見えても、デプロイ後にスクリプトやスタイルの取得でエラーが発生します。
アーカイブには、少なくともビルドログ、archiveのパス、静的サイト、ファイル一覧を含めます。ログは個々の診断を特定するために使い、ファイル一覧は想定外の大規模な削除を検出するために使います。静的サイトの保存期間は短めに設定できますが、失敗したジョブのログは問題が解決するまで保持すべきです。
外部リンクのチェックを分離する
外部リンクのチェックでは、生成後のHTMLを読み取り、アクセスが許可されたhttps URLだけを対象にし、同時実行数を制限します。タイムアウトやサーバー側のレート制限には回数を限定して再試行し、継続的に失敗する場合にだけブロックします。一時トークン、クエリパラメータ、内部アドレスを含むリンクは、公開文書に記載すべきではなく、チェックログにも残すべきではありません。
よくある失敗に対処して受け入れチェックリストを作る
「シンボルは存在するのにDocCが見つけられない」場合、通常は3つの原因があります。シンボルが現在のschemeに属していない、アクセスレベルが文書化の対象範囲に入っていない、またはリンクで古い完全シグネチャを使用している場合です。何度も綴りを変えて試すのではなく、まずtargetを確認し、生成ログに出力された候補シンボルを調べます。
記事へのリンクが壊れた場合は、ファイル名、タイトルから生成された識別子、catalog内の相対的な階層を確認します。リソースの読み込みに失敗した場合は、大文字と小文字、およびtarget membershipを確認してください。クラウドのファイルシステムは実際のパスを厳密に扱います。一部のローカル環境で偶然動作するだけの大文字・小文字表記を残してはいけません。
最終的な品質ゲートでは、次の問いに答えられる必要があります。
- XcodeとSwiftのバージョンが記録されているか。
- ワークスペースがクリーンな状態から開始されたか。
- DocCの警告が合意した方針どおりに処理されたか。
- 想定したarchiveが見つかり、それだけが処理されたか。
- 静的サイトのエントリーポイントが存在するか。
- ビルドログとファイル一覧がアーカイブされたか。
- 外部リンクの障害がDocCのコンパイル障害と分けて報告されているか。
これらのチェックをすべて同じスクリプトで実行すれば、文書の変更にもコード変更と同様に、再現可能な失敗時の状況が残ります。メンテナーはログから参照箇所を特定し、静的成果物から構造をレビューできます。また、Xcodeのアップグレード後に動作の違いを明確に比較することも可能です。
よくある質問
DocCのビルド成功で外部URLもすべて検証できますか?
できません。DocCが主に検証するのはシンボル参照と文書内のトピックリンクです。外部URLはタイムアウト、再試行、例外リストを備えた別ジョブで確認します。
CIでXcodeのパスを固定する理由は何ですか?
XcodeごとにコンパイラとDocCのバージョンが異なるためです。DEVELOPER_DIRを明示的に検証すれば、既定版の変更による予期しない差分を防げます。
OpsVMでクラウドMacワークフローを構築
Apple Silicon構成3種類と販売中の6ノードから選択できます。実際の利用可能状況はコンソールでリアルタイムに確認できます。