1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
|
---
stage: Enablement
group: Infrastructure
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
---
# Feature Categorization
Each Sidekiq worker, Batched Background migrations, controller action, [test example](../testing_guide/best_practices.md#feature-category-metadata) or API endpoint
must declare a `feature_category` attribute. This attribute maps each
of these to a [feature category](https://handbook.gitlab.com/handbook/product/categories/). This
is done for error budgeting, alert routing, and team attribution.
The list of feature categories can be found in the file `config/feature_categories.yml`.
This file is generated from the
[`stages.yml`](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml)
data file used in the GitLab Handbook and other GitLab resources.
## Updating `config/feature_categories.yml`
Occasionally new features will be added to GitLab stages, groups, and
product categories. When this occurs, you can automatically update
`config/feature_categories.yml` by running
`scripts/update-feature-categories`. This script will fetch and parse
[`stages.yml`](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml)
and generate a new version of the file, which needs to be committed to
the repository.
The [Scalability team](https://handbook.gitlab.com/handbook/engineering/infrastructure/team/scalability/)
currently maintains the `feature_categories.yml` file. They will automatically be
notified on Slack when the file becomes outdated.
## Gemfile
For each Ruby gem dependency we should specify which feature category requires
this dependency. This should clarify ownership and we can delegate upgrading
to the respective group owning the feature.
### Tooling feature category
For Engineering Productivity internal tooling we use `feature_category: :tooling`.
For example, `knapsack` and `crystalball` are both used to run RSpec test
suites in CI and they don't belong to any product groups.
### Test platform feature category
For gems that are primarily maintained by the [Test Platform sub department](https://handbook.gitlab.com/handbook/engineering/infrastructure/test-platform/), we use `feature_category: :test_platform`.
For example, `capybara` is defined in both `Gemfile` and `qa/Gemfile` to run tests involving UI. They don't belong to a specific product group.
### Shared feature category
For gems that are used across different product groups we use
`feature_category: :shared`. For example, `rails` is used through out the
application and it's shared with multiple groups.
## Sidekiq workers
The declaration uses the `feature_category` class method, as shown below.
```ruby
class SomeScheduledTaskWorker
include ApplicationWorker
# Declares that this worker is part of the
# `continuous_integration` feature category
feature_category :continuous_integration
# ...
end
```
The feature categories specified using `feature_category` should be
defined in
[`config/feature_categories.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/feature_categories.yml). If
not, the specs will fail.
### Excluding Sidekiq workers from feature categorization
A few Sidekiq workers, that are used across all features, cannot be mapped to a
single category. These should be declared as such using the
`feature_category :not_owned`
declaration, as shown below:
```ruby
class SomeCrossCuttingConcernWorker
include ApplicationWorker
# Declares that this worker does not map to a feature category
feature_category :not_owned # rubocop:disable Gitlab/AvoidFeatureCategoryNotOwned
# ...
end
```
When possible, workers marked as "not owned" use their caller's
category (worker or HTTP endpoint) in metrics and logs.
For instance, `ReactiveCachingWorker` can have multiple feature
categories in metrics and logs.
## Batched background migrations
Long-running migrations (as per the [time limits guidelines](../migration_style_guide.md#how-long-a-migration-should-take))
are pulled out as [batched background migrations](../database/batched_background_migrations.md).
They should define a `feature_category`, like this:
```ruby
# Filename: lib/gitlab/background_migration/my_background_migration_job.rb
class MyBackgroundMigrationJob < BatchedMigrationJob
feature_category :gitaly
#...
end
```
NOTE:
[`RuboCop::Cop::BackgroundMigration::FeatureCategory`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/rubocop/cop/background_migration/feature_category.rb) cop ensures a valid `feature_category` is defined.
## Rails controllers
Specifying feature categories on controller actions can be done using
the `feature_category` class method.
A feature category can be specified on an entire controller
using:
```ruby
class Boards::ListsController < ApplicationController
feature_category :kanban_boards
end
```
The feature category can be limited to a list of actions using the
second argument:
```ruby
class DashboardController < ApplicationController
feature_category :team_planning, [:issues, :issues_calendar]
feature_category :code_review_workflow, [:merge_requests]
end
```
These forms cannot be mixed: if a controller has more than one category,
every single action must be listed.
### Excluding controller actions from feature categorization
In the rare case an action cannot be tied to a feature category this
can be done using the `not_owned` feature category.
```ruby
class Admin::LogsController < ApplicationController
feature_category :not_owned
end
```
### Ensuring feature categories are valid
The `spec/controllers/every_controller_spec.rb` will iterate over all
defined routes, and check the controller to see if a category is
assigned to all actions.
The spec also validates if the used feature categories are known. And if
the actions used in configuration still exist as routes.
## API endpoints
The [GraphQL API](../../api/graphql/index.md) is currently categorized
as `not_owned`. For now, no extra specification is needed. For more
information, see
[`gitlab-com/gl-infra/scalability#583`](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/583/).
Grape API endpoints can use the `feature_category` class method, like
[Rails controllers](#rails-controllers) do:
```ruby
module API
class Issues < ::API::Base
feature_category :team_planning
end
end
```
The second argument can be used to specify feature categories for
specific routes:
```ruby
module API
class Users < ::API::Base
feature_category :user_profile, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key']
end
end
```
Or the feature category can be specified in the action itself:
```ruby
module API
class Users < ::API::Base
get ':id', feature_category: :user_profile do
end
end
end
```
As with Rails controllers, an API class must specify the category for
every single action unless the same category is used for every action
within that class.
## RSpec Examples
You must set feature category metadata for each RSpec example. This information is used for flaky test
issues to identify the group that owns the feature.
The `feature_category` should be a value from [`config/feature_categories.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/feature_categories.yml).
The `feature_category` metadata can be set:
- [In the top-level `RSpec.describe` blocks](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104274/diffs#6bd01173381e873f3e1b6c55d33cdaa3d897156b_5_5).
- [In `describe` blocks](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104274/diffs#a520db2677a30e7f1f5593584f69c49031b894b9_12_12).
Consider splitting the file in the case there are multiple feature categories identified in the same file.
Example:
```ruby
RSpec.describe Admin::Geo::SettingsController, :geo, feature_category: :geo_replication do
```
For examples that don't have a `feature_category` set we add a warning when running them in local environment.
To disable the warning use `RSPEC_WARN_MISSING_FEATURE_CATEGORY=false` when running RSpec tests:
```shell
RSPEC_WARN_MISSING_FEATURE_CATEGORY=false bin/rspec spec/<test_file>
```
Additionally, we flag the offenses via `RSpec/FeatureCategory` RuboCop rule.
### Tooling feature category
For Engineering Productivity internal tooling we use `feature_category: :tooling`.
For example in [`spec/tooling/danger/specs_spec.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/tooling/danger/specs_spec.rb#L12).
### Shared feature category
For features that support developers and they are not specific to a product group we use `feature_category: :shared`
For example [`spec/lib/gitlab/job_waiter_spec.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/lib/gitlab/job_waiter_spec.rb)
### Admin section
Adding feature categories is equally important when adding new parts to the Admin section. Historically, Admin sections were often marked as `not_owned` in the code. Now
you must ensure each new addition to the Admin section is properly annotated using `feature_category` notation.
|