diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-19 01:45:44 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-19 01:45:44 +0000 |
commit | 85dc423f7090da0a52c73eb66faf22ddb20efff9 (patch) | |
tree | 9160f299afd8c80c038f08e1545be119f5e3f1e1 /doc/development/feature_flags/development.md | |
parent | 15c2c8c66dbe422588e5411eee7e68f1fa440bb8 (diff) | |
download | gitlab-ce-85dc423f7090da0a52c73eb66faf22ddb20efff9.tar.gz |
Add latest changes from gitlab-org/gitlab@13-4-stable-ee
Diffstat (limited to 'doc/development/feature_flags/development.md')
-rw-r--r-- | doc/development/feature_flags/development.md | 140 |
1 files changed, 119 insertions, 21 deletions
diff --git a/doc/development/feature_flags/development.md b/doc/development/feature_flags/development.md index 9b30187fcd1..29bd0ca0a7e 100644 --- a/doc/development/feature_flags/development.md +++ b/doc/development/feature_flags/development.md @@ -1,3 +1,10 @@ +--- +type: reference, dev +stage: none +group: Development +info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines" +--- + # Developing with feature flags This document provides guidelines on how to use feature flags @@ -18,9 +25,7 @@ This document is the subject of continued work as part of an epic to [improve in ## Types of feature flags -Currently, only a single type of feature flag is available. -Additional feature flag types will be provided in the future, -with descriptions for their usage. +Choose a feature flag type that matches the expected usage. ### `development` type @@ -33,6 +38,53 @@ ideally created using the [Feature Flag Roll Out template](https://gitlab.com/gi NOTE: **Note:** This is the default type used when calling `Feature.enabled?`. +### `ops` type + +`ops` feature flags are long-lived feature flags that control operational aspects +of GitLab's behavior. For example, feature flags that disable features that might +have a performance impact, like special Sidekiq worker behavior. + +`ops` feature flags likely do not have rollout issues, as it is hard to +predict when they will be enabled or disabled. + +To use `ops` feature flags, you must append `type: :ops` to `Feature.enabled?` +invocations: + +```ruby +# Check if feature flag is enabled +Feature.enabled?(:my_ops_flag, project, type: ops) + +# Check if feature flag is disabled +Feature.disabled?(:my_ops_flag, project, type: ops) + +# Push feature flag to Frontend +push_frontend_feature_flag(:my_ops_flag, project, type: :ops) +``` + +### `licensed` type + +`licensed` feature flags are used to temporarily disable licensed features. There +should be a one-to-one mapping of `licensed` feature flags to licensed features. + +`licensed` feature flags must be `default_enabled: true`, because that's the only +supported option in the current implementation. This is under development as per +the [related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/218667). + +The `licensed` type has a dedicated set of functions to check if a licensed +feature is available for a project or namespace. This check validates +if the license is assigned to the namespace and feature flag itself. +The `licensed` feature flag has the same name as a licensed feature name: + +```ruby +# Good: checks if feature flag is enabled +project.feature_available?(:my_licensed_feature) +namespace.feature_available?(:my_licensed_feature) + +# Bad: licensed flag must be accessed via `feature_available?` +Feature.enabled?(:my_licensed_feature, type: :licensed) +push_frontend_feature_flag(:my_licensed_feature, type: :licensed) +``` + ## Feature flag definition and validation > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229161) in GitLab 13.3. @@ -58,7 +110,7 @@ Each feature flag is defined in a separate YAML file consisting of a number of f |---------------------|----------|----------------------------------------------------------------| | `name` | yes | Name of the feature flag. | | `type` | yes | Type of feature flag. | -| `default_enabled` | yes | The default state of the feature flag that is strongly validated, with `default_enabled:` passed as an argument. | +| `default_enabled` | yes | The default state of the feature flag that is strictly validated, with `default_enabled:` passed as an argument. | | `introduced_by_url` | no | The URL to the Merge Request that introduced the feature flag. | | `rollout_issue_url` | no | The URL to the Issue covering the feature flag rollout. | | `group` | no | The [group](https://about.gitlab.com/handbook/product/product-categories/#devops-stages) that owns the feature flag. | @@ -77,16 +129,16 @@ Only feature flags that have a YAML definition file can be used when running the ```shell $ bin/feature-flag my-feature-flag ->> Please specify the group introducing feature flag, like `group::apm`: +>> Specify the group introducing the feature flag, like `group::apm`: ?> group::memory ->> If you have MR open, can you paste the URL here? (or enter to skip) +>> URL of the MR introducing the feature flag (enter to skip): ?> https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38602 ->> Open this URL and fill the rest of details: +>> Open this URL and fill in the rest of the details: https://gitlab.com/gitlab-org/gitlab/-/issues/new?issue%5Btitle%5D=%5BFeature+flag%5D+Rollout+of+%60test-flag%60&issuable_template=Feature+Flag+Roll+Out ->> Paste URL of `rollout issue` here, or enter to skip: +>> URL of the rollout issue (enter to skip): ?> https://gitlab.com/gitlab-org/gitlab/-/issues/232533 create config/feature_flags/development/test-flag.yml --- @@ -140,6 +192,21 @@ if Feature.disabled?(:my_feature_flag, project, default_enabled: true) end ``` +If not specified, the default feature flag type for `Feature.enabled?` and `Feature.disabled?` +is `type: development`. For all other feature flag types, you must specify the `type:`: + +```ruby +if Feature.enabled?(:feature_flag, project, type: :ops) + # execute code if ops feature flag is enabled +else + # execute code if ops feature flag is disabled +end + +if Feature.disabled?(:my_feature_flag, project, type: :ops) + # execute code if feature flag is disabled +end +``` + ### Frontend Use the `push_frontend_feature_flag` method for frontend code, which is @@ -185,6 +252,15 @@ before_action do end ``` +If not specified, the default feature flag type for `push_frontend_feature_flag` +is `type: development`. For all other feature flag types, you must specify the `type:`: + +```ruby +before_action do + push_frontend_feature_flag(:vim_bindings, project, type: :ops) +end +``` + ### Feature actors **It is strongly advised to use actors with feature flags.** Actors provide a simple @@ -229,7 +305,7 @@ used as an actor for `Feature.enabled?`. ### Feature flags for licensed features If a feature is license-gated, there's no need to add an additional -explicit feature flag check since the flag will be checked as part of the +explicit feature flag check since the flag is checked as part of the `License.feature_available?` call. Similarly, there's no need to "clean up" a feature flag once the feature has reached general availability. @@ -238,12 +314,16 @@ The [`Project#feature_available?`](https://gitlab.com/gitlab-org/gitlab/blob/4cc [`License.feature_available?`](https://gitlab.com/gitlab-org/gitlab/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/license.rb#L293-300) (EE) methods all implicitly check for a by default enabled feature flag with the same name as the provided argument. -You'd still want to use an explicit `Feature.enabled?` check if your new feature -isn't gated by a License or Plan. - **An important side-effect of the implicit feature flags mentioned above is that unless the feature is explicitly disabled or limited to a percentage of users, -the feature flag check will default to `true`.** +the feature flag check defaults to `true`.** + +NOTE: **Note:** +Due to limitations with `feature_available?`, the YAML definition for `licensed` feature +flags accepts only `default_enabled: true`. This is under development as per the +[related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/218667). + +#### Alpha/beta licensed feature flags This is relevant when developing the feature using [several smaller merge requests](https://about.gitlab.com/handbook/values/#make-small-merge-requests), or when the feature is considered to be an @@ -259,13 +339,31 @@ GitLab.com and self-managed instances, you should use the method, according to our [definitions](https://about.gitlab.com/handbook/product/gitlab-the-product/#alpha-beta-ga). This ensures the feature is disabled unless the feature flag is _explicitly_ enabled. +CAUTION: **Caution:** +If `alpha_feature_available?` or `beta_feature_available?` is used, the YAML definition +for the feature flag must use `default_enabled: [false, true]`, because the usage +of the feature flag is undefined. These methods may change, as per the +[related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/218667). + +The resulting YAML should be similar to: + +```yaml +name: scoped_labels +group: group::memory +type: licensed +# The `default_enabled:` is undefined +# as `feature_available?` uses `default_enabled: true` +# as `beta_feature_available?` uses `default_enabled: false` +default_enabled: [false, true] +``` + ### Feature groups Feature groups must be defined statically in `lib/feature.rb` (in the `.register_feature_groups` method), but their implementation can obviously be -dynamic (querying the DB etc.). +dynamic (querying the DB, for example). -Once defined in `lib/feature.rb`, you will be able to activate a +Once defined in `lib/feature.rb`, you can to activate a feature for a given feature group via the [`feature_group` parameter of the features API](../../api/features.md#set-or-create-a-feature) ### Enabling a feature flag locally (in development) @@ -276,7 +374,7 @@ In the rails console (`rails c`), enter the following command to enable a featur Feature.enable(:feature_flag_name) ``` -Similarly, the following command will disable a feature flag: +Similarly, the following command disables a feature flag: ```ruby Feature.disable(:feature_flag_name) @@ -290,7 +388,7 @@ Feature.enable(:feature_flag_name, Project.find_by_full_path("root/my-project")) ## Feature flags in tests -Introducing a feature flag into the codebase creates an additional codepath that should be tested. +Introducing a feature flag into the codebase creates an additional code path that should be tested. It is strongly advised to test all code affected by a feature flag, both when **enabled** and **disabled** to ensure the feature works properly. @@ -325,10 +423,10 @@ Feature.enabled?(:ci_live_trace, project2) # => false The behavior of FlipperGate is as follows: -1. You can enable an override for a specified actor to be enabled +1. You can enable an override for a specified actor to be enabled. 1. You can disable (remove) an override for a specified actor, - falling back to default state -1. There's no way to model that you explicitly disable a specified actor + falling back to the default state. +1. There's no way to model that you explicitly disabled a specified actor. ```ruby Feature.enable(:my_feature) @@ -369,7 +467,7 @@ Feature.enable_percentage_of_time(:my_feature_3, 50) Feature.enable_percentage_of_actors(:my_feature_4, 50) ``` -Each feature flag that has a defined state will be persisted +Each feature flag that has a defined state is persisted during test execution time: ```ruby |