工程指南

云端 Mac 用 DocC 建立文档构建与链接门禁

云端 Mac 用 DocC 建立文档构建与链接门禁

团队把公共 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 应从干净检出开始,依赖解析文件必须纳入版本控制,生成文档所需的资源文件也不能依赖开发者目录中的本地副本。若脚本会生成 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 版本可能包含不同的 Swift 编译器与 DocC 行为。显式检查并选择 DEVELOPER_DIR,可避免执行节点默认版本变化后产生无法解释的文档差异。

独享物理节点

在 OpsVM 部署云端 Mac 工作流

从三档 Apple Silicon 配置与 6 个在售节点中完成选择,实际可用状态以控制台实时返回为准。

选择配置并下单