gitlab-org--gitlab-foss/lib/api/feature_flags.rb

221 lines
8.1 KiB
Ruby

# frozen_string_literal: true
module API
class FeatureFlags < ::API::Base
include PaginationParams
FEATURE_FLAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(name: API::NO_SLASH_URL_PART_REGEX)
feature_category :feature_flags
urgency :low
before do
authorize_read_feature_flags!
end
params do
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
resource :feature_flags do
desc 'List feature flags for a project' do
detail 'Gets all feature flags of the requested project. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
is_array true
tags %w[feature_flags]
end
params do
optional :scope,
type: String,
desc: 'The scope of feature flags, one of: `enabled`, `disabled`',
values: %w[enabled disabled]
use :pagination
end
get do
feature_flags = ::FeatureFlagsFinder
.new(user_project, current_user, declared_params(include_missing: false))
.execute
present_entity(paginate(feature_flags))
end
desc 'Create a new feature flag' do
detail 'Creates a new feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
tags %w[feature_flags]
end
params do
requires :name, type: String, desc: 'The name of the feature flag'
optional :description, type: String, desc: 'The description of the feature flag'
optional :active, type: Boolean, desc: 'The active state of the flag. Defaults to `true`. Supported in GitLab 13.3 and later'
optional :version, type: String, desc: 'The version of the feature flag. Must be `new_version_flag`. Omit to create a Legacy feature flag.'
optional :strategies, type: Array do
requires :name, type: String, desc: 'The strategy name. Can be `default`, `gradualRolloutUserId`, `userWithId`, or `gitlabUserList`. In GitLab 13.5 and later, can be `flexibleRollout`'
requires :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
optional :scopes, type: Array do
requires :environment_scope, type: String, desc: 'The environment scope of the scope'
end
end
end
post do
authorize_create_feature_flag!
attrs = declared_params(include_missing: false)
rename_key(attrs, :scopes, :scopes_attributes)
rename_key(attrs, :strategies, :strategies_attributes)
update_value(attrs, :strategies_attributes) do |strategies|
strategies.map { |s| rename_key(s, :scopes, :scopes_attributes) }
end
result = ::FeatureFlags::CreateService
.new(user_project, current_user, attrs)
.execute
if result[:status] == :success
present_entity(result[:feature_flag])
else
render_api_error!(result[:message], result[:http_status])
end
end
end
params do
requires :feature_flag_name, type: String, desc: 'The name of the feature flag'
end
resource 'feature_flags/:feature_flag_name', requirements: FEATURE_FLAG_ENDPOINT_REQUIREMENTS do
desc 'Get a single feature flag' do
detail 'Gets a single feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
tags %w[feature_flags]
end
get do
authorize_read_feature_flag!
exclude_legacy_flags_check!
present_entity(feature_flag)
end
desc 'Update a feature flag' do
detail 'Updates a feature flag. This feature was introduced in GitLab 13.2.'
success ::API::Entities::FeatureFlag
tags %w[feature_flags]
end
params do
optional :name, type: String, desc: 'The new name of the feature flag. Supported in GitLab 13.3 and later'
optional :description, type: String, desc: 'The description of the feature flag'
optional :active, type: Boolean, desc: 'The active state of the flag. Supported in GitLab 13.3 and later'
optional :strategies, type: Array do
optional :id, type: Integer, desc: 'The feature flag strategy ID'
optional :name, type: String, desc: 'The strategy name'
optional :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
optional :_destroy, type: Boolean, desc: 'Delete the strategy when true'
optional :scopes, type: Array do
optional :id, type: Integer, desc: 'The scope id'
optional :environment_scope, type: String, desc: 'The environment scope of the scope'
optional :_destroy, type: Boolean, desc: 'Delete the scope when true'
end
end
end
put do
authorize_update_feature_flag!
exclude_legacy_flags_check!
render_api_error!('PUT operations are not supported for legacy feature flags', :unprocessable_entity) unless feature_flag.new_version_flag?
attrs = declared_params(include_missing: false)
rename_key(attrs, :strategies, :strategies_attributes)
update_value(attrs, :strategies_attributes) do |strategies|
strategies.map { |s| rename_key(s, :scopes, :scopes_attributes) }
end
result = ::FeatureFlags::UpdateService
.new(user_project, current_user, attrs)
.execute(feature_flag)
if result[:status] == :success
present_entity(result[:feature_flag])
else
render_api_error!(result[:message], result[:http_status])
end
end
desc 'Delete a feature flag' do
detail 'Deletes a feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
tags %w[feature_flags]
end
delete do
authorize_destroy_feature_flag!
result = ::FeatureFlags::DestroyService
.new(user_project, current_user, declared_params(include_missing: false))
.execute(feature_flag)
if result[:status] == :success
present_entity(result[:feature_flag])
else
render_api_error!(result[:message], result[:http_status])
end
end
end
end
helpers do
def authorize_read_feature_flags!
authorize! :read_feature_flag, user_project
end
def authorize_read_feature_flag!
authorize! :read_feature_flag, feature_flag
end
def authorize_create_feature_flag!
authorize! :create_feature_flag, user_project
end
def authorize_update_feature_flag!
authorize! :update_feature_flag, feature_flag
end
def authorize_destroy_feature_flag!
authorize! :destroy_feature_flag, feature_flag
end
def present_entity(result)
present result,
with: ::API::Entities::FeatureFlag
end
def feature_flag
@feature_flag ||= user_project.operations_feature_flags.find_by_name!(params[:feature_flag_name])
end
def project
@project ||= feature_flag.project
end
def new_version_flag_present?
user_project.operations_feature_flags.new_version_flag.find_by_name(params[:name]).present?
end
def rename_key(hash, old_key, new_key)
hash[new_key] = hash.delete(old_key) if hash.key?(old_key)
hash
end
def update_value(hash, key)
hash[key] = yield(hash[key]) if hash.key?(key)
hash
end
def exclude_legacy_flags_check!
unless feature_flag.new_version_flag?
not_found!
end
end
end
end
end