功能分类
每个 Sidekiq worker、批量后台迁移(Batched Background migrations)、controller action、测试示例 或 API 端点都必须声明一个 feature_category 属性。这个属性将每个元素映射到一个 功能类别。这样做的目的是为了错误预算(error budgeting)、告警路由(alert routing)和团队归属(team attribution)。
功能类别列表可以在 config/feature_categories.yml 文件中找到。该文件是根据 GitLab Handbook 和其他 GitLab 资源中使用的 stages.yml 数据文件生成的。
更新 config/feature_categories.yml
偶尔会有新功能添加到 GitLab 的阶段(stages)、组(groups)和产品类别中。当这种情况发生时,你可以通过运行 scripts/update-feature-categories 来自动更新 config/feature_categories.yml。这个脚本会获取并解析 stages.yml 文件,并生成一个新版本的文件,需要将其提交到仓库中。
可扩展性团队 目前维护着 feature_categories.yml 文件。当文件过时时,他们会在 Slack 上收到自动通知。
Gemfile
对于每个 Ruby gem 依赖,我们应该指定哪个功能类别需要这个依赖。这应该明确所有权,我们可以将升级委托给拥有该功能的相关组。
工具功能类别
对于开发者体验(Developer Experience)内部工具,我们使用 feature_category: :tooling。例如,knapsack 和 gitlab-crystalball 都用于在 CI 中运行 RSpec 测试套件,它们不属于任何产品组。
测试平台功能类别
对于主要由 测试平台子部门 维护的 gem,我们使用 feature_category: :test_platform。例如,capybara 在 Gemfile 和 qa/Gemfile 中都有定义,用于运行涉及 UI 的测试。它们不属于特定的产品组。
共享功能类别
对于在不同产品组之间使用的 gem,我们使用 feature_category: :shared。例如,rails 在整个应用程序中使用,并与多个组共享。
Sidekiq workers
声明使用 feature_category 类方法,如下所示。
class SomeScheduledTaskWorker
include ApplicationWorker
# 声明这个 worker 属于
# `continuous_integration` 功能类别
feature_category :continuous_integration
# ...
end使用 feature_category 指定的功能类别应该在 config/feature_categories.yml 中定义。如果没有定义,测试将会失败。
将 Sidekiq workers 排除在功能分类之外
一些用于所有功能的 Sidekiq workers 无法映射到单个类别。这些应该使用 feature_category :not_owned 声明来声明,如下所示:
class SomeCrossCuttingConcernWorker
include ApplicationWorker
# 声明这个 worker 不映射到任何功能类别
feature_category :not_owned # rubocop:disable Gitlab/AvoidFeatureCategoryNotOwned
# ...
end在可能的情况下,标记为 “not owned” 的 workers 在指标和日志中使用其调用者的类别(worker 或 HTTP 端点)。例如,ReactiveCachingWorker 在指标和日志中可以有多个功能类别。
批量后台迁移
长时间运行的迁移(根据 时间限制指南)被提取为 批量后台迁移。它们应该定义一个 feature_category,如下所示:
# 文件名: lib/gitlab/background_migration/my_background_migration_job.rb
class MyBackgroundMigrationJob < BatchedMigrationJob
feature_category :gitaly
#...
endRuboCop::Cop::BackgroundMigration::FeatureCategory cop 确保定义了有效的 feature_category。
Rails controllers
可以使用 feature_category 类方法为 controller actions 指定功能类别。
可以在整个 controller 上指定功能类别,使用:
class Boards::ListsController < ApplicationController
feature_category :kanban_boards
end可以使用第二个参数将功能类别限制为动作列表:
class DashboardController < ApplicationController
feature_category :team_planning, [:issues, :issues_calendar]
feature_category :code_review_workflow, [:merge_requests]
end这些形式不能混合使用:如果一个 controller 有多个类别,每个动作都必须列出。
将 controller actions 排除在功能分类之外
在极少数情况下,如果一个动作无法与功能类别关联,可以使用 not_owned 功能类别来完成。
class Admin::LogsController < ApplicationController
feature_category :not_owned
end确保功能类别有效
spec/controllers/every_controller_spec.rb 会遍历所有已定义的路由,并检查 controller 是否为所有动作分配了类别。
该测试还会验证使用的功能类别是否已知,以及配置中使用的动作是否仍然作为路由存在。
API endpoints
GraphQL API 目前被归类为 not_owned。目前不需要额外的规范。更多信息,请参见 gitlab-com/gl-infra/scalability#583。
Grape API 端点可以使用 feature_category 类方法,就像 Rails controllers 一样:
module API
class Issues < ::API::Base
feature_category :team_planning
end
end第二个参数可用于为特定路由指定功能类别:
module API
class Users < ::API::Base
feature_category :user_profile, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key']
end
end或者可以在动作本身中指定功能类别:
module API
class Users < ::API::Base
get ':id', feature_category: :user_profile do
end
end
end与 Rails controllers 一样,API 类必须为每个动作指定类别,除非该类中的每个动作都使用相同的类别。
RSpec Examples
你必须为每个 RSpec 示例设置功能类别元数据。此信息用于识别拥有该功能的组,以解决不稳定测试问题。
feature_category 应该是 config/feature_categories.yml 中的一个值。
feature_category 元数据可以设置:
如果在同一文件中识别出多个功能类别,考虑拆分该文件。
示例:
RSpec.describe Admin::Geo::SettingsController, :geo, feature_category: :geo_replication do对于没有设置 feature_category 的示例,在本地环境中运行时会添加警告。
要禁用警告,在运行 RSpec 测试时使用 RSPEC_WARN_MISSING_FEATURE_CATEGORY=false:
RSPEC_WARN_MISSING_FEATURE_CATEGORY=false bin/rspec spec/<test_file>此外,我们通过 RSpec/FeatureCategory RuboCop 规则标记违规行为。
工具功能类别
对于工程生产力(Engineering Productivity)内部工具,我们使用 feature_category: :tooling。
例如在 spec/tooling/danger/specs_spec.rb 中。
共享功能类别
对于支持开发者且不特定于产品组的功能,我们使用 feature_category: :shared。例如 spec/lib/gitlab/job_waiter_spec.rb
Admin 部分
在添加 Admin 部分的新内容时,添加功能类别同样重要。历史上,Admin 部分在代码中通常被标记为 not_owned。现在,你必须确保 Admin 部分的每个新内容都使用 feature_category 标记法正确标注。