From 5ccdaeee4226d446816a6ed80e6ac204b886311b Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Mon, 4 Nov 2019 15:03:40 +0700 Subject: [PATCH] Feature flag API documentation This commit adds feature flag API documentation --- doc/api/feature_flag_specs.md | 291 +++++++++++++++++ doc/api/feature_flags.md | 308 ++++++++++++++++++ doc/user/permissions.md | 1 + doc/user/project/operations/feature_flags.md | 31 +- .../unreleased/feature-flag-documentation.yml | 5 + ee/lib/api/feature_flag_scopes.rb | 21 +- ee/lib/api/feature_flags.rb | 15 +- .../requests/api/feature_flag_scopes_spec.rb | 12 - 8 files changed, 647 insertions(+), 37 deletions(-) create mode 100644 doc/api/feature_flag_specs.md create mode 100644 doc/api/feature_flags.md create mode 100644 ee/changelogs/unreleased/feature-flag-documentation.yml diff --git a/doc/api/feature_flag_specs.md b/doc/api/feature_flag_specs.md new file mode 100644 index 00000000000000..6a2cd047f85e01 --- /dev/null +++ b/doc/api/feature_flag_specs.md @@ -0,0 +1,291 @@ +# Feature Flag Specs API **(PREMIUM)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9566) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5. + +The API for creating, updating, reading and deleting [Feature Flag Specs](../user/project/operations/feature_flags.md#define-environment-specs). +Automation engineers benefit from this API by being able to modify Feature Flag Specs without accessing user interface. +To manage the [Feature Flag](../user/project/operations/feature_flags.md) resources via public API, please refer to the [Feature Flags API](feature_flags.md) document. + +Users with Developer or higher [permissions](../user/permissions.md) can access Feature Flag Specs API. + +## List all effective feature flag specs under the specified environment + +Get all effective feature flag specs under the specified [environment](../ci/environments.md). + +For instance, there are two specs, `staging` and `production`, for a feature flag. +When you pass `production` as a parameter to this endpoint, the system returns +the `production` feature flag spec only. + +``` +GET /projects/:id/feature_flag_scopes +``` + +| Attribute | Type | Required | Description | +| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). | +| `environment` | string | yes | The [environment](../ci/environments.md) name | + +```bash +curl --header "PRIVATE-TOKEN: " https://gitlab.example.com/api/v4/projects/1/feature_flag_scopes?environment=production +``` + +Example response: + +```json +[ + { + "id": 88, + "active": true, + "environment_scope": "production", + "strategies": [ + { + "name": "userWithId", + "parameters": { + "userIds": "1,2,3" + } + } + ], + "created_at": "2019-11-04T08:36:41.327Z", + "updated_at": "2019-11-04T08:36:41.327Z", + "name": "awesome_feature" + }, + { + "id": 82, + "active": true, + "environment_scope": "*", + "strategies": [ + { + "name": "default", + "parameters": {} + } + ], + "created_at": "2019-11-04T08:13:51.425Z", + "updated_at": "2019-11-04T08:39:45.751Z", + "name": "merge_train" + }, + { + "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", + "name": "new_live_trace" + } +] +``` + +## List all specs of a feature flag + +Get all specs of a feature flag. + +``` +GET /projects/:id/feature_flags/:name/scopes +``` + +| 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: " https://gitlab.example.com/api/v4/projects/1/feature_flags/new_live_trace/scopes +``` + +Example response: + +```json +[ + { + "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 spec + +Creates a new feature flag spec. + +``` +POST /projects/:id/feature_flags/:name/scopes +``` + +| 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. | +| `environment_scope` | string | yes | The [environment spec](../ci/environments.md#scoping-environments-with-specs) of the feature flag. | +| `active` | boolean | yes | Whether the spec is active. | +| `strategies` | json | yes | 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/new_live_trace/scopes \ + --header "PRIVATE-TOKEN: " \ + --header "Content-type: application/json" \ + --data @- << EOF +{ + "environment_scope": "*", + "active": false, + "strategies": [{ "name": "default", "parameters": {} }] +} +EOF +``` + +Example response: + +```json +{ + "id": 81, + "active": false, + "environment_scope": "*", + "strategies": [ + { + "name": "default", + "parameters": {} + } + ], + "created_at": "2019-11-04T08:13:10.527Z", + "updated_at": "2019-11-04T08:13:10.527Z" +} +``` + +## Single feature flag spec + +Gets a single feature flag spec. + +``` +GET /projects/:id/feature_flags/:name/scopes/:environment_scope +``` + +| 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. | +| `environment_scope` | string | yes | The URL-encoded [environment spec](../ci/environments.md#scoping-environments-with-specs) of the feature flag. | + +```bash +curl --header "PRIVATE-TOKEN: " https://gitlab.example.com/api/v4/projects/:id/feature_flags/new_live_trace/scopes/production +``` + +Example response: + +```json +{ + "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" +} +``` + +## Edit feature flag spec + +Updates an existing feature flag spec. + +``` +PUT /projects/:id/feature_flags/:name/scopes/:environment_scope +``` + +| 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. | +| `environment_scope` | string | yes | The URL-encoded [environment spec](../ci/environments.md#scoping-environments-with-specs) of the feature flag. | +| `active` | boolean | yes | Whether the spec is active. | +| `strategies` | json | yes | 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/new_live_trace/scopes/production \ + --header "PRIVATE-TOKEN: " \ + --header "Content-type: application/json" \ + --data @- << EOF +{ + "active": true, + "strategies": [{ "name": "userWithId", "parameters": { "userIds": "1,2,3" } }] +} +EOF +``` + +Example response: + +```json +{ + "id": 81, + "active": true, + "environment_scope": "production", + "strategies": [ + { + "name": "userWithId", + "parameters": { "userIds": "1,2,3" } + } + ], + "created_at": "2019-11-04T08:13:10.527Z", + "updated_at": "2019-11-04T08:13:10.527Z" +} +``` + +## Delete feature flag spec + +Deletes a feature flag spec. + +``` +DELETE /projects/:id/feature_flags/:name/scopes/:environment_scope +``` + +| 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. | +| `environment_scope` | string | yes | The URL-encoded [environment spec](../ci/environments.md#scoping-environments-with-specs) of the feature flag. | + +```bash +curl --header "PRIVATE-TOKEN: " --request DELETE https://gitlab.example.com/api/v4/projects/1/feature_flags/new_live_trace/scopes/production +``` diff --git a/doc/api/feature_flags.md b/doc/api/feature_flags.md new file mode 100644 index 00000000000000..def452d36fb7cc --- /dev/null +++ b/doc/api/feature_flags.md @@ -0,0 +1,308 @@ +# 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: " 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: " \ + --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: " 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: " --request DELETE https://gitlab.example.com/api/v4/projects/1/feature_flags/awesome_feature +``` diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 0382c33f7c6e55..45a5fa7e47900c 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -103,6 +103,7 @@ The following table depicts the various user permission levels in a project. | Apply code change suggestions | | | ✓ | ✓ | ✓ | | Create and edit wiki pages | | | ✓ | ✓ | ✓ | | Rewrite/remove Git tags | | | ✓ | ✓ | ✓ | +| Manage Feature Flags **(PREMIUM)** | | | ✓ | ✓ | ✓ | | Use environment terminals | | | | ✓ | ✓ | | Run Web IDE's Interactive Web Terminals **(ULTIMATE ONLY)** | | | | ✓ | ✓ | | Add new team members | | | | ✓ | ✓ | diff --git a/doc/user/project/operations/feature_flags.md b/doc/user/project/operations/feature_flags.md index 08df92959c3779..c05f8fa8bc4f9d 100644 --- a/doc/user/project/operations/feature_flags.md +++ b/doc/user/project/operations/feature_flags.md @@ -81,7 +81,14 @@ NOTE: **NOTE** We'd highly recommend you to use the [Environment](../../../ci/environments.md) 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. @@ -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. 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 [`default`](https://unleash.github.io/docs/activation_strategy#default) activation strategy. -### Percent rollout (logged in users) +#### Percent rollout (logged in users) Enables the feature for a percentage of authenticated users. It is implemented using the Unleash @@ -112,7 +119,7 @@ CAUTION: **Caution:** 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. -## Target users +### Target users strategy > [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 [get the access credentials](#configuring-feature-flags) from GitLab and then 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: @@ -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 application instead of the running environment. -### Client libraries +## Client libraries GitLab currently implements a single backend that is compatible with [Unleash](https://github.com/Unleash/unleash#client-implementations) clients. @@ -178,7 +185,7 @@ Community contributed clients: - [Unofficial .Net Core Unleash client](https://github.com/onybo/unleash-client-core) - [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: @@ -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. @@ -249,3 +256,11 @@ else puts "hello, world!" 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) diff --git a/ee/changelogs/unreleased/feature-flag-documentation.yml b/ee/changelogs/unreleased/feature-flag-documentation.yml new file mode 100644 index 00000000000000..293fa6bccdc14e --- /dev/null +++ b/ee/changelogs/unreleased/feature-flag-documentation.yml @@ -0,0 +1,5 @@ +--- +title: Add public API for Feature Flags +merge_request: 19547 +author: +type: added diff --git a/ee/lib/api/feature_flag_scopes.rb b/ee/lib/api/feature_flag_scopes.rb index d4f856526bb018..fb0972978ae463 100644 --- a/ee/lib/api/feature_flag_scopes.rb +++ b/ee/lib/api/feature_flag_scopes.rb @@ -4,11 +4,10 @@ module API class FeatureFlagScopes < Grape::API 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) before do - not_found! unless Feature.enabled?(:feature_flag_api, user_project) authorize_read_feature_flags! end @@ -18,7 +17,7 @@ class FeatureFlagScopes < Grape::API resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do resource :feature_flag_scopes 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 end params do @@ -35,7 +34,7 @@ class FeatureFlagScopes < Grape::API resource 'feature_flags/:name', requirements: FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS do resource :scopes 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 end params do @@ -46,12 +45,12 @@ class FeatureFlagScopes < Grape::API end 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 end params do 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' end post do @@ -71,9 +70,9 @@ class FeatureFlagScopes < Grape::API params do requires :environment_scope, type: String, desc: 'URL-encoded environment scope' 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 - 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 end get do @@ -81,11 +80,11 @@ class FeatureFlagScopes < Grape::API end 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 end 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' end put do @@ -108,7 +107,7 @@ class FeatureFlagScopes < Grape::API end 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 end delete do diff --git a/ee/lib/api/feature_flags.rb b/ee/lib/api/feature_flags.rb index 1ea4f021125646..34e70c388637c0 100644 --- a/ee/lib/api/feature_flags.rb +++ b/ee/lib/api/feature_flags.rb @@ -8,7 +8,6 @@ class FeatureFlags < Grape::API .merge(name: API::NO_SLASH_URL_PART_REGEX) before do - not_found! unless Feature.enabled?(:feature_flag_api, user_project) authorize_read_feature_flags! end @@ -18,7 +17,7 @@ class FeatureFlags < Grape::API resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do resource :feature_flags 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 end params do @@ -35,7 +34,7 @@ class FeatureFlags < Grape::API end 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 end params do @@ -70,7 +69,7 @@ class FeatureFlags < Grape::API end resource 'feature_flags/:name', requirements: FEATURE_FLAG_ENDPOINT_REQUIREMENTS 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 end get do @@ -80,7 +79,7 @@ class FeatureFlags < Grape::API end 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 end params do @@ -88,6 +87,8 @@ class FeatureFlags < Grape::API requires :strategy, type: JSON, desc: 'The strategy to be enabled on the scope' end post :enable do + not_found! unless Feature.enabled?(:feature_flag_api, user_project) + result = ::FeatureFlags::EnableService .new(user_project, current_user, params).execute @@ -108,6 +109,8 @@ class FeatureFlags < Grape::API requires :strategy, type: JSON, desc: 'The strategy to be disabled on the scope' end post :disable do + not_found! unless Feature.enabled?(:feature_flag_api, user_project) + result = ::FeatureFlags::DisableService .new(user_project, current_user, params).execute @@ -120,7 +123,7 @@ class FeatureFlags < Grape::API end 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 end delete do diff --git a/ee/spec/requests/api/feature_flag_scopes_spec.rb b/ee/spec/requests/api/feature_flag_scopes_spec.rb index 908e3114014b87..edb8b0e644a308 100644 --- a/ee/spec/requests/api/feature_flag_scopes_spec.rb +++ b/ee/spec/requests/api/feature_flag_scopes_spec.rb @@ -38,18 +38,6 @@ expect(response).to have_gitlab_http_status(:forbidden) 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 shared_examples_for 'not found' do -- GitLab