API 定义已经更新,SDK 却还停留在上一个版本;命令行工具新增了参数,文档示例却没有同步——这类问题往往不是生成器能力不足,而是生成动作离 API 变更太远。
Forge 是一套可插拔的开源生成流水线,可以在 CI 中直接根据 API 定义生成 SDK、CLI、文档等开发者工具。它最值得关注的设计,是把生成工作前移到各团队自己的代码仓库,让 API 变更和配套工具更新进入同一条交付链路。
从“集中维护”转向“变更发生处生成”
传统做法常由一个平台团队集中维护所有 SDK 和文档。业务团队修改 API 后,需要通知平台团队、等待生成任务运行,再分别发布产物。随着服务数量增加,这条链路很容易出现版本错位。
将 Forge 放进服务仓库后,流程可以变成:
- 团队修改 OpenAPI 等 API 定义;
- CI 调用 Forge 的生成流水线;
- 插件分别生成 SDK、CLI 和文档;
- CI 检查生成结果是否与仓库内容一致;
- 代码评审同时覆盖 API 和开发者工具的变化。
这种模式把责任边界变得更清楚:定义 API 的团队也要对生成结果负责。平台团队则可以集中维护插件、默认配置和发布规范,而不必手动跟进每个服务的每次变更。
可插拔流水线为什么重要
SDK、CLI 和文档虽然都来自同一份 API 定义,但它们的生成要求并不相同:
- SDK 需要处理语言版本、包名、认证方式和发布仓库;
- CLI 需要设计命令层级、参数名称及退出码;
- 文档需要补充示例、导航和站点元数据;
- 企业内部还可能需要生成测试夹具、策略文件或 API 目录信息。
可插拔设计允许团队复用共同的流水线,同时按目标产物组合不同插件。更重要的是,插件版本可以被固定和审查,避免开发者本地工具版本不同而产生大量无意义差异。
不过,“来自同一个 API 定义”不等于“所有产物都应完全自动发布”。生成代码仍然需要格式化、测试、兼容性检查和人工评审。尤其是公开 SDK,方法重命名或类型变化可能构成破坏性升级,即使 API 定义本身能够通过语法校验。
可以这样接入 CI
下面是一个可改造的最小项目结构:
payments-api/
├── api/
│ └── openapi.yaml
├── generated/
│ ├── sdk/
│ ├── cli/
│ └── docs/
├── scripts/
│ └── generate.sh
└── .github/
└── workflows/
└── generated-assets.yml
由于具体 Forge CLI 参数取决于项目采用的版本和配置,下面假设命令形式为 forge generate。接入时需要按实际 CLI 调整参数,但 CI 的关键机制不变:固定输入、生成产物,然后检查工作区是否出现未提交差异。
创建 scripts/generate.sh:
#!/usr/bin/env bash
set -euo pipefail
FORGE_BIN="${FORGE_BIN:-forge}"
API_DEFINITION="${API_DEFINITION:-api/openapi.yaml}"
OUTPUT_DIR="${OUTPUT_DIR:-generated}"
command -v "$FORGE_BIN" >/dev/null 2>&1 || {
echo "Forge executable not found: $FORGE_BIN" >&2
exit 127
}
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"
# 示例接口:请根据实际 Forge 版本修改参数。
"$FORGE_BIN" generate \
--definition "$API_DEFINITION" \
--output "$OUTPUT_DIR"
然后执行:
chmod +x scripts/generate.sh
./scripts/generate.sh
git diff -- generated/
如果团队选择将生成结果提交到同一个仓库,可以加入 GitHub Actions 检查:
name: Verify generated developer tools
on:
pull_request:
paths:
- "api/**"
- "scripts/generate.sh"
- "generated/**"
- ".github/workflows/generated-assets.yml"
jobs:
verify:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
# 假设团队已将固定版本的 Forge 安装到 PATH。
# 实际项目应替换为官方安装方式或内部工具镜像。
- name: Install Forge
run: ./tools/install-forge.sh
- name: Regenerate SDKs, CLI, and docs
run: ./scripts/generate.sh
- name: Reject stale generated files
run: |
if ! git diff --exit-code -- generated/; then
echo "Generated files are stale. Run ./scripts/generate.sh and commit the result."
exit 1
fi
这段工作流假设仓库内提供了 tools/install-forge.sh,并且安装脚本固定 Forge 的明确版本。不要在 CI 中无条件安装“最新版”,否则同一提交可能在不同日期生成不同结果。
如果团队不希望提交生成代码,也可以让 CI 将产物上传到制品仓库,并通过输入定义的提交 SHA、Forge 版本和插件版本生成唯一版本号。无论采用哪种方式,都应保证产物可以追溯到确切的 API 定义。
真正需要守住的是可重复性
把生成器放进 CI 只是第一步。要让这条链路长期可靠,还需要控制几个边界:
- 固定工具与插件版本:避免插件升级悄悄改变公开接口;
- 检查确定性:时间戳、随机 ID 和本机绝对路径不应进入生成文件;
- 加入兼容性门禁:在生成前后比较 API 定义,识别删除字段、修改类型等破坏性变化;
- 测试生成产物:至少执行编译、格式检查和一个最小调用测试;
- 隔离插件权限:生成插件属于 CI 供应链的一部分,不应默认获得发布密钥;
- 明确发布策略:API 合并不一定意味着 SDK 必须立即发布,预览产物和正式版本可以使用不同阶段。
对于已经拥有大量服务的组织,不必一次迁移全部仓库。可以先选择一个 API 变化频繁、SDK 维护成本较高的服务,验证生成耗时、差异稳定性和发布流程。等插件、目录结构与版本策略稳定后,再将同一套 CI 模板推广到更多团队。
Forge 带来的核心变化并不只是“少写一些客户端代码”,而是让 API 定义、开发者工具和评审流程共享同一个变更节奏。只有当生成过程可重复、产物可审查、版本可追溯时,这种上游生成模式才能真正减少不同步,而不是把人工维护变成另一种自动化噪声。