Commit e825300e authored by James Lopez's avatar James Lopez

Merge branch 'sarnold-197129-graphql-feature-flag' into 'master'

Add ability hide GraphQL fields via feature flag

See merge request gitlab-org/gitlab!23563
parents 6a9fb294 ee1870c4
......@@ -10,6 +10,8 @@ module Types
@calls_gitaly = !!kwargs.delete(:calls_gitaly)
@constant_complexity = !!kwargs[:complexity]
kwargs[:complexity] ||= field_complexity(kwargs[:resolver_class])
@feature_flag = kwargs[:feature_flag]
kwargs = check_feature_flag(kwargs)
super(*args, **kwargs, &block)
end
......@@ -28,8 +30,27 @@ module Types
@constant_complexity
end
def visible?(context)
return false if feature_flag.present? && !Feature.enabled?(feature_flag)
super
end
private
attr_reader :feature_flag
def feature_documentation_message(key, description)
"#{description}. Available only when feature flag #{key} is enabled."
end
def check_feature_flag(args)
args[:description] = feature_documentation_message(args[:feature_flag], args[:description]) if args[:feature_flag].present?
args.delete(:feature_flag)
args
end
def field_complexity(resolver_class)
if resolver_class
field_resolver_complexity
......
---
title: Add ability to hide GraphQL fields using GitLab Feature flags
merge_request: 23563
author:
type: added
......@@ -3,6 +3,8 @@
require 'spec_helper'
describe 'Gitlab::Graphql::Authorization' do
include GraphqlHelpers
set(:user) { create(:user) }
let(:permission_single) { :foo }
......@@ -300,37 +302,4 @@ describe 'Gitlab::Graphql::Authorization' do
allow(Ability).to receive(:allowed?).with(user, permission, test_object).and_return(true)
end
end
def type_factory
Class.new(Types::BaseObject) do
graphql_name 'TestType'
field :name, GraphQL::STRING_TYPE, null: true
yield(self) if block_given?
end
end
def query_factory
Class.new(Types::BaseObject) do
graphql_name 'TestQuery'
yield(self) if block_given?
end
end
def execute_query(query_type)
schema = Class.new(GraphQL::Schema) do
use Gitlab::Graphql::Authorize
use Gitlab::Graphql::Connections
query(query_type)
end
schema.execute(
query_string,
context: { current_user: user },
variables: {}
)
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'Graphql Field feature flags' do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let(:feature_flag) { 'test_feature' }
let(:test_object) { double(name: 'My name') }
let(:query_string) { '{ item() { name } }' }
let(:result) { execute_query(query_type)['data'] }
subject { result }
describe 'Feature flagged field' do
let(:type) { type_factory }
let(:query_type) do
query_factory do |query|
query.field :item, type, null: true, feature_flag: feature_flag, resolve: ->(obj, args, ctx) { test_object }
end
end
it 'returns the value when feature is enabled' do
expect(subject['item']).to eq('name' => test_object.name)
end
it 'returns nil when the feature is disabled' do
stub_feature_flags(feature_flag => false)
expect(subject).to be_nil
end
end
end
......@@ -111,5 +111,70 @@ describe Types::BaseField do
end
end
end
describe '#visible?' do
context 'and has a feature_flag' do
let(:flag) { :test_feature }
let(:field) { described_class.new(name: 'test', type: GraphQL::STRING_TYPE, feature_flag: flag, null: false) }
let(:context) { {} }
it 'returns false if the feature is not enabled' do
stub_feature_flags(flag => false)
expect(field.visible?(context)).to eq(false)
end
it 'returns true if the feature is enabled' do
expect(field.visible?(context)).to eq(true)
end
context 'falsey feature_flag values' do
using RSpec::Parameterized::TableSyntax
where(:flag, :feature_value, :visible) do
'' | false | true
'' | true | true
nil | false | true
nil | true | true
end
with_them do
it 'returns the correct value' do
stub_feature_flags(flag => feature_value)
expect(field.visible?(context)).to eq(visible)
end
end
end
end
end
describe '#description' do
context 'feature flag given' do
let(:field) { described_class.new(name: 'test', type: GraphQL::STRING_TYPE, feature_flag: flag, null: false, description: 'Test description') }
let(:flag) { :test_flag }
it 'prepends the description' do
expect(field.description). to eq 'Test description. Available only when feature flag test_flag is enabled.'
end
context 'falsey feature_flag values' do
using RSpec::Parameterized::TableSyntax
where(:flag, :feature_value) do
'' | false
'' | true
nil | false
nil | true
end
with_them do
it 'returns the correct description' do
expect(field.description).to eq('Test description')
end
end
end
end
end
end
end
......@@ -349,6 +349,39 @@ module GraphqlHelpers
def custom_graphql_error(path, msg)
a_hash_including('path' => path, 'message' => msg)
end
def type_factory
Class.new(Types::BaseObject) do
graphql_name 'TestType'
field :name, GraphQL::STRING_TYPE, null: true
yield(self) if block_given?
end
end
def query_factory
Class.new(Types::BaseObject) do
graphql_name 'TestQuery'
yield(self) if block_given?
end
end
def execute_query(query_type)
schema = Class.new(GraphQL::Schema) do
use Gitlab::Graphql::Authorize
use Gitlab::Graphql::Connections
query(query_type)
end
schema.execute(
query_string,
context: { current_user: user },
variables: {}
)
end
end
# This warms our schema, doing this as part of loading the helpers to avoid
......
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