205 lines
6.6 KiB
Markdown
205 lines
6.6 KiB
Markdown
---
|
|
stage: Enablement
|
|
group: Infrastructure
|
|
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
|
---
|
|
|
|
# Feature Categorization
|
|
|
|
> [Introduced](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/269) in GitLab 13.2.
|
|
|
|
Each Sidekiq worker, 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://about.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://about.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.
|
|
|
|
## 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.
|
|
|
|
## 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, [: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 :users, ['/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: :users 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 [`categories.json`](https://about.gitlab.com/categories.json).
|
|
|
|
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.
|
|
|
|
In order 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>
|
|
```
|
|
|
|
### Excluding specs 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
|
|
RSpec.describe Utils, feature_category: :not_owned do
|
|
```
|