From 94a2e7c8840e2810ce87654163a2a975ca1f76eb Mon Sep 17 00:00:00 2001
From: Luke Duncalfe <lduncalfe@eml.cc>
Date: Thu, 18 Aug 2022 12:53:08 +1200
Subject: [PATCH] Remove GraphQL `feature_flag` property

The property had been renamed to `_deprecated_feature_flag` earlier.

This change removes it altogether and all code that was supporting it.

https://gitlab.com/gitlab-org/gitlab/-/issues/369202
---
 app/graphql/types/base_field.rb               | 31 ------
 doc/development/api_graphql_styleguide.md     |  6 --
 rubocop/code_reuse_helpers.rb                 |  6 --
 rubocop/cop/gitlab/mark_used_feature_flags.rb | 20 +---
 spec/graphql/features/feature_flag_spec.rb    | 52 ----------
 spec/graphql/types/base_field_spec.rb         | 99 -------------------
 spec/rubocop/code_reuse_helpers_spec.rb       | 25 -----
 .../gitlab/mark_used_feature_flags_spec.rb    | 13 ---
 8 files changed, 2 insertions(+), 250 deletions(-)
 delete mode 100644 spec/graphql/features/feature_flag_spec.rb

diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb
index 1c43432594a20..6f64e5b5053e8 100644
--- a/app/graphql/types/base_field.rb
+++ b/app/graphql/types/base_field.rb
@@ -17,8 +17,6 @@ def initialize(**kwargs, &block)
       @requires_argument = !!kwargs.delete(:requires_argument)
       @authorize = Array.wrap(kwargs.delete(:authorize))
       kwargs[:complexity] = field_complexity(kwargs[:resolver_class], kwargs[:complexity])
-      @feature_flag = kwargs[:_deprecated_feature_flag]
-      kwargs = check_feature_flag(kwargs)
       @deprecation = gitlab_deprecation(kwargs)
       after_connection_extensions = kwargs.delete(:late_extensions) || []
 
@@ -91,16 +89,8 @@ def constant_complexity?
       @constant_complexity
     end
 
-    def visible?(context)
-      return false if feature_flag.present? && !Feature.enabled?(feature_flag)
-
-      super
-    end
-
     private
 
-    attr_reader :feature_flag
-
     def field_authorized?(object, ctx)
       object = object.node if object.is_a?(GraphQL::Pagination::Connection::Edge)
 
@@ -123,27 +113,6 @@ def authorization
       @authorization ||= ::Gitlab::Graphql::Authorize::ObjectAuthorization.new(@authorize)
     end
 
-    def feature_documentation_message(key, description)
-      message_parts = ["#{description} Available only when feature flag `#{key}` is enabled."]
-
-      message_parts << if Feature::Definition.has_definition?(key) && Feature::Definition.default_enabled?(key)
-                         "This flag is enabled by default."
-                       else
-                         "This flag is disabled by default, because the feature is experimental and is subject to change without notice."
-                       end
-
-      message_parts.join(' ')
-    end
-
-    def check_feature_flag(args)
-      ff = args.delete(:_deprecated_feature_flag)
-      return args unless ff.present?
-
-      args[:description] = feature_documentation_message(ff, args[:description])
-
-      args
-    end
-
     def field_complexity(resolver_class, current)
       return current if current.present? && current > 0
 
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index 190e853a37663..78ff8fbba36c9 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -546,12 +546,6 @@ def resolve(id: )
 end
 ```
 
-### `feature_flag` property (deprecated)
-
-NOTE:
-This property is deprecated and should no longer be used. The property
-has been temporarily renamed to `_deprecated_feature_flag` and support for it will be removed in [#369202](https://gitlab.com/gitlab-org/gitlab/-/issues/369202).
-
 ## Deprecating schema items
 
 The GitLab GraphQL API is versionless, which means we maintain backwards
diff --git a/rubocop/code_reuse_helpers.rb b/rubocop/code_reuse_helpers.rb
index 2769da2389c82..87b907f87786b 100644
--- a/rubocop/code_reuse_helpers.rb
+++ b/rubocop/code_reuse_helpers.rb
@@ -81,12 +81,6 @@ def in_graphql?(node)
       in_app_directory?(node, 'graphql')
     end
 
-    # Returns true if the given node resides in app/graphql/types,
-    # ee/app/graphql/types, or ee/app/graphql/ee/types.
-    def in_graphql_types?(node)
-      in_graphql_directory?(node, 'types')
-    end
-
     # Returns true if the given node resides in lib/api or ee/lib/api.
     def in_api?(node)
       in_lib_directory?(node, 'api')
diff --git a/rubocop/cop/gitlab/mark_used_feature_flags.rb b/rubocop/cop/gitlab/mark_used_feature_flags.rb
index 63bccec31c056..4844dab0a30b3 100644
--- a/rubocop/cop/gitlab/mark_used_feature_flags.rb
+++ b/rubocop/cop/gitlab/mark_used_feature_flags.rb
@@ -26,9 +26,6 @@ class MarkUsedFeatureFlags < RuboCop::Cop::Cop
           data_consistency
           deduplicate
         ].freeze
-        GRAPHQL_METHODS = %i[
-          field
-        ].freeze
         SELF_METHODS = %i[
           push_frontend_feature_flag
           push_force_frontend_feature_flag
@@ -36,7 +33,7 @@ class MarkUsedFeatureFlags < RuboCop::Cop::Cop
           limit_feature_flag_for_override=
         ].freeze + EXPERIMENT_METHODS + RUGGED_METHODS + WORKER_METHODS
 
-        RESTRICT_ON_SEND = FEATURE_METHODS + EXPERIMENTATION_METHODS + GRAPHQL_METHODS + SELF_METHODS
+        RESTRICT_ON_SEND = FEATURE_METHODS + EXPERIMENTATION_METHODS + SELF_METHODS
 
         USAGE_DATA_COUNTERS_EVENTS_YAML_GLOBS = [
           File.expand_path("../../../config/metrics/aggregates/*.yml", __dir__),
@@ -138,15 +135,6 @@ def flag_arg(node)
             node.children[3].each_pair.find do |pair|
               pair.key.value == :feature_flag
             end&.value
-          elsif graphql_method?(node)
-            return unless node.children.size > 3
-
-            opts_index = node.children[3].hash_type? ? 3 : 4
-            return unless node.children[opts_index]
-
-            node.children[opts_index].each_pair.find do |pair|
-              pair.key.value == :_deprecated_feature_flag
-            end&.value
           else
             arg_index = rugged_method?(node) ? 3 : 2
 
@@ -209,16 +197,12 @@ def worker_method?(node)
           WORKER_METHODS.include?(method_name(node))
         end
 
-        def graphql_method?(node)
-          GRAPHQL_METHODS.include?(method_name(node)) && in_graphql_types?(node)
-        end
-
         def self_method?(node)
           SELF_METHODS.include?(method_name(node)) && class_caller(node).empty?
         end
 
         def trackable_flag?(node)
-          feature_method?(node) || experimentation_method?(node) || graphql_method?(node) || self_method?(node)
+          feature_method?(node) || experimentation_method?(node) || self_method?(node)
         end
 
         # Marking all event's feature flags as used as Gitlab::UsageDataCounters::HLLRedisCounter.track_event{,context}
diff --git a/spec/graphql/features/feature_flag_spec.rb b/spec/graphql/features/feature_flag_spec.rb
deleted file mode 100644
index b06718eb16ae8..0000000000000
--- a/spec/graphql/features/feature_flag_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Graphql Field feature flags' do
-  include GraphqlHelpers
-  include Graphql::ResolverFactories
-
-  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'] }
-
-  before do
-    skip_feature_flags_yaml_validation
-  end
-
-  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, _deprecated_feature_flag: feature_flag, resolver: new_resolver(test_object)
-      end
-    end
-
-    it 'checks YAML definition for default_enabled' do
-      # Exception is indicative of a check for YAML definition
-      expect { subject }.to raise_error(Feature::InvalidFeatureFlagError, /The feature flag YAML definition for '#{feature_flag}' does not exist/)
-    end
-
-    context 'skipping YAML check' do
-      before do
-        skip_default_enabled_yaml_check
-      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
-end
diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb
index b85716e4d2114..9f8a8717efbd4 100644
--- a/spec/graphql/types/base_field_spec.rb
+++ b/spec/graphql/types/base_field_spec.rb
@@ -205,39 +205,6 @@ def self.complexity_multiplier(args)
         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::Types::String, _deprecated_feature_flag: flag, null: false) }
-        let(:context) { {} }
-
-        before do
-          skip_feature_flags_yaml_validation
-        end
-
-        it 'checks YAML definition for default_enabled' do
-          # Exception is indicative of a check for YAML definition
-          expect { field.visible?(context) }.to raise_error(Feature::InvalidFeatureFlagError, /The feature flag YAML definition for '#{flag}' does not exist/)
-        end
-
-        context 'skipping YAML check' do
-          before do
-            skip_default_enabled_yaml_check
-          end
-
-          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
-        end
-      end
-    end
   end
 
   describe '#resolve' do
@@ -251,77 +218,11 @@ def self.complexity_multiplier(args)
     end
   end
 
-  describe '#description' do
-    context 'feature flag given' do
-      let(:field) { described_class.new(name: 'test', type: GraphQL::Types::String, _deprecated_feature_flag: flag, null: false, description: 'Test description.') }
-      let(:flag) { :test_flag }
-
-      it 'prepends the description' do
-        expect(field.description).to start_with '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, :default_enabled) do
-          ''  | false | false
-          ''  | true  | false
-          nil | false | true
-          nil | true  | false
-        end
-
-        with_them do
-          it 'returns the correct description' do
-            expect(field.description).to eq('Test description.')
-          end
-        end
-      end
-
-      context 'with different default_enabled values' do
-        using RSpec::Parameterized::TableSyntax
-
-        where(:feature_value, :default_enabled, :expected_description) do
-          disabled_ff_description = "Test description. Available only when feature flag `test_flag` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice."
-          enabled_ff_description = "Test description. Available only when feature flag `test_flag` is enabled. This flag is enabled by default."
-
-          false | false | disabled_ff_description
-          true  | false | disabled_ff_description
-          false | true  | enabled_ff_description
-          true  | true  | enabled_ff_description
-        end
-
-        with_them do
-          before do
-            stub_feature_flags("#{flag}": feature_value)
-
-            allow(Feature::Definition).to receive(:has_definition?).with(flag).and_return(true)
-            allow(Feature::Definition).to receive(:default_enabled?).and_return(default_enabled)
-          end
-
-          it 'returns the correct availability in the description' do
-            expect(field.description).to eq expected_description
-          end
-        end
-      end
-    end
-  end
-
   include_examples 'Gitlab-style deprecations' do
     def subject(args = {})
       base_args = { name: 'test', type: GraphQL::Types::String, null: true }
 
       described_class.new(**base_args.merge(args))
     end
-
-    it 'interacts well with the `_deprecated_feature_flag` property' do
-      field = subject(
-        deprecated: { milestone: '1.10', reason: 'Deprecation reason' },
-        description: 'Field description.',
-        _deprecated_feature_flag: 'foo_flag'
-      )
-
-      expect(field.description).to start_with('Field description. Available only when feature flag `foo_flag` is enabled.')
-      expect(field.description).to end_with('Deprecated in 1.10: Deprecation reason.')
-    end
   end
 end
diff --git a/spec/rubocop/code_reuse_helpers_spec.rb b/spec/rubocop/code_reuse_helpers_spec.rb
index 5cc396a4e3ef0..a8f935426e693 100644
--- a/spec/rubocop/code_reuse_helpers_spec.rb
+++ b/spec/rubocop/code_reuse_helpers_spec.rb
@@ -172,31 +172,6 @@ def build_and_parse_source(source, path = 'foo.rb')
     end
   end
 
-  describe '#in_graphql_types?' do
-    %w[
-      app/graphql/types
-      ee/app/graphql/ee/types
-      ee/app/graphql/types
-    ].each do |path|
-      it "returns true for a node in #{path}" do
-        node = build_and_parse_source('10', rails_root_join(path, 'foo.rb'))
-
-        expect(cop.in_graphql_types?(node)).to eq(true)
-      end
-    end
-
-    %w[
-      app/graphql/resolvers
-      app/foo
-    ].each do |path|
-      it "returns false for a node in #{path}" do
-        node = build_and_parse_source('10', rails_root_join(path, 'foo.rb'))
-
-        expect(cop.in_graphql_types?(node)).to eq(false)
-      end
-    end
-  end
-
   describe '#in_api?' do
     it 'returns true for a node in the API directory' do
       node = build_and_parse_source('10', rails_root_join('lib', 'api', 'foo.rb'))
diff --git a/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb b/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
index 5f72996a06a00..c61376d77607a 100644
--- a/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
+++ b/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
@@ -212,19 +212,6 @@ class Foo < ApplicationRecord
     include_examples 'does not set any flags as used', 'deduplicate :delayed'
   end
 
-  describe 'GraphQL `field` method' do
-    before do
-      allow(cop).to receive(:in_graphql_types?).and_return(true)
-    end
-
-    include_examples 'sets flag as used', 'field :runners, Types::Ci::RunnerType.connection_type, null: true, _deprecated_feature_flag: :foo', 'foo'
-    include_examples 'sets flag as used', 'field :runners, null: true, _deprecated_feature_flag: :foo', 'foo'
-    include_examples 'does not set any flags as used', 'field :solution'
-    include_examples 'does not set any flags as used', 'field :runners, Types::Ci::RunnerType.connection_type'
-    include_examples 'does not set any flags as used', 'field :runners, Types::Ci::RunnerType.connection_type, null: true, description: "hello world"'
-    include_examples 'does not set any flags as used', 'field :solution, type: GraphQL::Types::String, null: true, description: "URL to the vulnerabilitys details page."'
-  end
-
   describe "tracking of usage data metrics known events happens at the beginning of inspection" do
     let(:usage_data_counters_known_event_feature_flags) { ['an_event_feature_flag'] }
 
-- 
GitLab