RuboCop 规则开发指南
我们的代码库风格由 RuboCop 定义并强制执行。
你可以使用 bundle exec rubocop --parallel 在本地检查任何违规行为。
在 CI 上,这由 static-analysis 作业自动检查。
此外,你可以使用 Solargraph gem 将 RuboCop 集成到 支持的 IDE 中。
对于我们尚未做出决定的 RuboCop 规则,请遵循 Ruby style guide 来编写地道的 Ruby 代码。
审查者/维护者应该宽容,不要过于拘泥于风格。
一些 RuboCop 规则被禁用了,对于这些规则,审查者/维护者不能要求作者使用某种风格,因为两种风格都被接受。这不是一个理想的情况,因为这为 bike-shedding 留下了空间。理想情况下,我们应该启用所有 RuboCop 规则,以避免审查中的风格相关讨论、吹毛求疵或来回争论。GitLab Ruby style guide 包含一个非详尽列表,列出了在审查中经常出现且未强制执行的风格。
此外,我们有专门的 测试特定的风格指南和最佳实践。
内联禁用规则
默认情况下,RuboCop 规则不应 内联禁用,因为这会否定规则试图应用于代码库的商定的代码标准。
如果必须使用内联禁用,请在禁用规则的同一行中以代码注释的形式提供原因。
更多上下文可以放在此内联禁用注释上方的代码注释中。为了减少冗长的代码注释,可以链接一个资源(问题、史诗等)来提供详细上下文。
对于临时内联禁用,使用 rubocop:todo 并链接后续问题或史诗。
例如:
# 不好的示例
module Types
module Domain
# rubocop:disable Graphql/AuthorizeTypes
class SomeType < BaseObject
if condition # rubocop:disable Style/GuardClause
# 更多逻辑...
end
object.public_send(action) # rubocop:disable GitlabSecurity/PublicSend
end
# rubocop:enable Graphql/AuthorizeTypes
end
end
# 好的示例
module Types
module Domain
# rubocop:disable Graphql/AuthorizeTypes -- 父实体中已授权
class SomeType < BaseObject
if condition # rubocop:todo Style/GuardClause -- 通过 https://gitlab.com/gitlab-org/gitlab/-/issues/1234567890 清理
# 更多逻辑...
end
# 在这一点上,`action` 可以安全地用于 `public_send`。
# 参见 https://gitlab.com/gitlab-org/gitlab/-/issues/123457890。
object.public_send(action) # rubocop:disable GitlabSecurity/PublicSend -- 用户输入已验证
end
# rubocop:enable Graphql/AuthorizeTypes
end
end创建新的 RuboCop cops
通常,通过程序化方式强制执行 linting 规则更好,因为这可以减少上述 bike-shedding。
为此,我们鼓励在代码库中创建新的 RuboCop 规则。
在添加新的 cop 来强制执行特定风格之前,请确保与你的团队讨论。
我们在多个 Ruby 代码库中维护 cops,但并非所有都特定于 GitLab 应用程序。
当创建可以应用于多个应用程序的新 cop 时,我们鼓励你将其添加到我们的 gitlab-styles gem 中。
如果 cop 针对仅适用于主 GitLab 应用程序的规则,则应将其添加到 GitLab 中。
Cop 宽限期
如果某个 cop 已启用且在其 TODO YAML 配置中定义了 Details: grace period,则它处于 宽限期。
在默认分支上,来自 宽限期 中 cops 的违规行为不会导致 RuboCop CI 作业失败。相反,该作业会通知 #f_rubocop Slack 频道。然而,在其他分支上,RuboCop 作业会失败。
一旦在 #f_rubocop Slack 频道中连续 1 周没有警告,就可以安全地解除宽限期。
当 生成 TODOs 时,RuboCop cop 规则在以下条件下被置于宽限期:
- 该规则之前处于宽限期
- 该规则是新添加的
- 自上次生成以来,该规则的违规数量有所增加
提出新 cop 或 cop 更改
如果你想提出强制执行新 cop 或更改现有 cop 配置的提案,请使用 gitlab-styles merge request template 或 gitlab merge request template,具体取决于你想添加此规则的位置。使用此模板鼓励所有维护者就我们偏好的风格提供反馈,并提供一种结构化的方式来传达新规则的后果。
启用新的 cop
- 在
.rubocop.yml中启用新的 cop(如果尚未通过gitlab-styles完成)。 - 为新 cop 生成 TODOs。
- 创建一个问题来修复 TODOs 并鼓励社区贡献(通过 ~“quick win” 和/或 ~“Seeking community contributions”)。查看一些示例。
- 创建一个问题,在
#f_rubocopSlack 频道中沉默 1 周后移除grace period。查看示例。
静默的违规行为
当 宽限期 中 cops 的违规行为被静默时,#f_rubocop Slack 频道每 2 小时会收到一条通知消息。
要解决此问题:
- 在链接的 CI 作业中查找有静默违规行为的 cops。
- 为这些 cops 生成 TODOs。
RuboCop node pattern
在创建匹配 Ruby AST 的 node patterns 时,你可以使用 scripts/rubocop-parse。这会显示 Ruby 表达式的 AST,帮助你创建匹配器。另请参见 !97024。
解决 RuboCop 异常
当 RuboCop 异常数量超过默认的 exclude-limit of 15 时,我们可能希望分多个提交来解决异常。为了最小化混乱,我们应该通过异常列表跟踪我们的进度。
生成初始列表或特定 RuboCop 规则列表 的首选方法是运行 Rake 任务 rubocop:todo:generate:
# 初始列表
bundle exec rake rubocop:todo:generate
# 特定 RuboCop 规则的列表
bundle exec rake 'rubocop:todo:generate[Gitlab/NamespacedClass,Lint/Syntax]'此 Rake 任务在 .rubocop_todo/ 中创建或更新异常列表。例如,RuboCop 规则 Gitlab/NamespacedClass 的配置位于 .rubocop_todo/gitlab/namespaced_class.yml。
运行 Rake 任务后,请确保提交 .rubocop_todo/ 中的任何更改。
定期生成 RuboCop todo 文件
由于代码更改,一些 RuboCop 违规行为会随着时间的推移自动修复。为了避免重新引入这些违规行为,我们定期重新生成 .rubocop_todo 文件。
我们为此目的使用 housekeeper gem。它会重新生成 .rubocop_todo 文件并创建一个 merge request。审查者被随机分配以审查生成的 merge request。
要在本地运行 keep,请遵循 这些步骤 并运行 bundle exec gitlab-housekeeper -k Keeps::GenerateRubocopTodos。
揭示现有的 RuboCop 异常
要揭示代码中已通过 .rubocop_todo/**/*.yml 排除的现有 RuboCop 异常,请将环境变量 REVEAL_RUBOCOP_TODO 设置为 1。
这允许你在日常工作周期中揭示现有的 RuboCop 异常,并在过程中修复它们。
在 .rubocop.yml 中定义 Includes 和永久的 Excludes,而不是在 .rubocop_todo/**/*.yml 中。
RuboCop 文档
在创建内部 RuboCop 规则时,这些规则应包含 RDoc 风格的文档。
这些文档用于使用 Hugo 生成静态站点,并发布到 https://gitlab-org.gitlab.io/gitlab/rubocop-docs/。
该站点包含来自 gitlab 和 gitlab-styles 项目的所有内部 cops,以及 “good” 和 “bad” 示例。