Commit 44f6f21a authored by Marcia Ramos's avatar Marcia Ramos

Merge branch 'feature-flag-documentation' into 'master'

Publish Feature flag API

See merge request gitlab-org/gitlab!19547
parents 09c4b149 5ccdaeee
This diff is collapsed.
# Feature Flags API **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9566) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5.
API for accessing resources of [GitLab Feature Flags](../user/project/operations/feature_flags.md).
Users with Developer or higher [permissions](../user/permissions.md) can access Feature Flag API.
## Feature Flags pagination
By default, `GET` requests return 20 results at a time because the API results
are [paginated](README.md#pagination).
## List feature flags for a project
Gets all feature flags of the requested project.
```
GET /projects/:id/feature_flags
```
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
| `scope` | string | no | The condition of feature flags, one of: `enabled`, `disabled`. |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/feature_flags
```
Example response:
```json
[
{
"name":"merge_train",
"description":"This feature is about merge train",
"created_at":"2019-11-04T08:13:51.423Z",
"updated_at":"2019-11-04T08:13:51.423Z",
"scopes":[
{
"id":82,
"active":false,
"environment_scope":"*",
"strategies":[
{
"name":"default",
"parameters":{
}
}
],
"created_at":"2019-11-04T08:13:51.425Z",
"updated_at":"2019-11-04T08:13:51.425Z"
},
{
"id":83,
"active":true,
"environment_scope":"review/*",
"strategies":[
{
"name":"default",
"parameters":{
}
}
],
"created_at":"2019-11-04T08:13:51.427Z",
"updated_at":"2019-11-04T08:13:51.427Z"
},
{
"id":84,
"active":false,
"environment_scope":"production",
"strategies":[
{
"name":"default",
"parameters":{
}
}
],
"created_at":"2019-11-04T08:13:51.428Z",
"updated_at":"2019-11-04T08:13:51.428Z"
}
]
},
{
"name":"new_live_trace",
"description":"This is a new live trace feature",
"created_at":"2019-11-04T08:13:10.507Z",
"updated_at":"2019-11-04T08:13:10.507Z",
"scopes":[
{
"id":79,
"active":false,
"environment_scope":"*",
"strategies":[
{
"name":"default",
"parameters":{
}
}
],
"created_at":"2019-11-04T08:13:10.516Z",
"updated_at":"2019-11-04T08:13:10.516Z"
},
{
"id":80,
"active":true,
"environment_scope":"staging",
"strategies":[
{
"name":"default",
"parameters":{
}
}
],
"created_at":"2019-11-04T08:13:10.525Z",
"updated_at":"2019-11-04T08:13:10.525Z"
},
{
"id":81,
"active":false,
"environment_scope":"production",
"strategies":[
{
"name":"default",
"parameters":{
}
}
],
"created_at":"2019-11-04T08:13:10.527Z",
"updated_at":"2019-11-04T08:13:10.527Z"
}
]
}
]
```
## New feature flag
Creates a new feature flag.
```
POST /projects/:id/feature_flags
```
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
| `name` | string | yes | The name of the feature flag. |
| `description` | string | no | The description of the feature flag. |
| `scopes` | JSON | no | The [feature flag specs](../user/project/operations/feature_flags.md#define-environment-specs) of the feature flag. |
| `scopes:environment_scope` | string | no | The [environment spec](../ci/environments.md#scoping-environments-with-specs). |
| `scopes:active` | boolean | no | Whether the spec is active. |
| `scopes:strategies` | JSON | no | The [strategies](../user/project/operations/feature_flags.md#feature-flag-strategies) of the feature flag spec. |
```bash
curl https://gitlab.example.com/api/v4/projects/1/feature_flags \
--header "PRIVATE-TOKEN: <your_access_token>" \
--header "Content-type: application/json" \
--data @- << EOF
{
"name": "awesome_feature",
"scopes": [{ "environment_scope": "*", "active": false, "strategies": [{ "name": "default", "parameters": {} }] },
{ "environment_scope": "production", "active": true, "strategies": [{ "name": "userWithId", "parameters": { "userIds": "1,2,3" } }] }]
}
EOF
```
Example response:
```json
{
"name":"awesome_feature",
"description":null,
"created_at":"2019-11-04T08:32:27.288Z",
"updated_at":"2019-11-04T08:32:27.288Z",
"scopes":[
{
"id":85,
"active":false,
"environment_scope":"*",
"strategies":[
{
"name":"default",
"parameters":{
}
}
],
"created_at":"2019-11-04T08:32:29.324Z",
"updated_at":"2019-11-04T08:32:29.324Z"
},
{
"id":86,
"active":true,
"environment_scope":"production",
"strategies":[
{
"name":"userWithId",
"parameters":{
"userIds":"1,2,3"
}
}
],
"created_at":"2019-11-04T08:32:29.328Z",
"updated_at":"2019-11-04T08:32:29.328Z"
}
]
}
```
## Single feature flag
Gets a single feature flag.
```
GET /projects/:id/feature_flags/:name
```
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
| `name` | string | yes | The name of the feature flag. |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/feature_flags/new_live_trace
```
Example response:
```json
{
"name":"new_live_trace",
"description":"This is a new live trace feature",
"created_at":"2019-11-04T08:13:10.507Z",
"updated_at":"2019-11-04T08:13:10.507Z",
"scopes":[
{
"id":79,
"active":false,
"environment_scope":"*",
"strategies":[
{
"name":"default",
"parameters":{
}
}
],
"created_at":"2019-11-04T08:13:10.516Z",
"updated_at":"2019-11-04T08:13:10.516Z"
},
{
"id":80,
"active":true,
"environment_scope":"staging",
"strategies":[
{
"name":"default",
"parameters":{
}
}
],
"created_at":"2019-11-04T08:13:10.525Z",
"updated_at":"2019-11-04T08:13:10.525Z"
},
{
"id":81,
"active":false,
"environment_scope":"production",
"strategies":[
{
"name":"default",
"parameters":{
}
}
],
"created_at":"2019-11-04T08:13:10.527Z",
"updated_at":"2019-11-04T08:13:10.527Z"
}
]
}
```
## Delete feature flag
Deletes a feature flag.
```
DELETE /projects/:id/feature_flags/:name
```
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
| `name` | string | yes | The name of the feature flag. |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" --request DELETE https://gitlab.example.com/api/v4/projects/1/feature_flags/awesome_feature
```
...@@ -103,6 +103,7 @@ The following table depicts the various user permission levels in a project. ...@@ -103,6 +103,7 @@ The following table depicts the various user permission levels in a project.
| Apply code change suggestions | | | ✓ | ✓ | ✓ | | Apply code change suggestions | | | ✓ | ✓ | ✓ |
| Create and edit wiki pages | | | ✓ | ✓ | ✓ | | Create and edit wiki pages | | | ✓ | ✓ | ✓ |
| Rewrite/remove Git tags | | | ✓ | ✓ | ✓ | | Rewrite/remove Git tags | | | ✓ | ✓ | ✓ |
| Manage Feature Flags **(PREMIUM)** | | | ✓ | ✓ | ✓ |
| Use environment terminals | | | | ✓ | ✓ | | Use environment terminals | | | | ✓ | ✓ |
| Run Web IDE's Interactive Web Terminals **(ULTIMATE ONLY)** | | | | ✓ | ✓ | | Run Web IDE's Interactive Web Terminals **(ULTIMATE ONLY)** | | | | ✓ | ✓ |
| Add new team members | | | | ✓ | ✓ | | Add new team members | | | | ✓ | ✓ |
......
...@@ -81,7 +81,14 @@ NOTE: **NOTE** ...@@ -81,7 +81,14 @@ NOTE: **NOTE**
We'd highly recommend you to use the [Environment](../../../ci/environments.md) We'd highly recommend you to use the [Environment](../../../ci/environments.md)
feature in order to quickly assess which flag is enabled per environment. feature in order to quickly assess which flag is enabled per environment.
## Rollout strategy ## Feature Flag strategies
GitLab Feature Flag adopts [Unleash](https://unleash.github.io)
as the feature flag engine. In unleash, there is a concept of rulesets for granular feature flag controls,
called [strategies](https://unleash.github.io/docs/activation_strategy).
Supported strategies for GitLab Feature Flags are described below.
### Rollout strategy
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/8240) in GitLab 12.2. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/8240) in GitLab 12.2.
...@@ -91,13 +98,13 @@ The status of an environment spec ultimately determines whether or not a feature ...@@ -91,13 +98,13 @@ The status of an environment spec ultimately determines whether or not a feature
For instance, a feature will always be disabled for every user if the matching environment spec has a disabled status, regardless of the chosen rollout strategy. For instance, a feature will always be disabled for every user if the matching environment spec has a disabled status, regardless of the chosen rollout strategy.
However, a feature will be enabled for 50% of logged-in users if the matching environment spec has an enabled status along with a **Percent rollout (logged in users)** strategy set to 50%. However, a feature will be enabled for 50% of logged-in users if the matching environment spec has an enabled status along with a **Percent rollout (logged in users)** strategy set to 50%.
### All users #### All users
Enables the feature for all users. It is implemented using the Unleash Enables the feature for all users. It is implemented using the Unleash
[`default`](https://unleash.github.io/docs/activation_strategy#default) [`default`](https://unleash.github.io/docs/activation_strategy#default)
activation strategy. activation strategy.
### Percent rollout (logged in users) #### Percent rollout (logged in users)
Enables the feature for a percentage of authenticated users. It is Enables the feature for a percentage of authenticated users. It is
implemented using the Unleash implemented using the Unleash
...@@ -112,7 +119,7 @@ CAUTION: **Caution:** ...@@ -112,7 +119,7 @@ CAUTION: **Caution:**
If this strategy is selected, then the Unleash client **must** be given a user If this strategy is selected, then the Unleash client **must** be given a user
ID for the feature to be enabled. See the [Ruby example](#ruby-application-example) below. ID for the feature to be enabled. See the [Ruby example](#ruby-application-example) below.
## Target users ### Target users strategy
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/8240) in GitLab 12.2. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/8240) in GitLab 12.2.
...@@ -134,7 +141,7 @@ In order to use Feature Flags, you need to first ...@@ -134,7 +141,7 @@ In order to use Feature Flags, you need to first
[get the access credentials](#configuring-feature-flags) from GitLab and then [get the access credentials](#configuring-feature-flags) from GitLab and then
prepare your application and hook it with a [client library](#client-libraries). prepare your application and hook it with a [client library](#client-libraries).
### Configuring Feature Flags ## Configuring Feature Flags
To get the access credentials that your application will need to talk to GitLab: To get the access credentials that your application will need to talk to GitLab:
...@@ -153,7 +160,7 @@ if **Instance ID** will be single token or multiple tokens, assigned to the ...@@ -153,7 +160,7 @@ if **Instance ID** will be single token or multiple tokens, assigned to the
**Environment**. Also, **Application name** could describe the version of **Environment**. Also, **Application name** could describe the version of
application instead of the running environment. application instead of the running environment.
### Client libraries ## Client libraries
GitLab currently implements a single backend that is compatible with GitLab currently implements a single backend that is compatible with
[Unleash](https://github.com/Unleash/unleash#client-implementations) clients. [Unleash](https://github.com/Unleash/unleash#client-implementations) clients.
...@@ -178,7 +185,7 @@ Community contributed clients: ...@@ -178,7 +185,7 @@ Community contributed clients:
- [Unofficial .Net Core Unleash client](https://github.com/onybo/unleash-client-core) - [Unofficial .Net Core Unleash client](https://github.com/onybo/unleash-client-core)
- [Unleash client for Python 3](https://github.com/aes/unleash-client-python) - [Unleash client for Python 3](https://github.com/aes/unleash-client-python)
### Golang application example ## Golang application example
Here's an example of how to integrate the feature flags in a Golang application: Here's an example of how to integrate the feature flags in a Golang application:
...@@ -219,7 +226,7 @@ func main() { ...@@ -219,7 +226,7 @@ func main() {
} }
``` ```
### Ruby application example ## Ruby application example
Here's an example of how to integrate the feature flags in a Ruby application. Here's an example of how to integrate the feature flags in a Ruby application.
...@@ -249,3 +256,11 @@ else ...@@ -249,3 +256,11 @@ else
puts "hello, world!" puts "hello, world!"
end end
``` ```
## Feature Flags API
You can create, update, read, and delete Feature Flags via API
to control them in an automated flow:
- [Feature Flags API](../../../api/feature_flags.md)
- [Feature Flag Specs API](../../../api/feature_flag_specs.md)
---
title: Add public API for Feature Flags
merge_request: 19547
author:
type: added
...@@ -4,11 +4,10 @@ module API ...@@ -4,11 +4,10 @@ module API
class FeatureFlagScopes < Grape::API class FeatureFlagScopes < Grape::API
include PaginationParams include PaginationParams
ENVIRONMENT_SCOPE_ENDPOINT_REQUIREMETS = FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS ENVIRONMENT_SCOPE_ENDPOINT_REQUIREMENTS = FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS
.merge(environment_scope: API::NO_SLASH_URL_PART_REGEX) .merge(environment_scope: API::NO_SLASH_URL_PART_REGEX)
before do before do
not_found! unless Feature.enabled?(:feature_flag_api, user_project)
authorize_read_feature_flags! authorize_read_feature_flags!
end end
...@@ -18,7 +17,7 @@ module API ...@@ -18,7 +17,7 @@ module API
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
resource :feature_flag_scopes do resource :feature_flag_scopes do
desc 'Get all effective feature flags under the environment' do desc 'Get all effective feature flags under the environment' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag::DetailedScope success EE::API::Entities::FeatureFlag::DetailedScope
end end
params do params do
...@@ -35,7 +34,7 @@ module API ...@@ -35,7 +34,7 @@ module API
resource 'feature_flags/:name', requirements: FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS do resource 'feature_flags/:name', requirements: FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS do
resource :scopes do resource :scopes do
desc 'Get all scopes of a feature flag' do desc 'Get all scopes of a feature flag' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag::Scope success EE::API::Entities::FeatureFlag::Scope
end end
params do params do
...@@ -46,12 +45,12 @@ module API ...@@ -46,12 +45,12 @@ module API
end end
desc 'Create a scope of a feature flag' do desc 'Create a scope of a feature flag' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag::Scope success EE::API::Entities::FeatureFlag::Scope
end end
params do params do
requires :environment_scope, type: String, desc: 'The environment scope of the scope' requires :environment_scope, type: String, desc: 'The environment scope of the scope'
requires :active, type: Boolean, desc: 'Active/inactive of the scope' requires :active, type: Boolean, desc: 'Whether the scope is active'
requires :strategies, type: JSON, desc: 'The strategies of the scope' requires :strategies, type: JSON, desc: 'The strategies of the scope'
end end
post do post do
...@@ -71,9 +70,9 @@ module API ...@@ -71,9 +70,9 @@ module API
params do params do
requires :environment_scope, type: String, desc: 'URL-encoded environment scope' requires :environment_scope, type: String, desc: 'URL-encoded environment scope'
end end
resource ':environment_scope', requirements: ENVIRONMENT_SCOPE_ENDPOINT_REQUIREMETS do resource ':environment_scope', requirements: ENVIRONMENT_SCOPE_ENDPOINT_REQUIREMENTS do
desc 'Get a scope of a feature flag' do desc 'Get a scope of a feature flag' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag::Scope success EE::API::Entities::FeatureFlag::Scope
end end
get do get do
...@@ -81,11 +80,11 @@ module API ...@@ -81,11 +80,11 @@ module API
end end
desc 'Update a scope of a feature flag' do desc 'Update a scope of a feature flag' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag::Scope success EE::API::Entities::FeatureFlag::Scope
end end
params do params do
optional :active, type: Boolean, desc: 'Active/inactive of the scope' optional :active, type: Boolean, desc: 'Whether the scope is active'
optional :strategies, type: JSON, desc: 'The strategies of the scope' optional :strategies, type: JSON, desc: 'The strategies of the scope'
end end
put do put do
...@@ -108,7 +107,7 @@ module API ...@@ -108,7 +107,7 @@ module API
end end
desc 'Delete a scope from a feature flag' do desc 'Delete a scope from a feature flag' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag::Scope success EE::API::Entities::FeatureFlag::Scope
end end
delete do delete do
......
...@@ -8,7 +8,6 @@ module API ...@@ -8,7 +8,6 @@ module API
.merge(name: API::NO_SLASH_URL_PART_REGEX) .merge(name: API::NO_SLASH_URL_PART_REGEX)
before do before do
not_found! unless Feature.enabled?(:feature_flag_api, user_project)
authorize_read_feature_flags! authorize_read_feature_flags!
end end
...@@ -18,7 +17,7 @@ module API ...@@ -18,7 +17,7 @@ module API
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
resource :feature_flags do resource :feature_flags do
desc 'Get all feature flags of a project' do desc 'Get all feature flags of a project' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag success EE::API::Entities::FeatureFlag
end end
params do params do
...@@ -35,7 +34,7 @@ module API ...@@ -35,7 +34,7 @@ module API
end end
desc 'Create a new feature flag' do desc 'Create a new feature flag' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag success EE::API::Entities::FeatureFlag
end end
params do params do
...@@ -70,7 +69,7 @@ module API ...@@ -70,7 +69,7 @@ module API
end end
resource 'feature_flags/:name', requirements: FEATURE_FLAG_ENDPOINT_REQUIREMENTS do resource 'feature_flags/:name', requirements: FEATURE_FLAG_ENDPOINT_REQUIREMENTS do
desc 'Get a feature flag of a project' do desc 'Get a feature flag of a project' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag success EE::API::Entities::FeatureFlag
end end
get do get do
...@@ -80,7 +79,7 @@ module API ...@@ -80,7 +79,7 @@ module API
end end
desc 'Enable a strategy for a feature flag on an environment' do desc 'Enable a strategy for a feature flag on an environment' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag success EE::API::Entities::FeatureFlag
end end
params do params do
...@@ -88,6 +87,8 @@ module API ...@@ -88,6 +87,8 @@ module API
requires :strategy, type: JSON, desc: 'The strategy to be enabled on the scope' requires :strategy, type: JSON, desc: 'The strategy to be enabled on the scope'
end end
post :enable do post :enable do
not_found! unless Feature.enabled?(:feature_flag_api, user_project)
result = ::FeatureFlags::EnableService result = ::FeatureFlags::EnableService
.new(user_project, current_user, params).execute .new(user_project, current_user, params).execute
...@@ -108,6 +109,8 @@ module API ...@@ -108,6 +109,8 @@ module API
requires :strategy, type: JSON, desc: 'The strategy to be disabled on the scope' requires :strategy, type: JSON, desc: 'The strategy to be disabled on the scope'
end end
post :disable do post :disable do
not_found! unless Feature.enabled?(:feature_flag_api, user_project)
result = ::FeatureFlags::DisableService result = ::FeatureFlags::DisableService
.new(user_project, current_user, params).execute .new(user_project, current_user, params).execute
...@@ -120,7 +123,7 @@ module API ...@@ -120,7 +123,7 @@ module API
end end
desc 'Delete a feature flag' do desc 'Delete a feature flag' do
detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed' detail 'This feature was introduced in GitLab 12.5'
success EE::API::Entities::FeatureFlag success EE::API::Entities::FeatureFlag
end end
delete do delete do
......
...@@ -38,18 +38,6 @@ describe API::FeatureFlagScopes do ...@@ -38,18 +38,6 @@ describe API::FeatureFlagScopes do
expect(response).to have_gitlab_http_status(:forbidden) expect(response).to have_gitlab_http_status(:forbidden)
end end
end end
context 'when feature_flag_api feature flag is disabled' do
before do
stub_feature_flags(feature_flag_api: false)
end
it 'forbids the request' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
end end
shared_examples_for 'not found' do shared_examples_for 'not found' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment