使用 GitLab 进行 Simulink 模型验证的持续集成
作者 : Jemima Pulipati、Anand Vaidyanathan Sarma 和 David Boissy,MathWorks
如果您使用的是 R2022a 或更高版本,并且有 Simulink Check™ 许可证,则可以通过使用 CI Support Package for Simulink® 来简化您的 CI 集成。使用该支持包,您可以为团队定义过程模型,并设置 CI 系统以自动将过程中的任务作为 CI 中的管道运行。该支持包包含对多个 CI 平台的支持,以便您可以自动生成特定于您的工程和过程的管道,无需手动更新。
主要功能:
- 内置任务:通过使用内置任务,自动化基于模型的开发和验证工作流中的常见任务,例如使用模型顾问检查建模标准、使用 Simulink Test™ 运行测试,以及使用 Embedded Coder® 生成代码。您无需为开发和验证活动管理各种脚本,而是可以重新配置并使用这些内置任务,以实现一致的执行和井然有序的任务结果。
- 增量编译:识别工程变更的影响,并自动仅重新运行受影响的任务,以帮助提高编译效率。过程顾问及其编译系统可以重新运行结果过期的任务,并自动跳过最新任务。
- 自动管道生成:使用支持包的模板文件自动生成管道,这样当您对工程或过程进行变更时,就无需手动更新 CI/CD 配置文件。您可以轻松自定义管道生成器的设置,以将任务划分为不同作业、并行运行模型任务,以及变更其他管道行为。
有关详细信息,请参阅持续集成和将过程集成到 GitLab。
此系列文章共两篇,这是第二篇。第 1 部分,Simulink 模型验证的持续集成,探讨使用 GitLab® 进行版本控制和使用 Jenkins® 进行持续集成 (CI)。本文讨论如何使用 GitLab 进行版本控制和 CI。
此示例中使用的工程可从 GitHub® 和 File Exchange 下载。
持续集成 (CI) 工作流
持续集成 (CI) 是一种敏捷方法的最佳实践。采用该实践时,开发人员会定期将源代码变更提交并合并到一个中央仓库中。然后这些“变更集”会自动构建、验证和发布。图 1 展示了这个基本的 CI 工作流以及开发工作流。
案例研究:在 GitLab 内验证、编译和测试的 Simulink 模型
在此示例中,我们使用基于模型的设计与 CI 对巡航控制系统(图 2)执行基于需求的测试。
CI 管道
CI 管道在技术文章 Simulink 模型验证的持续集成中进行说明。我们将应用这些相同的概念在 GitLab 中定义管道。每次在变更推送到 GitLab 仓库时,都会执行我们的 CI 管道。管道如图 3 所示。
图 3. 巡航控制系统的管道。
此示例管道中的阶段如下:
- 验证建模规范:运行 MATLAB® 脚本,以使用 ISO® 26262 检查通过模型顾问验证建模规范,并生成 HTML 报告。
- 生成代码:使用 MATLAB 脚本编译模型并生成对应的编译报告。
- 执行测试用例:对指定模型执行单元测试并生成对应报告。
- 打包工件:生成包含与先前阶段相关的信息的摘要报告。
- 部署:将先前各阶段的所有工件下载到管道中指定的工件路径。
工作流步骤
工作流包括以下步骤(图 4):
- 触发 GitLab 中的管道,并观察 Verify 和 Build 阶段是否通过。
- 检测 GitLab CI 管道中的测试用例失败,并创建一个问题以跟踪和讨论 Bug 修复。
- 在桌面版 MATLAB 中重现该问题。
- 在模型中修复问题。
- 在本地运行测试,确保测试用例通过。
- 评审测试分支上的变更。
- 提交变更至 Git™,并触发 GitLab 中的 CI 管道。
- 在 GitLab 中验证、编译和测试。
- 创建合并请求以将测试分支的变更合并到主分支,并关闭对应的问题。
图 4 左上角显示了我们第一次失败的 CI 循环。它显示了 CI 测试失败、本地重现、标准放宽以及 CI 工作流的成功完成。
工作流详细信息
1. 我们首先通过将变更从 MATLAB 推送到 GitLab 来触发 GitLab 中的管道。模型标准检查和代码生成成功通过。
管道状态可以在工程主页上查看。管道中作业的状态可以通过点击该图标查看。红色符号表示管道失败。
下面是父子管道,显示触发提交的失败。对应的子管道可以在第二列的 Downstream 下展开。
2. 接下来,我们检测 TargetSpeedThrottle 管道内部的失败。子管道 TargetSpeedThrottle 已失败。点击此失败的管道可以查看它。
由于 Testing 阶段失败,其他阶段未执行。点击失败的作业可查看控制台输出。
在观察输出后,我们可以认为 opMode Increment 单元测试用例已失败。点击右侧的 New Issue 按钮可创建新问题。使用此表单可输入描述和其他字段,从而为仓库创建新问题。
创建的问题如下所示,#1 是对应的问题编号。
3. 为了更好地了解失败原因,我们使用 Simulink Test 在本地将其重现。打开位于 Design/TargetSpeedThrottle/pipeline/tests/collection 文件夹中的测试文件 TargetSpeedThrottleTestManager.mldatax,并运行测试用例 opMode Increment。在测试套件中,我们可以看到 Verify Statements 在 opMode Increment 单元测试中失败,如图所示。
4. 为了修复该问题,请打开 Design/TargetSpeedThrottle/specification/TargetSpeedThrottle.slx 模型,并在测试框架 TargetSpeedThrottle_Harness 中导航到 Test Assessments 模块,如图所示。
该评估断言 throtCC 和 exp_throtCC 之间的差异小于 0.1%,如图所示。
该评估对于检查差异小于 0.1% 而言过于严格。必须将此值变更为 0.005 以修复测试。
5. 该问题在我们的仿真中似乎得到了修复。为了确认,我们进行本地测试,既保存模型并在测试管理器中重新运行测试。请注意,它通过了新的评估标准。
6. 我们已修复该问题并在本地验证修复。现在,我们使用模型比较工具来评审变更,然后再将其提交到版本控制。
我们还可以使用模型比较工具的发布功能来评审代码。
7. 修复错误后,我们提交这些变更并将其推送到 GitLab 上的远程仓库(使用 MATLAB 工程),并添加一条提交消息来记录对评估标准的变更。
可以使用特定短语撰写提交消息以自动关闭问题。在此处,当最近的 CI 管道通过时,提交消息 Fixes #1 将自动关闭管道失败时创建的问题。
随后我们注意到最新的变更已提交至 GitLab 仓库。
8. GitLab CI 管道运行。现在验证、编译和测试管道阶段已可通过。
9. 现在我们来创建一条合并请求,将测试分支中的变更合并到主分支中。在 GitLab 中,在 Repository 下,我们可以选择 Branches,然后点击测试分支上最新提交旁边的 Merge request,或使用仓库页顶部出现的 Create merge request 按钮。
我们填写表单并提交合并请求。
作为分支的所有者,可以点击 Merge(合并)按钮接受合并请求。根据我们的 CI 设置,我们还可以在 CI 管道通过后启用自动合并。现在所有变更都已捕获到主分支上,管道自动开始在主分支上运行。
在管道执行后,对应的问题会自动关闭。
在管道中的 Verify、Build 和 Test 阶段执行后,会在 Package 阶段为每个模型生成摘要报告。
使用示例:工具、资源和需求
此示例中使用的工程可以直接在此下载。以下各部分概述了帮助您快速入门的资源,以及所需工具及其配置方式。以下各部分概述了帮助您快速入门的资源,以及所需工具及其配置方式。
配置系统
GitLab 用作版本控制系统和 CI 系统。MATLAB 和 GitLab 必须一起配置。以下教程可提供设置方面的帮助:
所需工具
- GitLab 帐户。使用 GitLab 作为源代码管理系统和 CI。GitLab 还提供云版本。MATLAB 工程包括用于与 GitLab 通信的 Git 接口。
CI 的许可注意事项
如果您计划在大量主机或云上执行 CI,请联系 MathWorks (continuous-integration@mathworks.com) 寻求帮助。注意:转换类产品,如 MATLAB 和 Simulink® Coder 和编译器产品,可能需要客户端访问许可证 (CAL)。
附录 1:配置 MATLAB 工程和 GitLab
步骤 1:配置 MATLAB 工程以使用源代码管理
我们示例中的第一步是配置我们的工程以使用 GitLab 的源代码管理。
- 创建一个名为
MBDExampleWithGitLab的新目录,将示例加载到其中,然后打开 MATLAB 工程MBDExampleWithGitLab.prj。 - 在 GitLab 中,创建将作为远程仓库的新工程。将其命名为
MBDExampleWithGitLab,并记下托管它的 URL。 - 在 MATLAB 中,转换工程以使用源代码控制。在 Project 选项卡上,点击 Use Source Control。
点击 Add Project to Source Control。
4. 点击 Convert。
5. 完成后点击 Open Project。
该工程现已处于本地 Git 源代码管理下。
步骤 2.设置 GitLab Runner
GitLab Runner 是与 GitLab CI/CD 配合使用以在管道中运行作业的应用程序。必须安装、注册并启动 GitLab Runner 才能执行管道。
要安装、注册和启动与您的操作系统对应的 GitLab Runner,请参阅此处提到的步骤(对于此示例,config.toml 中的可选 concurrent 值可以设为“8”)。在继续上述链接中的 Runner 注册之前,请参考以下要点。
- GitLab 仓库可以对单个工程使用特定的 Runner。要为工程创建并注册特定的 Runner,请遵循需求中提到且与正在使用的操作系统对应的步骤。注册期间输入的标记有助于识别将哪个 Runner 分配给 GitLab 中的哪个仓库。在此示例中,标记应设为
testci,因为(当前示例中用于管道定义的).yml 文件将标记设为testci。在注册期间提及执行程序时,可以使用“shell”。这意味着管道在执行期间将使用 shell 环境。 - 成功注册 Runner 后,将显示类似以下内容的消息:
步骤 3.GitLab 个人访问令牌
为 GitLab 仓库创建个人访问令牌。记下生成的个人访问令牌很重要,因为它只能查看一次。为此个人访问令牌创建 CI/CD 管道变量(Key 指变量名称,Value 是实际标记)。在 Key 字段中输入的此变量名称将用作管道定义中作业工件 API 的参数,因此请记下它。(要运行此示例,请将 Key 设置为 CIPROJECTTOKEN。)
步骤 4.配置管道
1. 在 .yml 文件中提及与 Runner 相关的标记。工程文件夹中的 .yml 文件描述 CI 管道的不同阶段。.gitlab-ci.yml 文件引用主管道,当代码推送到仓库时会触发该主管道。文件 .driverSwRequest-gitlab-ci.yml、.cruiseControlMode-gitlab-ci.yml、.targetSpeedThrottle-gitlab-ci.yml 和 .crs_controller-gitlab-ci.yml 引用模型的子管道,并且仅当特定模型发生变更或 gitlab-ci.yml 变更时才触发。打开 .yml 文件并将 tags 字段变更为 testci - 类似于 GitLab Runner 设置的步骤 2。示例如下:
2. 修改工件路径。
验证并修改 .gitlab-ci.yml 中的 ARTIFACTS_DOWNLOAD_PATH 变量。工件在子管道的 Deploy 阶段使用作业工件 API 下载。此变量值用于放置下载工件的路径。
3. 为作业工件 API 指定个人访问令牌。
每个子管道的 .yml 文件(.driverSwRequest-gitlab-ci.yml、.cruiseControlMode-gitlab-ci.yml、.targetSpeedThrottle-gitlab-ci.yml 和 .crs_controller-gitlab-ci.yml)中定义一个 Deploy 阶段,该阶段使用作业工件 API 下载整个子管道的工件。此示例在 API 请求中使用 PRIVATE-TOKEN: $CIPROJECTTOKEN。将 CIPROJECTTOKEN 替换为配置 GitLab 的步骤 3 中使用的 Key 字段名称。
步骤 5:提交变更并将本地仓库推送到 GitLab
1. 在 Project 选项卡上,点击 Remote。
2. 指定 GitLab 中的远程源的 URL。这是托管 GitLab 仓库的 URL。
点击 Validate 以确保与远程仓库的连接成功,然后点击 OK。该工程现已配置为使用 GitLab 推送和拉取变更。
3. 点击 Commit 以执行初始提交。
4. 点击 Push,将所有变更从本地仓库推送到远程 GitLab 仓库。
5. 刷新 GitLab 控制板并查看 MATLAB 工程的内容。
由于在前面的步骤中设置了 GitLab Runner,一旦变更推送到仓库,管道就会开始运行。.gitlab-ci.yml 文件负责启动管道。
步骤 6:创建测试分支
在此步骤中,我们会创建一个测试分支,用于在与主分支合并之前测试和验证变更。
1. 点击 Branches。
展开 Branch and Tag Creation 部分,将分支命名为 Test,然后点击 Create。
2. 现在,在分支浏览器中查看 Test。从 Test 分支依次点击 Switch 和 Close。
3. 将变更推送到 Test 分支。在 MATLAB 中,选择 Push 将这些变更推送到 GitLab,然后在 GitLab 中查看 Test 分支。
有一个主要父管道,其中包含子管道(上图中第一列所示)。有四个触发器(在 Downstream 阶段下显示为四个作业)指示四个子管道。每个子管道用于系统的每个模型,其进度也可以通过展开 Downstream 中的内容来查看。
上面所示的子管道显示系统中 CruiseControlMode 模型的阶段。
2. 子管道中的阶段
- 验证:此处使用 Simulink Check 验证 ISO 26262 的建模标准。
- 构建:这会对模型执行代码生成。
- 测试:这会执行为模型编写的单元测试。
- 打包:显示生成的工件且管道已成功的最终阶段。
- 部署:包含任何代码部署的占位阶段。管道的所有工件都使用作业工件 API 下载。
3. YAML 关键字
此管道结构和作业定义必须在 .yml 文件中创建,这些文件由 Runner 用于执行管道。.gitlab-ci.yml 包含任何工程的 CI/CD 管道的阶段和作业的配置详细信息。以下步骤解释用于构造前面步骤中所述的父子管道的 .yml 文件(本文中使用的示例包含执行管道所需的所有 .yml 文件,但以下步骤简要描述 .yml 文件的内容)。
a.最初,父管道的阶段在 .gitlab-ci.yml 中提及。
b.关键字 trigger 对应于子管道。由于有四个模型,必须编写四个不同作业。以下是其中一个示例:
每个作业都以唯一作业名称开头,后跟其所属的阶段。由于这会调用另一个子管道,因此使用关键字 include 提及子管道的 .yml 文件。关键字 strategy 表示下一个作业在此作业完成之前将不会执行。关键字 rule 表示仅当用户在第 2225 行提到的文件夹路径中进行变更时,才必须触发子管道。
c.四个子管道中的每个管道都有其对应的 .yml 文件。它们还将包含子管道每个阶段下的阶段声明和作业。以下是子管道中其中一个作业的示例。
tags 引用注册 Runner 期间给出的标记。要执行的任何文件/命令都在 script 下提及。artifacts 是在传递给下一个作业之前需要保存的文件。通常,在作业执行期间生成的任何文件,以及对用户后续验证结果有帮助的文件,都会作为工件存储。此处,模型 analyze 文件夹中生成的报告/结果以及日志保存为工件。父管道的其他作业也可以在 gitlab-ci.yml 文件中同样描述。
d.工件在 Deploy 阶段使用作业工件 API 下载。此处 CIPROJECTTOKEN 指之前为个人访问令牌创建的 CI/CD 变量。ARTIFACTS_DOWNLOAD_PATH 在 .gitlab-ci.yml 中定义为变量。请注意,工件也可以在后续步骤中提到的各个作业页中浏览/下载。
4. 工件
a. 可以从仓库页查看管道。
绿色符号表示管道已运行且成功。
b. 点击该符号,我们可以看到该管道中成功的作业。
可以通过点击查看每个作业的进度。
这是打印任何输出语句的控制台。此外,作业的工件可以从右侧部分查看,在那里可以浏览或下载工件。子管道中的每个阶段都会生成工件,直到 Deploy 阶段。
c. 每个子管道的测试结果也可以在每个子管道作业中的 Tests 选项卡下查看。
d. 执行作业时生成的任何报告/结果文件都会存储在每个模型的 analyze 文件夹中。除此之外,在每个子管道结束时(在 Package 阶段)会创建一个摘要报告,其中包含子管道先前阶段的所有结果。
以下是 DriverSwRequest 模型的摘要报告示例:
此报告位于每个模型的 /analyze/package 文件夹中,文件名带有模型名称后跟 SummaryReport。用户可以从每个子管道的 Package 阶段将这些报告作为一个工件下载。
如果子管道的任何阶段(Package 之前)失败,则无法生成摘要报告,因为这仅在 Package 阶段发生。一旦某个阶段失败,控制权不会转至下一阶段。
5. 子管道 - 每个阶段中的作业工件
Cruise Control Project 在各阶段生成以下工件:
- 验证:模型顾问结果报告
- 构建:编译报告,Codegen 文件夹
- 测试:测试报告
- 打包:analyze 文件夹中的所有报告
- 部署:先前阶段的所有工件
如何检查管道是否正确执行
- 工件中生成的摘要报告适合用来验证所有阶段的结果统计信息。
- 管道中的所有作业都必须通过。如果 MATLAB 引发错误,则由于 MATLAB 引发的退出状态码,管道作业将失败。
对于运行 GitLab 管道时出现“error setting certificate verify locations”错误消息的任何问题,请参阅以下内容:
2024 年发布