團隊重新命名公開 API 後,本機專案仍可正常編譯,但文件中的舊符號連結已經失效。這類問題通常要等到發佈前人工瀏覽文件時才會曝光。更可靠的做法,是在雲端 Mac 的每次合併檢查中執行 DocC 建置,讓無法解析的參照、重複主題和編譯警告直接導致檢查失敗,同時保留靜態網站與診斷記錄。
先定義門禁邊界
DocC 門禁不應包辦所有文件檢查。它最適合驗證 Swift 符號、文章目錄、主題層級與內部參照。至於外部網址是否可存取、文字風格是否一致,則適合放在獨立作業中,否則一次暫時性的網路逾時就可能阻擋程式碼合併。
建議先定義三類結果:
| 結果 | 處理方式 | 典型情況 |
|---|---|---|
| 錯誤 | 立即阻擋 | 無法解析的符號、無效的目錄結構 |
| 警告 | 阻擋主分支 | 失效的主題參照、重複識別碼 |
| 建議 | 記錄但放行 | 摘要過短、範例仍可補充 |
文件門禁的目標不是追求零提示,而是讓相同輸入在固定環境中得到一致結論。規則必須能在開發機與 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 應從乾淨的 checkout 開始,依賴解析檔案必須納入版本控制,產生文件所需的資源檔案也不能依賴開發者目錄中的本機副本。如果指令碼會產生 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 位址,並限制並行數量。針對逾時和伺服器端限流進行有限次重試;只有持續失敗才阻擋作業。含有臨時權杖、查詢參數或內部位址的連結,不應寫入公開文件,也不應出現在檢查記錄中。
處理常見失敗並建立驗收清單
「符號存在但 DocC 找不到」通常有三個原因:符號不屬於目前的 scheme、存取層級未納入文件範圍,或連結使用了過時的完整簽章。應先確認 target,再查看產生記錄中的候選符號,不要靠反覆修改拼字來嘗試排錯。
文章連結失效時,應檢查檔名、由標題產生的識別碼,以及目錄中的相對層級。資源載入失敗時,則應核對大小寫與 target membership。雲端檔案系統會嚴格依照實際路徑運作;只在部分本機環境中碰巧可用的大小寫寫法不應保留。
最終門禁應能回答以下問題:
- 是否記錄了 Xcode 與 Swift 版本;
- 工作區是否從乾淨狀態開始;
- DocC 警告是否依約定處理;
- 是否找到且只處理預期的 archive;
- 靜態網站進入點是否存在;
- 建置記錄與檔案清單是否已封存;
- 外部連結故障是否與 DocC 編譯故障分開回報。
當這些檢查全部由同一支指令碼執行時,文件變更便能和程式碼變更一樣,提供可重現的失敗現場。維護者可以從記錄中定位參照問題、透過靜態產物審閱結構,也能在升級 Xcode 後明確比較行為差異。
常見問題
DocC 建置成功是否代表所有外部連結都能存取?
不是。DocC 主要驗證符號參照與文件目錄內的主題連結;外部 HTTP 連結應由獨立工作驗證,並設定逾時、重試與允許清單。
為什麼要在 CI 固定 Xcode 路徑?
不同 Xcode 版本包含不同的編譯器與 DocC 行為。明確檢查 DEVELOPER_DIR,可避免執行節點的預設版本變更後產生難以追查的文件差異。
在 OpsVM 部署雲端 Mac 工作流程
從三種 Apple Silicon 配置與 6 個在售節點中選擇,實際可用狀態以控制台即時回傳結果為準。