4. 持续集成核心概念与流水线设计
持续集成(Continuous Integration,CI)不是“把 Jenkins 装起来”这么简单,它是一组工程约束:任何一次代码或模型变更,都必须在可重复的环境中自动完成构建、检查与验证,并尽快把结果反馈给提交者。对 Simulink 项目而言,CI 的难点在于模型是二进制文件、依赖 MATLAB/Simulink 授权、仿真耗时长、结果包含数值与图形两类证据。因此流水线设计必须围绕“可重复、可追溯、可反馈”三个原则展开。
CI 的四条基本原则
第一条是单一可信源:所有模型、脚本、配置、测试用例都纳入 Git 管理,禁止在本地保留“只有我这里有”的 .slx 版本。第二条是每次提交都触发验证,而不是每周集中跑一次。第三条是构建可重复:同一 commit 在任意 agent 上应得到一致的编译与仿真结果,这要求固定 MATLAB 版本、固定依赖工具箱、固定随机种子。第四条是失败即阻断:一旦关键检查失败,后续阶段不再继续,避免把错误制品传递到下游。
构建触发方式与选择
常见触发方式包括:push 触发(每次推送即跑)、Pull Request 触发(合并前验证)、定时触发(夜间全量回归)、手动触发(发布前验证)。对 Simulink 项目,推荐组合使用:PR 触发跑“快速门禁”(模型编译 + 静态检查 + 少量冒烟测试),push 到主干触发“中等回归”,夜间定时触发“全量 MIL/SIL 回归”。这样既保证反馈速度,又控制授权与算力成本。
# 示例:GitLab CI 触发规则(示意)
smoke_test:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
script:
- matlab -batch "run('ci/run_smoke.m')"
nightly_regression:
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
script:
- matlab -batch "run('ci/run_full_regression.m')"
阶段划分:从门禁到制品
一条典型的 Simulink CI 流水线可划分为五个阶段:准备(拉取代码、恢复缓存、检查授权)、静态检查(模型规范检查、命名与配置检查)、构建(模型编译、代码生成)、测试(单元测试、MIL/SIL 回归)、制品与反馈(归档结果、发布报告)。阶段之间通过制品传递,而不是通过共享工作目录,这样才能保证可追溯。
下面这张图展示了流水线各阶段、触发条件、输入输出与反馈路径之间的关系,也标出了 Simulink 在其中的位置。
制品管理:让结果可追溯
制品(Artifact)是流水线各阶段产出的、需要被保存和传递的文件。Simulink 项目中常见的制品包括:编译后的模型缓存(.slxc)、生成的 C 代码、测试结果 .mat 文件、覆盖率报告、HTML 测试报告。制品管理的关键是按 commit 版本索引,即每个制品都能回答“它来自哪个 commit、哪个 MATLAB 版本、哪次流水线运行”。
实践中建议:测试报告和覆盖率报告作为长期制品保留(例如 90 天),编译缓存作为短期制品(例如 7 天)用于加速后续构建。制品命名应包含 commit 短哈希与流水线 ID,例如 report_${CI_COMMIT_SHORT_SHA}_${CI_PIPELINE_ID}.html。这样在排查回归失败时,可以直接定位到对应版本的报告,而不需要重新跑一遍仿真。
反馈机制:快、准、可行动
反馈机制决定 CI 是否真正被团队使用。好的反馈有三个特征:快(PR 门禁在 10 分钟内给出结论)、准(失败信息指向具体模型、具体测试用例、具体信号)、可行动(附上报告链接和失败波形截图)。Simulink 测试失败时,仅输出“测试失败”没有价值,应输出:哪个测试用例、哪个信号、在哪个时间点超出容差、期望值与实际值分别是多少。
Simulink 在流水线中的位置
Simulink 不是流水线中的一个“步骤”,而是贯穿构建与测试阶段的核心工具链。模型文件既是源代码,也是被测对象;模型编译对应传统软件的编译;仿真执行对应测试执行。因此 Simulink 流水线的设计必须额外考虑:MATLAB 授权并发数、仿真并行加速(parsim / parfeval)、模型依赖的库与数据字典版本一致性。
一个常见的误区是把 Simulink 测试放在流水线最后“有空再跑”。正确做法是把模型编译和静态检查放在最前面作为门禁,因为这两步最快、最能暴露低级错误;把耗时的 MIL/SIL 回归放在夜间或独立阶段,并通过并行池加速。这样既保证了快速反馈,又不会因为仿真时间长而拖垮整个流水线。