Commit 099a6470 authored by Jason Goodman's avatar Jason Goodman Committed by Shinya Maeda

Add active field to feature flag api

Add support to POST, PUT, GET requests
Add documentation
parent 1072170f
...@@ -45,6 +45,7 @@ Example response: ...@@ -45,6 +45,7 @@ Example response:
{ {
"name":"merge_train", "name":"merge_train",
"description":"This feature is about merge train", "description":"This feature is about merge train",
"active": true,
"version": "new_version_flag", "version": "new_version_flag",
"created_at":"2019-11-04T08:13:51.423Z", "created_at":"2019-11-04T08:13:51.423Z",
"updated_at":"2019-11-04T08:13:51.423Z", "updated_at":"2019-11-04T08:13:51.423Z",
...@@ -68,6 +69,7 @@ Example response: ...@@ -68,6 +69,7 @@ Example response:
{ {
"name":"new_live_trace", "name":"new_live_trace",
"description":"This is a new live trace feature", "description":"This is a new live trace feature",
"active": true,
"version": "new_version_flag", "version": "new_version_flag",
"created_at":"2019-11-04T08:13:10.507Z", "created_at":"2019-11-04T08:13:10.507Z",
"updated_at":"2019-11-04T08:13:10.507Z", "updated_at":"2019-11-04T08:13:10.507Z",
...@@ -112,6 +114,7 @@ Example response: ...@@ -112,6 +114,7 @@ Example response:
{ {
"name": "awesome_feature", "name": "awesome_feature",
"description": null, "description": null,
"active": true,
"version": "new_version_flag", "version": "new_version_flag",
"created_at": "2020-05-13T19:56:33.119Z", "created_at": "2020-05-13T19:56:33.119Z",
"updated_at": "2020-05-13T19:56:33.119Z", "updated_at": "2020-05-13T19:56:33.119Z",
...@@ -146,6 +149,7 @@ POST /projects/:id/feature_flags ...@@ -146,6 +149,7 @@ POST /projects/:id/feature_flags
| `name` | string | yes | The name of the feature flag. | | `name` | string | yes | The name of the feature flag. |
| `version` | string | yes | The version of the feature flag. Must be `new_version_flag`. Omit or set to `legacy_flag` to create a [Legacy Feature Flag](feature_flags_legacy.md). | | `version` | string | yes | The version of the feature flag. Must be `new_version_flag`. Omit or set to `legacy_flag` to create a [Legacy Feature Flag](feature_flags_legacy.md). |
| `description` | string | no | The description of the feature flag. | | `description` | string | no | The description of the feature flag. |
| `active` | boolean | no | The active state of the flag. Defaults to true. [Supported](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38350) in GitLab 13.3 and later. |
| `strategies` | JSON | no | The feature flag [strategies](../operations/feature_flags.md#feature-flag-strategies). | | `strategies` | JSON | no | The feature flag [strategies](../operations/feature_flags.md#feature-flag-strategies). |
| `strategies:name` | JSON | no | The strategy name. | | `strategies:name` | JSON | no | The strategy name. |
| `strategies:parameters` | JSON | no | The strategy parameters. | | `strategies:parameters` | JSON | no | The strategy parameters. |
...@@ -171,6 +175,7 @@ Example response: ...@@ -171,6 +175,7 @@ Example response:
{ {
"name": "awesome_feature", "name": "awesome_feature",
"description": null, "description": null,
"active": true,
"version": "new_version_flag", "version": "new_version_flag",
"created_at": "2020-05-13T19:56:33.119Z", "created_at": "2020-05-13T19:56:33.119Z",
"updated_at": "2020-05-13T19:56:33.119Z", "updated_at": "2020-05-13T19:56:33.119Z",
...@@ -204,6 +209,7 @@ PUT /projects/:id/feature_flags/:name ...@@ -204,6 +209,7 @@ PUT /projects/:id/feature_flags/:name
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). | | `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. | | `name` | string | yes | The name of the feature flag. |
| `description` | string | no | The description of the feature flag. | | `description` | string | no | The description of the feature flag. |
| `active` | boolean | no | The active state of the flag. [Supported](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38350) in GitLab 13.3 and later. |
| `strategies` | JSON | no | The feature flag [strategies](../operations/feature_flags.md#feature-flag-strategies). | | `strategies` | JSON | no | The feature flag [strategies](../operations/feature_flags.md#feature-flag-strategies). |
| `strategies:id` | JSON | no | The feature flag strategy id. | | `strategies:id` | JSON | no | The feature flag strategy id. |
| `strategies:name` | JSON | no | The strategy name. | | `strategies:name` | JSON | no | The strategy name. |
...@@ -229,6 +235,7 @@ Example response: ...@@ -229,6 +235,7 @@ Example response:
{ {
"name": "awesome_feature", "name": "awesome_feature",
"description": null, "description": null,
"active": true,
"version": "new_version_flag", "version": "new_version_flag",
"created_at": "2020-05-13T20:10:32.891Z", "created_at": "2020-05-13T20:10:32.891Z",
"updated_at": "2020-05-13T20:10:32.891Z", "updated_at": "2020-05-13T20:10:32.891Z",
......
...@@ -44,6 +44,7 @@ Example response: ...@@ -44,6 +44,7 @@ Example response:
{ {
"name":"merge_train", "name":"merge_train",
"description":"This feature is about merge train", "description":"This feature is about merge train",
"active": true,
"created_at":"2019-11-04T08:13:51.423Z", "created_at":"2019-11-04T08:13:51.423Z",
"updated_at":"2019-11-04T08:13:51.423Z", "updated_at":"2019-11-04T08:13:51.423Z",
"scopes":[ "scopes":[
...@@ -97,6 +98,7 @@ Example response: ...@@ -97,6 +98,7 @@ Example response:
{ {
"name":"new_live_trace", "name":"new_live_trace",
"description":"This is a new live trace feature", "description":"This is a new live trace feature",
"active": true,
"created_at":"2019-11-04T08:13:10.507Z", "created_at":"2019-11-04T08:13:10.507Z",
"updated_at":"2019-11-04T08:13:10.507Z", "updated_at":"2019-11-04T08:13:10.507Z",
"scopes":[ "scopes":[
...@@ -163,6 +165,7 @@ POST /projects/:id/feature_flags ...@@ -163,6 +165,7 @@ POST /projects/:id/feature_flags
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). | | `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. | | `name` | string | yes | The name of the feature flag. |
| `description` | string | no | The description of the feature flag. | | `description` | string | no | The description of the feature flag. |
| `active` | boolean | no | The active state of the flag. Defaults to true. [Supported](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38350) in GitLab 13.3 and later. |
| `scopes` | JSON | no | The feature flag specs of the feature flag. | | `scopes` | JSON | no | The feature flag specs of the feature flag. |
| `scopes:environment_scope` | string | no | The environment spec. | | `scopes:environment_scope` | string | no | The environment spec. |
| `scopes:active` | boolean | no | Whether the spec is active. | | `scopes:active` | boolean | no | Whether the spec is active. |
...@@ -187,6 +190,7 @@ Example response: ...@@ -187,6 +190,7 @@ Example response:
{ {
"name":"awesome_feature", "name":"awesome_feature",
"description":null, "description":null,
"active": true,
"created_at":"2019-11-04T08:32:27.288Z", "created_at":"2019-11-04T08:32:27.288Z",
"updated_at":"2019-11-04T08:32:27.288Z", "updated_at":"2019-11-04T08:32:27.288Z",
"scopes":[ "scopes":[
...@@ -247,6 +251,7 @@ Example response: ...@@ -247,6 +251,7 @@ Example response:
{ {
"name":"new_live_trace", "name":"new_live_trace",
"description":"This is a new live trace feature", "description":"This is a new live trace feature",
"active": true,
"created_at":"2019-11-04T08:13:10.507Z", "created_at":"2019-11-04T08:13:10.507Z",
"updated_at":"2019-11-04T08:13:10.507Z", "updated_at":"2019-11-04T08:13:10.507Z",
"scopes":[ "scopes":[
......
---
title: Add support for active field to feature flags api
merge_request: 38350
author:
type: fixed
...@@ -40,6 +40,7 @@ module API ...@@ -40,6 +40,7 @@ module API
params do params do
requires :name, type: String, desc: 'The name of feature flag' requires :name, type: String, desc: 'The name of feature flag'
optional :description, type: String, desc: 'The description of the feature flag' optional :description, type: String, desc: 'The description of the feature flag'
optional :active, type: Boolean, desc: 'Active/inactive value of the flag'
optional :version, type: String, desc: 'The version of the feature flag' optional :version, type: String, desc: 'The version of the feature flag'
optional :scopes, type: Array do optional :scopes, type: Array 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'
...@@ -145,6 +146,7 @@ module API ...@@ -145,6 +146,7 @@ module API
end end
params do params do
optional :description, type: String, desc: 'The description of the feature flag' optional :description, type: String, desc: 'The description of the feature flag'
optional :active, type: Boolean, desc: 'Active/inactive value of the flag'
optional :strategies, type: Array do optional :strategies, type: Array do
optional :id, type: Integer, desc: 'The strategy id' optional :id, type: Integer, desc: 'The strategy id'
optional :name, type: String, desc: 'The strategy type' optional :name, type: String, desc: 'The strategy type'
......
...@@ -6,6 +6,7 @@ module EE ...@@ -6,6 +6,7 @@ module EE
class FeatureFlag < Grape::Entity class FeatureFlag < Grape::Entity
expose :name expose :name
expose :description expose :description
expose :active
expose :version, if: :feature_flags_new_version_enabled expose :version, if: :feature_flags_new_version_enabled
expose :created_at expose :created_at
expose :updated_at expose :updated_at
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
"properties": { "properties": {
"name": { "type": "string" }, "name": { "type": "string" },
"description": { "type": ["string", "null"] }, "description": { "type": ["string", "null"] },
"active": {"type": "boolean" },
"version": { "type": "string" }, "version": { "type": "string" },
"created_at": { "type": "date" }, "created_at": { "type": "date" },
"updated_at": { "type": "date" }, "updated_at": { "type": "date" },
......
...@@ -4,19 +4,21 @@ require 'spec_helper' ...@@ -4,19 +4,21 @@ require 'spec_helper'
RSpec.describe API::FeatureFlags do RSpec.describe API::FeatureFlags do
include FeatureFlagHelpers include FeatureFlagHelpers
let(:project) { create(:project, :repository) } let_it_be(:project) { create(:project) }
let(:developer) { create(:user) } let_it_be(:developer) { create(:user) }
let(:reporter) { create(:user) } let_it_be(:reporter) { create(:user) }
let_it_be(:non_project_member) { create(:user) }
let(:user) { developer } let(:user) { developer }
let(:non_project_member) { create(:user) }
before do
stub_licensed_features(feature_flags: true)
before_all do
project.add_developer(developer) project.add_developer(developer)
project.add_reporter(reporter) project.add_reporter(reporter)
end end
before do
stub_licensed_features(feature_flags: true)
end
shared_examples_for 'check user permission' do shared_examples_for 'check user permission' do
context 'when user is reporter' do context 'when user is reporter' do
let(:user) { reporter } let(:user) { reporter }
...@@ -118,6 +120,7 @@ RSpec.describe API::FeatureFlags do ...@@ -118,6 +120,7 @@ RSpec.describe API::FeatureFlags do
expect(json_response).to eq([{ expect(json_response).to eq([{
'name' => 'feature1', 'name' => 'feature1',
'description' => nil, 'description' => nil,
'active' => true,
'version' => 'new_version_flag', 'version' => 'new_version_flag',
'updated_at' => feature_flag.updated_at.as_json, 'updated_at' => feature_flag.updated_at.as_json,
'created_at' => feature_flag.created_at.as_json, 'created_at' => feature_flag.created_at.as_json,
...@@ -207,6 +210,7 @@ RSpec.describe API::FeatureFlags do ...@@ -207,6 +210,7 @@ RSpec.describe API::FeatureFlags do
expect(json_response).to eq({ expect(json_response).to eq({
'name' => 'feature1', 'name' => 'feature1',
'description' => nil, 'description' => nil,
'active' => true,
'version' => 'new_version_flag', 'version' => 'new_version_flag',
'updated_at' => feature_flag.updated_at.as_json, 'updated_at' => feature_flag.updated_at.as_json,
'created_at' => feature_flag.created_at.as_json, 'created_at' => feature_flag.created_at.as_json,
...@@ -298,6 +302,25 @@ RSpec.describe API::FeatureFlags do ...@@ -298,6 +302,25 @@ RSpec.describe API::FeatureFlags do
expect(json_response.key?('version')).to eq(false) expect(json_response.key?('version')).to eq(false)
end end
context 'with active set to false in the params for a legacy flag' do
let(:params) do
{
name: 'awesome-feature',
version: 'legacy_flag',
active: 'false',
scopes: [scope_default]
}
end
it 'creates an inactive feature flag' do
subject
expect(response).to have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/feature_flag', dir: 'ee')
expect(json_response['active']).to eq(false)
end
end
context 'when no scopes passed in parameters' do context 'when no scopes passed in parameters' do
let(:params) { { name: 'awesome-feature' } } let(:params) { { name: 'awesome-feature' } }
...@@ -370,12 +393,37 @@ RSpec.describe API::FeatureFlags do ...@@ -370,12 +393,37 @@ RSpec.describe API::FeatureFlags do
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/feature_flag', dir: 'ee') expect(response).to match_response_schema('public_api/v4/feature_flag', dir: 'ee')
expect(json_response).to match(hash_including({
'name' => 'new-feature',
'description' => nil,
'active' => true,
'version' => 'new_version_flag',
'scopes' => [],
'strategies' => []
}))
feature_flag = project.operations_feature_flags.last feature_flag = project.operations_feature_flags.last
expect(feature_flag.name).to eq(params[:name]) expect(feature_flag.name).to eq(params[:name])
expect(feature_flag.version).to eq('new_version_flag') expect(feature_flag.version).to eq('new_version_flag')
end end
it 'creates a new feature flag that is inactive' do
params = {
name: 'new-feature',
version: 'new_version_flag',
active: false
}
post api("/projects/#{project.id}/feature_flags", user), params: params
expect(response).to have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/feature_flag', dir: 'ee')
expect(json_response['active']).to eq(false)
feature_flag = project.operations_feature_flags.last
expect(feature_flag.active).to eq(false)
end
it 'creates a new feature flag with strategies' do it 'creates a new feature flag with strategies' do
params = { params = {
name: 'new-feature', name: 'new-feature',
...@@ -691,7 +739,7 @@ RSpec.describe API::FeatureFlags do ...@@ -691,7 +739,7 @@ RSpec.describe API::FeatureFlags do
context 'with a version 2 feature flag' do context 'with a version 2 feature flag' do
let!(:feature_flag) do let!(:feature_flag) do
create(:operations_feature_flag, :new_version_flag, project: project, create(:operations_feature_flag, :new_version_flag, project: project, active: true,
name: 'feature1', description: 'old description') name: 'feature1', description: 'old description')
end end
...@@ -755,6 +803,17 @@ RSpec.describe API::FeatureFlags do ...@@ -755,6 +803,17 @@ RSpec.describe API::FeatureFlags do
expect(feature_flag.reload.description).to eq('new description') expect(feature_flag.reload.description).to eq('new description')
end end
it 'updates the flag active value' do
params = { active: false }
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/feature_flag', dir: 'ee')
expect(json_response['active']).to eq(false)
expect(feature_flag.reload.active).to eq(false)
end
it 'ignores a provided version parameter' do it 'ignores a provided version parameter' do
params = { description: 'other description', version: 'bad_value' } params = { description: 'other description', version: 'bad_value' }
...@@ -776,6 +835,7 @@ RSpec.describe API::FeatureFlags do ...@@ -776,6 +835,7 @@ RSpec.describe API::FeatureFlags do
expect(json_response).to eq({ expect(json_response).to eq({
'name' => 'feature1', 'name' => 'feature1',
'description' => 'new description', 'description' => 'new description',
'active' => true,
'created_at' => feature_flag.created_at.as_json, 'created_at' => feature_flag.created_at.as_json,
'updated_at' => feature_flag.updated_at.as_json, 'updated_at' => feature_flag.updated_at.as_json,
'scopes' => [], 'scopes' => [],
......
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