diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-06 06:07:26 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-06 06:07:26 +0300 |
commit | 5e448ff06309854c838fb5eaa46fd05ebc5218ab (patch) | |
tree | 0fd59db933c6f11053028559a8f6fc2e2b050f6e /app | |
parent | bdad4dd5dabec7a0a611d5241fa2d56359884420 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/graphql_controller.rb | 36 | ||||
-rw-r--r-- | app/graphql/cached_introspection_query.rb | 107 | ||||
-rw-r--r-- | app/models/integration.rb | 7 | ||||
-rw-r--r-- | app/models/project.rb | 23 |
4 files changed, 168 insertions, 5 deletions
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb index ff4fce9ad1e..11ac641419f 100644 --- a/app/controllers/graphql_controller.rb +++ b/app/controllers/graphql_controller.rb @@ -12,6 +12,9 @@ class GraphqlController < ApplicationController # Max size of the query text in characters MAX_QUERY_SIZE = 10_000 + # The query string of a standard IntrospectionQuery, used to compare incoming requests for caching + CACHED_INTROSPECTION_QUERY_STRING = CachedIntrospectionQuery.query_string + # If a user is using their session to access GraphQL, we need to have session # storage, since the admin-mode check is session wide. # We can't enable this for anonymous users because that would cause users using @@ -54,7 +57,12 @@ class GraphqlController < ApplicationController urgency :low, [:execute] def execute - result = multiplex? ? execute_multiplex : execute_query + result = if Feature.enabled?(:cache_introspection_query) && params[:operationName] == 'IntrospectionQuery' + execute_introspection_query + else + multiplex? ? execute_multiplex : execute_query + end + render json: result end @@ -259,4 +267,30 @@ class GraphqlController < ApplicationController def logs RequestStore.store[:graphql_logs].to_a end + + def execute_introspection_query + if introspection_query_can_use_cache? + # Context for caching: https://gitlab.com/gitlab-org/gitlab/-/issues/409448 + Rails.cache.fetch( + introspection_query_cache_key, + expires_in: 1.day) do + execute_query.to_json + end + else + execute_query + end + end + + def introspection_query_can_use_cache? + graphql_query = GraphQL::Query.new(GitlabSchema, query: query, variables: build_variables(params[:variables])) + + CACHED_INTROSPECTION_QUERY_STRING == graphql_query.query_string.squish + end + + def introspection_query_cache_key + # We use context[:remove_deprecated] here as an introspection query result can differ based on the + # visibility of schema items. Visibility can be affected by the remove_deprecated param. For more context, see: + # https://gitlab.com/gitlab-org/gitlab/-/issues/409448#note_1377558096 + ['introspection-query-cache', Gitlab.revision, context[:remove_deprecated]] + end end diff --git a/app/graphql/cached_introspection_query.rb b/app/graphql/cached_introspection_query.rb new file mode 100644 index 00000000000..f2b98426714 --- /dev/null +++ b/app/graphql/cached_introspection_query.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +module CachedIntrospectionQuery + def self.query_string + <<~QUERY.squish + query IntrospectionQuery { + __schema { + queryType { + name + } + mutationType { + name + } + subscriptionType { + name + } + types { + ...FullType + } + directives { + name + description + locations + args { + ...InputValue + } + } + } + } + + fragment FullType on __Type { + kind + name + description + fields(includeDeprecated: true) { + name + description + args { + ...InputValue + } + type { + ...TypeRef + } + isDeprecated + deprecationReason + } + inputFields { + ...InputValue + } + interfaces { + ...TypeRef + } + enumValues(includeDeprecated: true) { + name + description + isDeprecated + deprecationReason + } + possibleTypes { + ...TypeRef + } + } + + fragment InputValue on __InputValue { + name + description + type { + ...TypeRef + } + defaultValue + } + + fragment TypeRef on __Type { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + } + } + } + } + } + } + } + } + QUERY + end +end diff --git a/app/models/integration.rb b/app/models/integration.rb index 43e923511bb..fa3a47f8936 100644 --- a/app/models/integration.rb +++ b/app/models/integration.rb @@ -28,7 +28,7 @@ class Integration < ApplicationRecord # TODO Shimo is temporary disabled on group and instance-levels. # See: https://gitlab.com/gitlab-org/gitlab/-/issues/345677 PROJECT_SPECIFIC_INTEGRATION_NAMES = %w[ - apple_app_store google_play jenkins shimo + apple_app_store gitlab_slack_application google_play jenkins shimo ].freeze # Fake integrations to help with local development. @@ -282,7 +282,6 @@ class Integration < ApplicationRecord # Returns a list of available integration names. # Example: ["asana", ...] - # @deprecated def self.available_integration_names(include_project_specific: true, include_dev: true) names = integration_names names += project_specific_integration_names if include_project_specific @@ -302,7 +301,9 @@ class Integration < ApplicationRecord end def self.project_specific_integration_names - PROJECT_SPECIFIC_INTEGRATION_NAMES + names = PROJECT_SPECIFIC_INTEGRATION_NAMES.dup + names.delete('gitlab_slack_application') unless Gitlab::CurrentSettings.slack_app_enabled || Rails.env.test? + names end # Returns a list of available integration types. diff --git a/app/models/project.rb b/app/models/project.rb index 05e61e70853..e5278f7f1ea 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -195,6 +195,7 @@ class Project < ApplicationRecord has_one :emails_on_push_integration, class_name: 'Integrations::EmailsOnPush' has_one :ewm_integration, class_name: 'Integrations::Ewm' has_one :external_wiki_integration, class_name: 'Integrations::ExternalWiki' + has_one :gitlab_slack_application_integration, class_name: 'Integrations::GitlabSlackApplication' has_one :google_play_integration, class_name: 'Integrations::GooglePlay' has_one :hangouts_chat_integration, class_name: 'Integrations::HangoutsChat' has_one :harbor_integration, class_name: 'Integrations::Harbor' @@ -796,6 +797,20 @@ class Project < ApplicationRecord preload(:project_feature, :route, :creator, group: :parent, namespace: [:route, :owner]) end + def self.with_slack_application_disabled + # Using Arel to avoid exposing what the column backing the type: attribute is + # rubocop: disable GitlabSecurity/PublicSend + with_active_slack = Integration.active.by_name(:gitlab_slack_application) + join_contraint = arel_table[:id].eq(Integration.arel_table[:project_id]) + constraint = with_active_slack.where_clause.send(:predicates).reduce(join_contraint) { |a, b| a.and(b) } + join = arel_table.join(Integration.arel_table, Arel::Nodes::OuterJoin).on(constraint).join_sources + # rubocop: enable GitlabSecurity/PublicSend + + joins(join).where(integrations: { id: nil }) + rescue Integration::UnknownType + all + end + def self.eager_load_namespace_and_owner includes(namespace: :owner) end @@ -1707,7 +1722,13 @@ class Project < ApplicationRecord end def disabled_integrations - %w[shimo zentao] + return [] if Rails.env.development? + + names = %w[shimo zentao] + + # The Slack Slash Commands integration is only available for customers who cannot use the GitLab for Slack app. + # The GitLab for Slack app integration is only available when enabled through settings. + names << (Gitlab::CurrentSettings.slack_app_enabled ? 'slack_slash_commands' : 'gitlab_slack_application') end def find_or_initialize_integration(name) |