ROS 2 开发者指南
本页定义了我们在开发 ROS 2 时采用的实践和政策。
一般原则
一些原则适用于所有 ROS 2 开发:
共享所有权:
ROS 2 上的每个人都应该对系统的所有部分拥有所有权。 代码块的原始作者没有任何特殊权限或义务来控制或维护该代码块。 每个人都可以自由地在任何地方提出更改、处理任何类型的票证并审查任何拉取请求。 * 愿意做任何事情: 作为共享所有权的必然结果,每个人都应该愿意承担任何可用的任务并为系统的任何方面做出贡献。 * 寻求帮助: 如果您遇到麻烦,请根据需要通过票证、评论或电子邮件向您的同事寻求帮助。
质量实践
根据`REP 2004:软件包质量类别<https://www.ros.org/reps/rep-2004.html>`_ 中的指南,软件包可以根据其遵循的开发实践归属于不同的质量级别。 这些类别根据其在版本控制、测试、文档等方面的政策进行区分。
以下部分是我们遵循的特定开发规则,以确保核心软件包具有最高质量(“1 级”)。
我们建议所有 ROS 开发人员努力遵守以下政策,以确保整个 ROS 生态系统的质量。
版本控制
我们将使用“语义版本控制指南 <http://semver.org/>`__(“semver”)进行版本控制。
我们还将遵守一些基于“semver”完整含义的 ROS 特定规则:
不应在已发布的 ROS 发行版中进行主要版本增量(即重大更改)。
补丁(保留接口)和次要(非破坏性)版本增量不会破坏兼容性,因此这些类型的更改*是*允许在发行版中进行的。
ROS 的主要版本是发布重大更改的最佳时机。
如果核心包需要多个重大更改,则应将它们合并到其集成分支(例如滚动),以便快速捕获 CI 中的问题,但一起发布以减少 ROS 用户的主要版本数量。
虽然主要增量需要新的发行版,但新的发行版并不一定需要重大升级(如果开发和发布可以在不破坏 API 的情况下进行)。
对于编译代码,ABI 被视为公共接口的一部分。
任何需要重新编译依赖代码的更改都被视为重大(重大)。
ABI 重大更改*可以*在发行版发布*之前*在次要版本升级中进行(添加到滚动版本中)。
尽管`SemVer 的规范 <https://semver.org/#spec-item-4>`_ 关于初始开发,但我们仍强制执行 Dashing 和 Eloquent 中核心包的 API 稳定性,即使它们的主要版本组件为
0
。随后,软件包应努力达到成熟状态并提升至版本“1.0.0”,以符合“semver”的规范。
注意事项
这些规则是*尽力而为*。 在极少数极端情况下,可能需要在主要版本/发行版中破坏 API。 计划外破坏是否会增加主要版本或次要版本将根据具体情况进行评估。
例如,考虑涉及已发布的 X-turtle(对应于主要版本“1.0.0”)和已发布的 Y-turtle(对应于主要版本“2.0.0”)的情况。
如果确定在 X-turtle 中绝对需要修复破坏 API 的问题,则升级到“2.0.0”显然不是一个选择,因为“2.0.0”已经存在。
在这种情况下处理 X-turtle 版本的解决方案(两者都不理想)是:
升级 X-turtle 的次要版本:不理想,因为它违反了 SemVer 的原则,即破坏性更改必须升级主要版本。
将 X-turtle 的主要版本提升至 Y-turtle 之上(至
3.0.0
):这是不理想的,因为旧发行版的版本会高于新发行版的现有版本,这会使特定于版本的条件代码无效/中断。
开发人员必须决定使用哪种解决方案,或者更重要的是,他们愿意打破哪条原则。
我们不能建议其中一种,但无论哪种情况,我们都要求采取明确措施手动向用户传达中断及其解释(不仅仅是版本增量)。
如果没有 Y-turtle,即使修复在技术上只是一个补丁,X-turtle 也必须升级到 2.0.0
。
这种情况符合 SemVer,但违反了我们自己的规则,即不应在已发布的发行版中引入主要增量。
这就是我们认为版本控制规则*尽力而为*的原因。 尽管上述示例不太可能发生,但准确定义我们的版本控制系统非常重要。
公共 API 声明
根据“semver”,每个包都必须明确声明一个公共 API。 我们将使用包质量声明的“公共 API 声明”部分来声明哪些符号是公共 API 的一部分。 对于大多数 C 和 C++ 包,声明是它安装的任何标头。 但是,定义一组被视为私有的符号是可以接受的。 避免在标头中使用私有符号有助于 ABI 稳定性,但这不是必需的。 对于 Python 等其他语言,必须明确定义公共 API,以便明确根据版本控制指南可以依赖哪些符号。 公共 API 还可以扩展以构建配置变量、CMake 配置文件等工件,以及可执行文件和命令行选项和输出。 公共 API 的任何元素都应在包的文档中明确说明。 如果您正在使用的东西没有在包的文档中明确列为公共 API 的一部分,那么您不能依赖它在次要版本或补丁版本之间不会发生变化。 弃用策略 ~~~~~~~~~~~~~~~~~~~~~~
在可能的情况下,我们还将使用 tick-tock 弃用和迁移策略来增加主要版本。 新的弃用将出现在新的发行版本中,并伴有编译器警告,表示该功能已被弃用。 在下一个版本中,该功能将被完全删除(无警告)。
弃用函数“foo”并由函数“bar”替换的示例:
Version |
API |
---|---|
X-turtle |
void foo(); |
Y-turtle |
[[deprecated(“use bar()”)]] void foo(); <br> void bar(); |
Z-turtle |
void bar(); |
我们决不能在发行版发布后添加弃用。 不过,弃用并不一定需要主要版本升级。 如果升级发生在发行版发布之前(类似于 ABI 重大更改),则可以在次要版本升级中引入弃用。
例如,如果 X-turtle 以“2.0.0”开始开发,则可以在 X-turtle 发布之前在“2.1.0”中添加弃用。
我们将尽可能地尝试保持发行版之间的兼容性。 但是,与与 SemVer 相关的警告一样,在某些情况下,可能无法完全遵守 tick-tock 甚至弃用。
变更控制流程
所有更改都必须通过拉取请求。
我们将在 ROSCore 存储库的拉取请求中强制执行`开发者原产地证书 (DCO) <https://developercertificate.org/>`_。
它要求所有提交消息都包含``Signed-off-by`` 行,其中包含与提交作者匹配的电子邮件地址。
您可以将``-s`` /
--signoff
传递给``git commit`` 调用,或手动编写预期消息(例如``Signed-off-by:您的姓名开发者<your.name@example.com>``)。对于仅解决空格删除、拼写错误更正和其他``琐碎更改<http://cr.openjdk.java.net/~jrose/draft/trivial-fixes.html>`_ 的拉取请求,DCO 不是必需的。
始终为每个拉取请求运行所有 tier 1 平台 的 CI 作业,并在拉取请求中包含作业链接。
(如果您无权访问 Jenkins 作业,则有人会为您触发作业。)
需要至少 1 位未撰写拉取请求的开发人员批准才能将其视为已批准。
合并前需要批准。
软件包可以选择增加此数字。
必须在合并相关更改之前提出对文档(API 文档、功能文档、发行说明等)的任何必要更改。
反向移植 PR 的指南
更改旧版本的 ROS 时:
在打开 PR 以将更改反向移植到旧版本之前,请确保滚动分支中已接受并合并了功能或修复。
反向移植到旧版本时,还请考虑反向移植到任何其他 仍受支持的版本,甚至非 LTS 版本。
如果您要反向移植整个单个 PR,请将反向移植 PR 命名为“[Distro] <原始 PR 的名称>”。
如果从一个或多个 PR 反向移植一部分更改,则标题应为“[Distro] <更改说明>”。 * 从反向移植 PR 的说明中链接到您要反向移植其更改的所有 PR。 在 Foxy 更改的 Dashing 反向移植中,您无需链接到相同更改的 Eloquent 反向移植。
文档
所有软件包的 README 中都应包含这些文档元素,或者从其 README 中链接到这些文档元素:
描述和目的
公共 API 的定义和描述
示例
如何构建和安装(应引用外部工具/工作流)
如何构建和运行测试
如何构建文档
如何开发(用于描述“python setup.py evolve”之类的内容)
许可和版权声明
每个源文件都必须具有许可和版权声明,并使用自动 linter 检查。
每个软件包都必须有一个 LICENSE 文件,通常是 Apache 2.0 许可,除非软件包具有现有的宽松许可(例如,rviz 使用三条款 BSD)。
每个软件包都应描述自身及其用途,尽可能假设读者是在不了解 ROS 或其他相关项目的情况下偶然发现它的。
每个包都应该定义并描述其公共 API,以便用户对语义版本控制策略所涵盖的内容有合理的期望。 即使在 C 和 C++ 中,公共 API 可以通过 API 和 ABI 检查来强制执行,这是一个很好的机会来描述代码的布局和代码每个部分的功能。
应该很容易获取任何包,并从该包的文档中了解如何构建、运行、构建和运行测试以及构建文档。 显然,我们应该避免重复常见的工作流程,例如在工作区中构建包,但应该描述或引用基本工作流程。
最后,它应该包括任何开发人员文档。 这可能包括使用“python setup.py evolve”之类的东西测试代码的工作流程,或者它可能意味着描述如何使用包提供的扩展点。
示例:
capabilities: https://docs.ros.org/hydro/api/capabilities/html/
这个给出了描述公共 API 的文档示例
catkin_tools: https://catkin-tools.readthedocs.org/en/latest/development/extending_the_catkin_command.html
这是描述包的扩展点的示例
ROS 软件包的 API 文档
所有已发布的 ROS 软件包的 API 文档都可以在此处找到 <https://docs.ros.org/en/rolling/p/>`__。
我们建议使用 index.ros.org 搜索可用的 ROS 软件包以查找其文档。
如果您是 ROS 软件包开发人员,正在寻找有关编写软件包文档的指导,请参阅 我们的软件包级别文档“操作方法”指南。
所有已发布的 ROS 2 软件包的文档都会自动托管在 docs.ros.org 上。
测试
所有软件包都应具有一定程度的 系统、集成和/或单元测试。
单元测试 应始终位于正在测试的软件包中,并应使用“Mock”等工具尝试在构造的场景中测试代码库的狭窄部分。
单元测试不应引入非测试工具的测试依赖项,例如 gtest、nosetest、pytest、mock 等…
集成测试 可以测试代码各部分之间或代码各部分与系统之间的交互。
它们通常以我们期望用户使用的方式测试软件接口。
与单元测试一样,集成测试应位于正在测试的软件包中,除非绝对必要,否则不应引入非工具测试依赖项,即所有非工具依赖项都应仅在经过严格审查的情况下才允许,因此应尽可能避免使用它们。
**系统测试**旨在测试包之间的端到端情况,并且应将其放在自己的包中,以避免包膨胀或耦合,并避免循环依赖。
通常,应尽量减少外部或跨包测试依赖,以防止循环依赖和紧密耦合的测试包。
所有包都应该有一些单元测试和可能的集成测试,但它们应该拥有的程度取决于包的质量类别。
以下小节适用于“1 级”包:
代码覆盖率
我们将提供行覆盖率,并实现 95% 以上的行覆盖率。 如果有理由降低百分比目标,则必须对其进行突出记录。 我们可能会提供分支覆盖率,或从覆盖率中排除代码(测试代码、调试代码等)。 我们要求在合并更改之前覆盖率增加或保持不变,但如果有适当的理由,进行减少代码覆盖率的更改也是可以接受的(例如,删除之前覆盖的代码可能会导致百分比下降)。
性能
我们强烈建议进行性能测试,但认识到它们对某些软件包没有意义。 如果有性能测试,我们将选择检查每个更改或在每个版本之前或两者。 我们还需要合并更改或发布降低性能的版本的理由。
Linters 和静态分析
我们将使用 ROS 代码样式 并使用来自 ament_lint_common 的 linters 强制执行它。
必须使用属于 ament_lint_common
的所有 linters/静态分析。
ament_lint_auto 文档提供有关运行 ament_lint_common
的信息。
一般做法
有些做法对所有 ROS 2 开发都是通用的。
这些做法不会影响 REP 2004 中所述的软件包质量水平,但仍强烈建议在开发过程中使用。
问题
提交问题时,请确保:
包含足够的信息,以便其他人了解问题。
在 ROS 2 中,需要以下几点来缩小问题的原因。 在每个类别中使用尽可能多的替代方案进行测试将特别有帮助。
操作系统和版本。
理由:ROS 2 支持多个平台,并且某些错误特定于特定版本的操作系统/编译器。 - 安装方法。 理由:某些问题仅在从二进制存档或 debs 安装 ROS 2 时才会出现。 这可以帮助我们确定问题是否与打包过程有关。 - ROS 2 的特定版本。 理由:某些错误可能存在于特定的 ROS 2 版本中,后来得到修复。 了解您的安装是否包含这些修复非常重要。 - 正在使用的 DDS/RMW 实现**(请参阅`此页面 <../../Concepts/Intermediate/About-Different-Middleware-Vendors>` 以了解如何确定哪一个)。 推理:通信问题可能特定于正在使用的底层 ROS 中间件。 - **正在使用的 ROS 2 客户端库。 推理:这有助于我们缩小问题可能出现的堆栈层。
包括重现问题的步骤列表。
如果出现错误,请考虑提供`简短、独立、正确(可编译)的示例 <http://sscce.org/>`__。
如果其他人可以轻松重现问题,则更有可能解决问题。
提及已经尝试过的故障排除步骤,包括:
升级到最新版本的代码,其中可能包括尚未发布的错误修复。
请参阅“本节 <building-from-source>”并按照说明获取“滚动”分支。 - 尝试使用不同的 RMW 实现。 请参阅“此页面 <../../How-To-Guides/Working-with-multiple-RMW-implementations>”了解如何执行此操作。
分支
Note
这些只是指导原则。 软件包维护者可以选择符合其自身工作流程的分支名称。
最好在软件包的源存储库中为其所针对的每个 ROS 发行版设置 单独的分支。 这些分支通常以其所针对的发行版命名。 例如,专门针对 Humble 发行版的开发的“humble”分支。
发布也从这些分支进行,针对适当的发行版。 针对特定 ROS 发行版的开发可以在适当的分支上进行。 例如:针对“foxy”的开发提交到“foxy”分支,并且“foxy”的软件包发布从同一分支进行。
Note
这要求软件包维护人员根据需要执行反向移植或前向移植,以使所有分支都具有最新的功能。
维护人员还必须在仍发布软件包的所有分支上执行常规维护(错误修复等)。
例如,如果某个功能已合并到 Rolling 特定分支(例如“rolling”或“main”)中,并且该功能也适用于 Humble 发行版(不会破坏 API 等),那么将该功能反向移植到 Humble 特定分支是一种很好的做法。
如果有新功能或错误修复可用,维护人员可能会为那些较旧的发行版发布版本。
What about main
and rolling
?
main
通常以 Rolling 为目标(因此,下一个未发布的 ROS 发行版),尽管维护人员可能决定从 rolling
分支进行开发和发布。
拉取请求
拉取请求应仅关注一项更改。
单独的更改应放入单独的拉取请求中。 请参阅 GitHub 编写完美拉取请求指南。
补丁应尽量小,并避免任何不必要的更改。
拉取请求必须包含最少数量的有意义的提交。
您可以在拉取请求审核期间创建新的提交。
在合并拉取请求之前,应将所有更改压缩为少量语义提交,以保持历史记录清晰。
但应避免在拉取请求审核期间压缩提交。
您的审阅者可能不会注意到您进行了更改,从而可能造成混淆。 另外,无论如何您都要在合并之前压缩;过早执行此操作没有任何好处。
欢迎任何开发人员审阅和批准拉取请求(请参阅 一般原则)。
当您正在处理尚未准备好进行审查或合并的更改时,请使用草稿拉取请求。
当该更改准备好进行审查时,将拉取请求移出草稿状态。 请注意,如果您希望从特定人员那里获得有关草稿拉取请求的早期反馈,您可以在拉取请求的描述或拉取请求的评论中@提及他们。
如果您的拉取请求依赖于其他拉取请求,请在拉取请求描述的顶部添加“- 依赖于 <link>”以链接到每个依赖的拉取请求。
这样做有助于审阅者了解拉取请求的上下文。
当您开始审阅拉取请求时,请在拉取请求上发表评论,以便其他开发人员知道您正在审阅它。
拉取请求审阅不是只读的,审阅者发表评论,然后等待作者解决。
作为审阅者,可以随意就地进行细微改进(拼写错误、样式问题等)。 作为拉取请求的发起者,如果您正在 fork 中工作,请选中“允许上游贡献者进行编辑 <https://github.com/blog/2247-improving-collaboration-with-forks>”复选框将有助于上述操作。 作为审阅者,也可以自由地进行更实质性的改进,但请考虑将它们放在单独的分支中(在评论中提及新分支,或从新分支向原始分支打开另一个拉取请求)。
任何开发人员(作者、审阅者或其他人)都可以合并任何已批准的拉取请求。
库版本控制
我们将对包中的所有库进行版本控制。 这意味着库从包中继承其版本。 这可以防止库和包版本出现分歧,并与发布共享存储库的包的策略相同。 如果您需要库具有不同的版本,请考虑将它们拆分为不同的包。
开发过程
默认分支(大多数情况下为滚动分支)必须始终构建、通过所有测试并在无警告的情况下进行编译。
如果任何时候出现回归,则首要任务是至少恢复到之前的状态。 * 始终在启用测试的情况下构建。 * 始终在更改后和在拉取请求中提出更改之前在本地运行测试。 除了使用自动测试外,还要手动运行修改后的代码路径,以确保补丁按预期工作。 * 始终为每个拉取请求运行所有平台的 CI 作业,并在拉取请求中包含指向作业的链接。
有关推荐的软件开发工作流程的更多详细信息,请参阅“软件开发生命周期”部分。
RMW API 的更改
更新 RMW API 时,也需要更新 Tier 1 中间件库的 RMW 实现。 例如,必须在以下软件包中实现 RMW API 中引入的新函数 ``rmw_foo()``(从 ROS Galactic 开始):
如果可行,还应考虑更新非 Tier 1 中间件库(例如,取决于更改的大小)。 请参阅 REP-2000 了解中间件库及其层级的列表。
跟踪任务
为了帮助组织 ROS 2 的工作,核心 ROS 2 开发团队使用看板式 GitHub 项目板。
但是,并非所有问题和拉取请求都会在项目板上跟踪。 板通常代表即将发布的版本或特定项目。 可以通过浏览 ROS 2 存储库’ 单个问题页面,按每个存储库浏览票证。
任何给定的 ROS 2 项目板中的列的名称和用途各不相同,但通常遵循相同的一般结构:
待办事项:
与项目相关的问题,准备分配 * 进行中: 当前正在进行的工作的活跃拉取请求 * 审核中: 工作已完成并准备审核的拉取请求,以及当前正在积极审核的拉取请求 * 完成: 拉取请求和相关问题已合并/关闭(仅供参考)
要请求进行更改的权限,只需对您感兴趣的票证进行评论即可。
根据复杂程度,描述您计划如何解决它可能会很有用。 我们将更新状态(如果您没有权限),您可以开始处理拉取请求。 如果您定期做出贡献,我们可能会授予您自己管理标签等的权限。
编程约定
防御性编程:确保尽早做出假设。
例如,检查每个返回代码并确保至少抛出一个异常,直到情况得到更妥善的处理。
* 所有错误消息都必须指向 stderr
。
* 在尽可能窄的范围内声明变量。
* 保持项目组(依赖项、导入、包含等)按字母顺序排列。
C++ 特定
避免使用直接流式传输(“<<”)到
stdout
/stderr
,以防止多个线程之间交错。避免使用
std::shared_ptr
的引用,因为这会破坏引用计数。
如果原始实例超出范围并且引用正在使用,它将访问已释放的内存。
文件系统布局
软件包和存储库的文件系统布局应遵循相同的约定,以便为浏览我们源代码的用户提供一致的体验。
软件包布局
src
:包含所有 C 和 C++ 代码还包含未安装的 C/C++ 标头
include
:包含所有已安装的 C 和 C++ 标头<package name>
:对于所有已安装的 C 和 C++ 标头,它们应按包名称命名文件夹<package_name>
:包含所有 Python 代码test
:包含所有自动化测试和测试数据config
:包含配置文件,例如YAML 参数文件和 RViz 配置文件doc
:包含所有文档launch
:包含所有启动文件msg
:包含所有 ROS 消息定义srv
:包含所有 ROS 服务定义action
:包含所有 ROS 操作定义package.xml
:由 REP-0140 定义(可能会更新以用于原型设计)CMakeLists.txt
:仅使用 CMake 的 ROS 包setup.py
:仅使用 Python 代码的 ROS 包README
:可以在 GitHub 上呈现为项目的登录页面这可以尽可能简短或详细,但至少应该链接到项目文档
考虑在此 README 中放置 CI 或代码覆盖率标签
也可以``.rst`` 或 GitHub 支持的任何其他内容
CONTRIBUTING
:描述贡献指南这可能包括许可证含义,例如使用 Apache 2 许可证时。
LICENSE
:此软件包的许可证副本CHANGELOG.rst
:REP-0132 兼容变更日志
存储库布局
每个包都应位于与包同名的子文件夹中。
如果存储库仅包含单个包,则可以选择将其放在存储库的根目录中。
上游包
Debian 和 Ubuntu 上游中的包
感谢 Jochen Sprickerhof 和 Leopold Palomo-Avellaneda 的辛勤努力,一些 ROS 2 包现已从主 Debian 和 Ubuntu 存储库中提供。 以下是 Jochen 在 ROSCon 2015 上对该过程的简要概述。 原始 ROS 软件包已根据 Debian 指南进行了修改,包括将软件包拆分为多个部分、在某些情况下更改名称、根据 FHS 指南安装到 /usr 以及在共享库上使用版本。
此外,一些引导依赖项(例如命令行工具,如“vcstool”和“colcon”)以及一些库(如“osrf-pycommon”和“ament”)也已打包到上游。
与 http://packages.ros.org 中 OSRF 提供的 ROS 软件包不同,上游存储库中的软件包未附加到特定的 ROS 发行版。 相反,它们代表时间快照,将在 Debian 不稳定版本中定期更新,然后在下游 Debian 和 Ubuntu 发行版的各个点锁定。
不要混合流
我们强烈建议不要在同一系统上混合来自上游 Debian/Ubuntu 和 http://packages.ros.org 的 ROS 包。 在某些情况下,这种混合系统可以正常工作,但两组包之间可能会产生负面相互作用。 我们正在与 Jochen 和朋友们合作,通过文档和包冲突规范将出现问题的可能性降至最低,但我们预计仍会存在一些风险,包括一些相当微妙的问题。
因此,我们建议您选择从上游或 http://packages.ros.org 安装包,但不要同时安装两者。 您不仅不应该同时安装来自两者的包,而且如果您打算使用上游包,那么您甚至不应该在您的 apt 源(即“/etc/apt/sources*”中的任何文件中)中包含 http://packages.ros.org 条目。 同时启用它们可能会导致两个源之间名称重叠的包混合,例如“python3-rospkg”。
已知差异
与 packages.ros.org 中的 ROS 软件包相比,上游 ROS 软件包中存在一些差异,人们应该注意:
软件包集不完整。
软件包可能具有不同的名称,并且分区方式也不同。
开发人员工作流程
我们使用 GitHub 项目板 跟踪与即将发布的版本和大型项目相关的未结票据和有效 PR。
通常的工作流程是:
讨论设计(GitHub 上相应存储库的票据,以及设计 PR 到 https://github.com/ros2/design(如果需要))
在 fork 上的功能分支上编写实现
请查看`开发者指南 <Developer-Guide>` 了解指南和最佳实践
编写测试
启用并运行 linters
使用
colcon test
在本地运行测试(请参阅 colcon 教程)一旦所有内容在本地构建且没有警告并且所有测试都通过,请在您的功能分支上运行 CI:
转到 ci.ros2.org
登录(右上角)
单击
ci_launcher
作业单击“使用参数构建”(左栏)
在第一个框“CI_BRANCH_TO_TEST”中输入您的功能分支名称
点击``build``按钮
(如果您不是 ROS 2 提交者,则无权访问 CI 农场。在这种情况下,请 ping 您的 PR 的审阅者以为您运行 CI)
如果您的用例需要运行代码覆盖率:
转到 ci.ros2.org
登录(右上角)
单击
ci_linux_coverage
作业单击“使用参数构建”(左栏)
确保将“CI_BUILD_ARGS”和“CI_TEST_ARGS”保留为默认值
点击
build
按钮如果 CI 作业构建时没有警告、错误和测试失败,请在您的 PR 或高级票证上发布作业链接,汇总所有 PR (参见`此处 <https://github.com/ros2/rcl/pull/106#issuecomment-271119200>`__ 的示例)
请注意,这些徽章的标记位于
ci_launcher
作业的控制台输出中PR 获得批准后:
提交 PR 的人使用“压缩并合并”选项将其合并,以便我们保持干净的历史记录
如果提交值得分开:将所有挑剔/linters/错别字压缩在一起并合并剩余的集合
注意:每个 PR 都应针对一个特定功能,因此 99% 的时间压缩并合并都应该有意义
合并后删除分支
架构开发实践
本节介绍对 ROS 2 进行大型架构更改时应采用的理想生命周期。
软件开发生命周期
本节逐步介绍如何规划、设计和实现新功能:
创建任务
创建设计文档
设计评审
实施
代码评审
任务创建
需要更改 ROS 2 关键部分的任务应在发布周期的早期阶段进行设计评审。
如果在后期阶段进行设计评审,则更改将成为未来版本的一部分。
编写设计文档
设计文档绝不能包含机密信息。 您的更改是否需要设计文档取决于任务的大小。
您正在进行小改动或修复错误:
不需要设计文档,但应在适当的存储库中打开问题以跟踪工作并避免重复工作。
您正在实现新功能或希望为 OSRF 拥有的基础设施(如 Jenkins CI)做出贡献:
设计文档是必需的,应将其贡献给 ros2/design 以便在 https://design.ros2.org/ 上访问。
您应该分叉存储库并提交详细说明设计的拉取请求。
在拉取请求或提交消息中提及相关的 ros2 问题(例如,任务 ros2/ros2#<issue id> 的设计文档
)。
详细说明请参阅 ROS 2 Contribute 页面。
设计评论将直接在拉取请求上进行。
如果计划使用特定版本的 ROS 发布该任务,则应将此信息包含在拉取请求中。
设计文档审查
一旦设计准备好进行审查,就应该打开拉取请求并指定适当的审阅者。 建议包括项目所有者 - 所有受影响软件包的维护者(由``package.xml``维护者字段定义,请参阅`REP-140 <https://www.ros.org/reps/rep-0140.html#maintainer-multiple-but-at-least-one>`__) - 作为审阅者。
如果设计文档很复杂或审阅者的日程安排有冲突,则可以安排可选的设计审查会议。
在这种情况下,
会议前
至少提前一周发送会议邀请
建议会议时长为一小时
会议邀请应列出审查期间要做出的所有决定(需要软件包维护者批准的决定)
会议必需参加者:设计拉取请求审查者
会议可选参加者:所有 OSRF 工程师(如果适用)
会议期间
任务负责人主持会议,提出自己的想法并管理讨论,以确保按时达成协议
会议结束后
任务所有者应将会议记录发回给所有与会者
如果设计中出现了小问题:
任务所有者应根据反馈更新设计文档拉取请求
无需额外审核
如果设计中出现了大问题:
可以删除没有明确一致的部分
设计中有争议的部分可以在将来作为单独的任务重新提交
如果无法删除有争议的部分,请直接与包所有者合作达成协议
达成共识后:
确保 ros2/design 拉取请求已合并(如果适用)
更新并关闭与此设计任务相关的 GitHub 问题
实施
开始之前,请先阅读 `Pull 请求`_ 部分以了解最佳实践。
对于要修改的每个存储库:
修改代码,如果完成或定期备份您的工作,请转到下一步。
使用
git add -i```
自我审查 <https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging>`__ 您的更改。使用
git commit -s`
创建新的签名提交。拉取请求应包含最少的语义上有意义的提交(例如,不接受大量的 1 行提交)。
在迭代反馈时创建新的修复提交,或者,如果您不想每次都创建新提交,则可选择使用
git commit --amend
修改现有提交。每个提交都必须有一个正确编写的、有意义的提交消息。
更多说明请参见`此处 <https://chris.beams.io/posts/git-commit/>`__。 * 移动文件必须在单独的提交中完成,否则 git 可能无法准确跟踪文件历史记录。 * 拉取请求描述或提交消息必须包含对相关 ros2 问题的引用,以便在合并拉取请求时自动关闭。 有关更多详细信息,请参阅此`doc <https://help.github.com/articles/closing-issues-using-keywords/>`__。 * 推送新的提交。
代码审查
更改准备好进行代码审查后:
为每个修改的存储库打开一个拉取请求。
请记住遵循`拉取请求`_最佳实践。
`GitHub <https://hub.github.com/>`__可用于从命令行创建拉取请求。
如果计划使用特定版本的 ROS 发布任务,则每个拉取请求中都应包含此信息。
应在拉取请求中提及审阅设计文档的软件包所有者。
代码审查 SLO:尽管审查拉取请求是尽最大努力,
但让审阅者在一周内对拉取请求发表评论, 让代码作者在一周内回复评论会很有帮助,这样就不会丢失上下文。 * 像往常一样迭代反馈,根据需要修改和更新开发分支。 * 一旦 PR 获得批准,软件包维护者将合并更改。
构建农场简介
构建农场位于 ci.ros2.org。
每天晚上,我们都会运行夜间作业,在各种平台上构建和运行各种场景中的所有测试。
此外,我们会在合并之前针对这些平台测试所有拉取请求。
这是当前的目标平台和架构集,但它会随着时间的推移而发展:
Ubuntu 24.04 Noble
amd64
aarch64
Windows 10
amd64
buildfarm 上有几类作业:
手动作业(由开发人员手动触发):
ci_linux:在 Ubuntu 上构建 + 测试代码
ci_linux-aarch64:在 ARM 64 位机器(aarch64)上的 Ubuntu 上构建 + 测试代码
ci_linux_coverage:构建 + 测试 + 生成测试覆盖率
ci_windows:在 Windows 上构建 + 测试代码
ci_launcher:触发上面列出的所有作业
nightly(每晚运行):
Debug:使用 CMAKE_BUILD_TYPE=Debug 构建 + 测试代码
nightly_linux_debug
nightly_linux-aarch64_debug
nightly_win_deb
发布:使用 CMAKE_BUILD_TYPE=Release 构建 + 测试代码
nightly_linux_release
nightly_linux-aarch64_release
nightly_win_rel
重复:构建然后运行每个测试最多 20 次或直到失败(又名不稳定猎人)
nightly_linux_repeated
nightly_linux-aarch64_repeated
nightly_win_rep
覆盖率:
nightly_linux_coverage:构建 + 测试代码 + 分析 c/c++ 和 python 的覆盖率
结果导出为 cobertura 报告
打包(每晚运行;结果捆绑到存档中):
packaging_linux
packaging_windows
另外两个构建农场通过提供源代码和二进制包的构建、持续集成、测试和分析来支持 ROS / ROS 2 生态系统。
有关详细信息、常见问题和故障排除,请参阅:doc:build farms。
关于覆盖率运行的说明
ROS 2 包的组织方式是,给定包的测试代码不仅包含在包中,还可以存在于不同的包中。 换句话说:包可以在测试阶段执行属于其他包的代码。
为了实现 ROS 2 核心包中所有可用代码的覆盖率,建议使用一组固定的建议存储库运行构建。 该集合在 Jenkins 中覆盖率作业的默认参数中定义。
如何从 buildfarm 报告中读取覆盖率
要查看给定包的覆盖率报告:
当
ci_linux_coverage
构建完成后,单击覆盖率报告
向下滚动到
按包划分的覆盖率
表在表中,查看名为“名称”的第一列
buildfarm 中的覆盖率报告包括 ROS 工作区中使用的所有包。 覆盖率报告包含与同一包相对应的不同路径:
以以下形式命名的条目:
src.*.<repository_name>.<package_name>.*
这些对应于包中针对其自身源代码的单元测试运行
* 以以下形式命名的条目:build.<repository_name>.<package_name>.*
这些对应于包中针对其在构建或配置时生成的文件的单元测试运行
* 以以下形式命名的条目:install.<package_name>.*
这些对应于来自其他包的测试运行的系统/集成测试
如何从 buildfarm 报告中计算覆盖率
使用自动脚本获取组合单元覆盖率:
从 ci_linux_coverage Jenkins 构建中复制构建的 URL
下载 get_coverage_ros2_pkg 脚本
执行脚本:
./get_coverage_ros2_pkg.py <jenkins_build_url> <ros2_package_name>
(README)从脚本输出中的“组合单元测试”最后一行获取结果
替代方案:从覆盖率报告中获取组合单元覆盖率(需要手动计算):
当 ci_linux_coverage 构建完成后,单击“Cobertura 覆盖率报告”
向下滚动到“覆盖率细分”包`` 表
在表中,在第一列“名称”下查找(其中 <package_name> 是您正在测试的包):
模式“src.*.<repository_name>.<package_name>.*`` 下的所有目录获取“行数”列中的两个绝对值。
模式“build/.<repository_name>.*`` 下的所有目录获取“行数”列中的两个绝对值。
使用前面的选择:对于每个单元格,第一个值是测试的行数,第二个值是代码行数的总数。
汇总所有行以获得测试的行数总数和正在测试的代码行数的总数。 除以得到覆盖率。
如何使用 lcov 在本地测量覆盖率 (Ubuntu)
要在您自己的机器上测量覆盖率,请安装“lcov”。
sudo apt install -y lcov
本节的其余部分假设您正在 colcon 工作区中工作。 使用覆盖标志在调试中进行编译。 请随意使用 colcon 标志来定位特定包。
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} --coverage" -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS} --coverage"
“lcov” 需要一个初始基线,您可以使用以下命令生成该基线。 根据您的需要更新输出文件位置。
lcov --no-external --capture --initial --directory . --output-file ~/ros2_base.info
对与覆盖率测量相关的软件包运行测试。 例如,如果测量“rclcpp”,也使用“test_rclcpp”
colcon test --packages-select rclcpp test_rclcpp
使用类似的命令捕获 lcov 结果,这次删除“–initial”标志。
lcov --no-external --capture --directory . --output-file ~/ros2.info
合并跟踪 .info 文件:
lcov --add-tracefile ~/ros2_base.info --add-tracefile ~/ros2.info --output-file ~/ros2_coverage.info
生成 html 以便于可视化和注释覆盖的线条。
mkdir -p coverage
genhtml ~/ros2_coverage.info --output-directory coverage