依赖、CI、制品与发布流程 / Dependencies, CI, Artifacts, and Release Flow
1. CI 要产出可追溯的发布路径
CI 不是把本机命令搬到云端。工程 CI 要在多个平台、编译器、构建类型和依赖组合上产生可追溯证据,并把普通 PR、可信分支、发布 tag 的权限边界分开。
2. 最简单心智模型
PR CI 负责快速反馈和阻止明显错误。 Nightly CI 负责重型 sanitizer、fuzz、长 benchmark 和更多平台。 Release CI 负责不可变制品、签名、证据归档和发布提升。
pull request -> fast build/test/lint
main branch -> full matrix + sanitizer + package smoke
tag release -> reproducible build + sign + evidence + publish
incident -> rollback using previous artifact + evidence ledger3. 核心术语
CI 矩阵:把平台、编译器、构建类型、依赖版本和检查类型组合成可执行的验证集合。
依赖锁:记录依赖的精确版本或来源,避免今天和明天构建出行为不同的程序。
artifact:流水线产出的可保存文件,例如安装包、测试报告、覆盖率、符号包和发布清单。
cache key:CI 判断缓存能否复用的标识。设计不好会导致缓存失效、污染或把旧依赖混进新构建。
release promotion:同一个已验证制品从候选版本提升到正式发布,而不是在最后一步重新构建一份未知产物。
rollback:把线上或用户侧恢复到上一个已知可用版本的流程,包括制品、配置、依赖和验证步骤。
4. 机制展开
矩阵不是越大越好
矩阵要覆盖真实支持承诺,而不是追求好看。
每增加一个维度,都要问它能发现哪类风险、成本是多少、失败由谁处理。
缓存不能破坏可复现
缓存 key 应包含编译器、依赖锁、构建类型和平台信息。
缓存命中可以加速,但不能成为唯一依赖来源;发布 job 应能从锁文件和镜像重新构建。
发布提升
建议把 build、test、package、sign、publish 分成阶段。只有前一阶段证据完整,才允许提升到下一阶段。
fork PR 不应获得发布 token;发布凭据只出现在受保护 tag 或手动审批环境。
5. 最小示例
下面的示例不是完整项目,而是为了把本篇概念落到可审查文本。阅读代码时关注它暴露了哪些边界,而不是照抄每个名字。
jobs:
build-test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
build_type: [Debug, Release]
steps:
- uses: actions/checkout@v4
- run: cmake --preset ci-${{ matrix.build_type }}
- run: cmake --build --preset ci-${{ matrix.build_type }}
- run: ctest --preset ci-${{ matrix.build_type }} --output-on-failure6. 工程取舍
| 选择 | 收益 | 风险 | 需要的证据 |
|---|---|---|---|
| 只在本机验证 | 反馈最快 | 环境不可复现 | 仅适合草稿,不适合作为发布结论 |
| CI 快速门禁 | 阻止常见错误 | 覆盖不完整 | 明确矩阵、日志和失败归属 |
| 完整发布门禁 | 证据最强 | 成本更高 | 制品、符号、SBOM、ABI 和回滚记录 |
| 最小消费者测试 | 最接近用户 | 需要维护样例 | 独立目录、安装包、运行输出 |
7. 常见错误
- 把“当前源码树能构建”误认为“安装包能被别人消费”。
- 把 PRIVATE 实现细节通过头文件、导出符号或包配置泄漏出去。
- 只保存最终二进制,不保存构建输入、依赖锁、调试符号和版本信息。
- 只在 Debug 测试,不在 Release 或发布配置里测试。
- 把 CI 缓存当成依赖管理,把绿色状态当成发布结论。
- 遇到链接或 ABI 问题时只改 flags,不留下能够复盘的符号证据。
8. 调试与验证方法
定义公开承诺
写清楚本库承诺源码兼容、二进制兼容、协议兼容还是仅内部使用。承诺越模糊,升级事故越难判责。
observe 依赖锁
-> isolate artifact
-> run minimal proof
-> store evidence建立干净环境
用全新 build directory 和最小 consumer project 验证,不依赖源码树中的 include 路径和本机缓存。
observe CI 矩阵
-> isolate 依赖锁
-> run minimal proof
-> store evidence固定工具版本
记录编译器、CMake、Ninja、包管理器、系统镜像和关键 flags,避免把偶然环境当成规则。
observe rollback
-> isolate CI 矩阵
-> run minimal proof
-> store evidence保存失败证据
失败日志、符号报告、测试输出和构建命令要能被别人复现,而不是只留一句“CI failed”。
observe release promotion
-> isolate rollback
-> run minimal proof
-> store evidence区分私有与公开
私有实现可以快速迭代;公开头、导出符号、包元数据和 ABI policy 必须谨慎变更。
observe cache key
-> isolate release promotion
-> run minimal proof
-> store evidence审查跨平台差异
Windows 的 DLL/import lib/PDB 与 Linux 的 so/SONAME/RPATH/debug file 不同,不能用一个平台的经验套全部。
observe artifact
-> isolate cache key
-> run minimal proof
-> store evidence限制全局状态
全局 include、全局 flags、隐式环境变量和手工 PATH 修改都会让构建不可解释。
observe 依赖锁
-> isolate artifact
-> run minimal proof
-> store evidence做升级测试
old consumer + new library、new consumer + package install 是比单纯编译源码更接近用户现场的测试。
observe CI 矩阵
-> isolate 依赖锁
-> run minimal proof
-> store evidence设置回滚入口
发布前准备上一稳定制品、数据库或文件格式迁移策略、插件兼容说明和符号包。
observe rollback
-> isolate CI 矩阵
-> run minimal proof
-> store evidence写入 CI
能自动检查的规则不要只写在文章里;把它变成 preset、脚本、workflow 或 release checklist。
observe release promotion
-> isolate rollback
-> run minimal proof
-> store evidence管理例外
允许临时豁免时必须记录原因、过期时间和补偿测试,否则门禁会慢慢失去意义。
observe cache key
-> isolate release promotion
-> run minimal proof
-> store evidence保持证据总账
把构建输入、依赖锁、测试、ABI、性能、SBOM、签名和制品 hash 放在同一发布记录中。
observe artifact
-> isolate cache key
-> run minimal proof
-> store evidence9. 本篇专属检查表
- PR 是否禁用发布 token。
- cache key 是否含锁文件 hash。
- artifact 命名是否含平台和 ABI。
- 发布是否需要审批。
- 回滚包是否已保留。
| 检查点 | 通过标准 | 失败时优先看哪里 |
|---|---|---|
| CI 矩阵 | 有可重复命令、报告或 consumer 证明 | target 属性、CI 日志、符号报告、包元数据 |
| 依赖锁 | 有可重复命令、报告或 consumer 证明 | target 属性、CI 日志、符号报告、包元数据 |
| artifact | 有可重复命令、报告或 consumer 证明 | target 属性、CI 日志、符号报告、包元数据 |
| cache key | 有可重复命令、报告或 consumer 证明 | target 属性、CI 日志、符号报告、包元数据 |
| release promotion | 有可重复命令、报告或 consumer 证明 | target 属性、CI 日志、符号报告、包元数据 |
| rollback | 有可重复命令、报告或 consumer 证明 | target 属性、CI 日志、符号报告、包元数据 |
10. 练习任务
- 建立一个只有一个库和一个 consumer 的最小工程,证明安装树可用。
- 故意破坏一个 PUBLIC/PRIVATE 作用域,观察消费者构建失败方式。
- 保存一次链接或 ABI 报告,并写下它能证明什么、不能证明什么。
- 把一个手工验证命令改成 CI 步骤,并让失败消息能指向具体文件或配置。
- 写一份 release evidence 小清单,列出制品、符号、依赖、测试和回滚入口。
12. 总结
《依赖、CI、制品与发布流程 / Dependencies, CI, Artifacts, and Release Flow》的核心不是多记几个命令,而是把 CI 矩阵、依赖锁、artifact、cache key、release promotion、rollback 变成可审查、可复现、可回滚的工程证据。
深化问题 1:依赖锁 怎样变成证据
围绕 依赖锁 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:用全新 build directory 和最小 consumer project 验证,不依赖源码树中的 include 路径和本机缓存。
rule: 依赖锁
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 2:artifact 怎样变成证据
围绕 artifact 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:记录编译器、CMake、Ninja、包管理器、系统镜像和关键 flags,避免把偶然环境当成规则。
rule: artifact
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 3:cache key 怎样变成证据
围绕 cache key 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:失败日志、符号报告、测试输出和构建命令要能被别人复现,而不是只留一句“CI failed”。
rule: cache key
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 4:release promotion 怎样变成证据
围绕 release promotion 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:私有实现可以快速迭代;公开头、导出符号、包元数据和 ABI policy 必须谨慎变更。
rule: release promotion
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 5:rollback 怎样变成证据
围绕 rollback 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:Windows 的 DLL/import lib/PDB 与 Linux 的 so/SONAME/RPATH/debug file 不同,不能用一个平台的经验套全部。
rule: rollback
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 6:CI 矩阵 怎样变成证据
围绕 CI 矩阵 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:全局 include、全局 flags、隐式环境变量和手工 PATH 修改都会让构建不可解释。
rule: CI 矩阵
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 7:依赖锁 怎样变成证据
围绕 依赖锁 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:old consumer + new library、new consumer + package install 是比单纯编译源码更接近用户现场的测试。
rule: 依赖锁
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 8:artifact 怎样变成证据
围绕 artifact 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:发布前准备上一稳定制品、数据库或文件格式迁移策略、插件兼容说明和符号包。
rule: artifact
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 9:cache key 怎样变成证据
围绕 cache key 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:能自动检查的规则不要只写在文章里;把它变成 preset、脚本、workflow 或 release checklist。
rule: cache key
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 10:release promotion 怎样变成证据
围绕 release promotion 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:允许临时豁免时必须记录原因、过期时间和补偿测试,否则门禁会慢慢失去意义。
rule: release promotion
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 11:rollback 怎样变成证据
围绕 rollback 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:把构建输入、依赖锁、测试、ABI、性能、SBOM、签名和制品 hash 放在同一发布记录中。
rule: rollback
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 12:CI 矩阵 怎样变成证据
围绕 CI 矩阵 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:写清楚本库承诺源码兼容、二进制兼容、协议兼容还是仅内部使用。承诺越模糊,升级事故越难判责。
rule: CI 矩阵
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 13:依赖锁 怎样变成证据
围绕 依赖锁 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:用全新 build directory 和最小 consumer project 验证,不依赖源码树中的 include 路径和本机缓存。
rule: 依赖锁
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 14:artifact 怎样变成证据
围绕 artifact 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:记录编译器、CMake、Ninja、包管理器、系统镜像和关键 flags,避免把偶然环境当成规则。
rule: artifact
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 15:cache key 怎样变成证据
围绕 cache key 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:失败日志、符号报告、测试输出和构建命令要能被别人复现,而不是只留一句“CI failed”。
rule: cache key
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 16:release promotion 怎样变成证据
围绕 release promotion 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:私有实现可以快速迭代;公开头、导出符号、包元数据和 ABI policy 必须谨慎变更。
rule: release promotion
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 17:rollback 怎样变成证据
围绕 rollback 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:Windows 的 DLL/import lib/PDB 与 Linux 的 so/SONAME/RPATH/debug file 不同,不能用一个平台的经验套全部。
rule: rollback
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 18:CI 矩阵 怎样变成证据
围绕 CI 矩阵 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:全局 include、全局 flags、隐式环境变量和手工 PATH 修改都会让构建不可解释。
rule: CI 矩阵
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 19:依赖锁 怎样变成证据
围绕 依赖锁 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:old consumer + new library、new consumer + package install 是比单纯编译源码更接近用户现场的测试。
rule: 依赖锁
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 20:artifact 怎样变成证据
围绕 artifact 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:发布前准备上一稳定制品、数据库或文件格式迁移策略、插件兼容说明和符号包。
rule: artifact
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception深化问题 21:cache key 怎样变成证据
围绕 cache key 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。
对应的工程动作是:能自动检查的规则不要只写在文章里;把它变成 preset、脚本、workflow 或 release checklist。
rule: cache key
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception