diff options
Diffstat (limited to 'app/graphql/types')
22 files changed, 317 insertions, 33 deletions
diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb index 2b2ea64c00b..dd0d9105df6 100644 --- a/app/graphql/types/base_field.rb +++ b/app/graphql/types/base_field.rb @@ -3,5 +3,47 @@ module Types class BaseField < GraphQL::Schema::Field prepend Gitlab::Graphql::Authorize + + DEFAULT_COMPLEXITY = 1 + + def initialize(*args, **kwargs, &block) + kwargs[:complexity] ||= field_complexity(kwargs[:resolver_class]) + + super(*args, **kwargs, &block) + end + + private + + def field_complexity(resolver_class) + if resolver_class + field_resolver_complexity + else + DEFAULT_COMPLEXITY + end + end + + def field_resolver_complexity + # Complexity can be either integer or proc. If proc is used then it's + # called when computing a query complexity and context and query + # arguments are available for computing complexity. For resolvers we use + # proc because we set complexity depending on arguments and number of + # items which can be loaded. + proc do |ctx, args, child_complexity| + # Resolvers may add extra complexity depending on used arguments + complexity = child_complexity + self.resolver&.try(:resolver_complexity, args, child_complexity: child_complexity).to_i + + field_defn = to_graphql + + if field_defn.connection? + # Resolvers may add extra complexity depending on number of items being loaded. + page_size = field_defn.connection_max_page_size || ctx.schema.default_max_page_size + limit_value = [args[:first], args[:last], page_size].compact.min + multiplier = self.resolver&.try(:complexity_multiplier, args).to_f + complexity += complexity * limit_value * multiplier + end + + complexity.to_i + end + end end end diff --git a/app/graphql/types/base_object.rb b/app/graphql/types/base_object.rb index 82b78abd573..e40059c46bb 100644 --- a/app/graphql/types/base_object.rb +++ b/app/graphql/types/base_object.rb @@ -6,5 +6,10 @@ module Types prepend Gitlab::Graphql::ExposePermissions field_class Types::BaseField + + # All graphql fields exposing an id, should expose a global id. + def id + GitlabSchema.id_from_object(object) + end end end diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb new file mode 100644 index 00000000000..2987354b556 --- /dev/null +++ b/app/graphql/types/ci/detailed_status_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +module Types + module Ci + class DetailedStatusType < BaseObject + graphql_name 'DetailedStatus' + + field :group, GraphQL::STRING_TYPE, null: false + field :icon, GraphQL::STRING_TYPE, null: false + field :favicon, GraphQL::STRING_TYPE, null: false + field :details_path, GraphQL::STRING_TYPE, null: false + field :has_details, GraphQL::BOOLEAN_TYPE, null: false, method: :has_details? + field :label, GraphQL::STRING_TYPE, null: false + field :text, GraphQL::STRING_TYPE, null: false + field :tooltip, GraphQL::STRING_TYPE, null: false, method: :status_tooltip + end + end +end diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb index 2bbffad4563..cff81e5670b 100644 --- a/app/graphql/types/ci/pipeline_type.rb +++ b/app/graphql/types/ci/pipeline_type.rb @@ -3,16 +3,22 @@ module Types module Ci class PipelineType < BaseObject - expose_permissions Types::PermissionTypes::Ci::Pipeline - graphql_name 'Pipeline' + authorize :read_pipeline + + expose_permissions Types::PermissionTypes::Ci::Pipeline + field :id, GraphQL::ID_TYPE, null: false - field :iid, GraphQL::ID_TYPE, null: false + field :iid, GraphQL::STRING_TYPE, null: false field :sha, GraphQL::STRING_TYPE, null: false field :before_sha, GraphQL::STRING_TYPE, null: true field :status, PipelineStatusEnum, null: false + field :detailed_status, + Types::Ci::DetailedStatusType, + null: false, + resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) } field :duration, GraphQL::INT_TYPE, null: true, diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb new file mode 100644 index 00000000000..530aecc2bf9 --- /dev/null +++ b/app/graphql/types/group_type.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Types + class GroupType < NamespaceType + graphql_name 'Group' + + authorize :read_group + + expose_permissions Types::PermissionTypes::Group + + field :web_url, GraphQL::STRING_TYPE, null: false + + field :avatar_url, GraphQL::STRING_TYPE, null: true, resolve: -> (group, args, ctx) do + group.avatar_url(only_path: false) + end + + if ::Group.supports_nested_objects? + field :parent, GroupType, + null: true, + resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.parent_id).find } + end + end +end diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 87f6b1f8278..dd5133189dc 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -2,10 +2,12 @@ module Types class IssueType < BaseObject - expose_permissions Types::PermissionTypes::Issue - graphql_name 'Issue' + authorize :read_issue + + expose_permissions Types::PermissionTypes::Issue + present_using IssuePresenter field :iid, GraphQL::ID_TYPE, null: false @@ -13,20 +15,22 @@ module Types field :description, GraphQL::STRING_TYPE, null: true field :state, IssueStateEnum, null: false + field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference do + argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false + end + field :author, Types::UserType, null: false, - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.author_id).find } do - authorize :read_user - end + resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.author_id).find } - field :assignees, Types::UserType.connection_type, null: true + # Remove complexity when BatchLoader is used + field :assignees, Types::UserType.connection_type, null: true, complexity: 5 - field :labels, Types::LabelType.connection_type, null: true + # Remove complexity when BatchLoader is used + field :labels, Types::LabelType.connection_type, null: true, complexity: 5 field :milestone, Types::MilestoneType, null: true, - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, obj.milestone_id).find } do - authorize :read_milestone - end + resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, obj.milestone_id).find } field :due_date, Types::TimeType, null: true field :confidential, GraphQL::BOOLEAN_TYPE, null: false @@ -37,7 +41,9 @@ module Types field :upvotes, GraphQL::INT_TYPE, null: false field :downvotes, GraphQL::INT_TYPE, null: false field :user_notes_count, GraphQL::INT_TYPE, null: false + field :web_path, GraphQL::STRING_TYPE, null: false, method: :issue_path field :web_url, GraphQL::STRING_TYPE, null: false + field :relative_position, GraphQL::INT_TYPE, null: true field :closed_at, Types::TimeType, null: true diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 7827b6e3717..85ac3102442 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -2,14 +2,16 @@ module Types class MergeRequestType < BaseObject + graphql_name 'MergeRequest' + + authorize :read_merge_request + expose_permissions Types::PermissionTypes::MergeRequest present_using MergeRequestPresenter - graphql_name 'MergeRequest' - field :id, GraphQL::ID_TYPE, null: false - field :iid, GraphQL::ID_TYPE, null: false + field :iid, GraphQL::STRING_TYPE, null: false field :title, GraphQL::STRING_TYPE, null: false field :description, GraphQL::STRING_TYPE, null: true field :state, MergeRequestStateEnum, null: false @@ -48,9 +50,7 @@ module Types field :downvotes, GraphQL::INT_TYPE, null: false field :subscribed, GraphQL::BOOLEAN_TYPE, method: :subscribed?, null: false - field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline do - authorize :read_pipeline - end + field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline field :pipelines, Types::Ci::PipelineType.connection_type, resolver: Resolvers::MergeRequestPipelinesResolver end diff --git a/app/graphql/types/metadata_type.rb b/app/graphql/types/metadata_type.rb new file mode 100644 index 00000000000..2d8bad0614b --- /dev/null +++ b/app/graphql/types/metadata_type.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Types + class MetadataType < ::Types::BaseObject + graphql_name 'Metadata' + + field :version, GraphQL::STRING_TYPE, null: false + field :revision, GraphQL::STRING_TYPE, null: false + end +end diff --git a/app/graphql/types/milestone_type.rb b/app/graphql/types/milestone_type.rb index af31b572c9a..2772fbec86f 100644 --- a/app/graphql/types/milestone_type.rb +++ b/app/graphql/types/milestone_type.rb @@ -4,6 +4,8 @@ module Types class MilestoneType < BaseObject graphql_name 'Milestone' + authorize :read_milestone + field :description, GraphQL::STRING_TYPE, null: true field :title, GraphQL::STRING_TYPE, null: false field :state, GraphQL::STRING_TYPE, null: false diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb new file mode 100644 index 00000000000..f6d91320e50 --- /dev/null +++ b/app/graphql/types/namespace_type.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Types + class NamespaceType < BaseObject + graphql_name 'Namespace' + + field :id, GraphQL::ID_TYPE, null: false + + field :name, GraphQL::STRING_TYPE, null: false + field :path, GraphQL::STRING_TYPE, null: false + field :full_name, GraphQL::STRING_TYPE, null: false + field :full_path, GraphQL::ID_TYPE, null: false + + field :description, GraphQL::STRING_TYPE, null: true + field :visibility, GraphQL::STRING_TYPE, null: true + field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true, method: :lfs_enabled? + field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true + + field :projects, + Types::ProjectType.connection_type, + null: false, + resolver: ::Resolvers::NamespaceProjectsResolver + end +end diff --git a/app/graphql/types/permission_types/group.rb b/app/graphql/types/permission_types/group.rb new file mode 100644 index 00000000000..29833993ce6 --- /dev/null +++ b/app/graphql/types/permission_types/group.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Types + module PermissionTypes + class Group < BasePermissionType + graphql_name 'GroupPermissions' + + abilities :read_group + end + end +end diff --git a/app/graphql/types/project_statistics_type.rb b/app/graphql/types/project_statistics_type.rb new file mode 100644 index 00000000000..62537361918 --- /dev/null +++ b/app/graphql/types/project_statistics_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Types + class ProjectStatisticsType < BaseObject + graphql_name 'ProjectStatistics' + + field :commit_count, GraphQL::INT_TYPE, null: false + + field :storage_size, GraphQL::INT_TYPE, null: false + field :repository_size, GraphQL::INT_TYPE, null: false + field :lfs_objects_size, GraphQL::INT_TYPE, null: false + field :build_artifacts_size, GraphQL::INT_TYPE, null: false + field :packages_size, GraphQL::INT_TYPE, null: false + field :wiki_size, GraphQL::INT_TYPE, null: true + end +end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index d25c8c8bd90..2236ffa394d 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -2,10 +2,12 @@ module Types class ProjectType < BaseObject - expose_permissions Types::PermissionTypes::Project - graphql_name 'Project' + authorize :read_project + + expose_permissions Types::PermissionTypes::Project + field :id, GraphQL::ID_TYPE, null: false field :full_path, GraphQL::ID_TYPE, null: false @@ -16,7 +18,6 @@ module Types field :description, GraphQL::STRING_TYPE, null: true - field :default_branch, GraphQL::STRING_TYPE, null: true field :tag_list, GraphQL::STRING_TYPE, null: true field :ssh_url_to_repo, GraphQL::STRING_TYPE, null: true @@ -59,26 +60,30 @@ module Types end field :import_status, GraphQL::STRING_TYPE, null: true - field :ci_config_path, GraphQL::STRING_TYPE, null: true field :only_allow_merge_if_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::BOOLEAN_TYPE, null: true field :printing_merge_request_link_enabled, GraphQL::BOOLEAN_TYPE, null: true + field :namespace, Types::NamespaceType, null: false + field :group, Types::GroupType, null: true + + field :statistics, Types::ProjectStatisticsType, + null: false, + resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchProjectStatisticsLoader.new(obj.id).find } + + field :repository, Types::RepositoryType, null: false + field :merge_requests, Types::MergeRequestType.connection_type, null: true, - resolver: Resolvers::MergeRequestsResolver do - authorize :read_merge_request - end + resolver: Resolvers::MergeRequestsResolver field :merge_request, Types::MergeRequestType, null: true, - resolver: Resolvers::MergeRequestsResolver.single do - authorize :read_merge_request - end + resolver: Resolvers::MergeRequestsResolver.single field :issues, Types::IssueType.connection_type, @@ -92,7 +97,7 @@ module Types field :pipelines, Types::Ci::PipelineType.connection_type, - null: false, + null: true, resolver: Resolvers::ProjectPipelinesResolver end end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 7c41716b82a..536bdb077ad 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -1,14 +1,30 @@ # frozen_string_literal: true module Types - class QueryType < BaseObject + class QueryType < ::Types::BaseObject graphql_name 'Query' field :project, Types::ProjectType, null: true, resolver: Resolvers::ProjectResolver, - description: "Find a project" do - authorize :read_project + description: "Find a project" + + field :group, Types::GroupType, + null: true, + resolver: Resolvers::GroupResolver, + description: "Find a group" + + field :namespace, Types::NamespaceType, + null: true, + resolver: Resolvers::NamespaceResolver, + description: "Find a namespace" + + field :metadata, Types::MetadataType, + null: true, + resolver: Resolvers::MetadataResolver, + description: 'Metadata about GitLab' do |*args| + + authorize :read_instance_metadata end field :echo, GraphQL::STRING_TYPE, null: false, function: Functions::Echo.new diff --git a/app/graphql/types/repository_type.rb b/app/graphql/types/repository_type.rb new file mode 100644 index 00000000000..5987467e1ea --- /dev/null +++ b/app/graphql/types/repository_type.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Types + class RepositoryType < BaseObject + graphql_name 'Repository' + + authorize :download_code + + field :root_ref, GraphQL::STRING_TYPE, null: true + field :empty, GraphQL::BOOLEAN_TYPE, null: false, method: :empty? + field :exists, GraphQL::BOOLEAN_TYPE, null: false, method: :exists? + field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver + end +end diff --git a/app/graphql/types/tree/blob_type.rb b/app/graphql/types/tree/blob_type.rb new file mode 100644 index 00000000000..f2b7d5df2b2 --- /dev/null +++ b/app/graphql/types/tree/blob_type.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true +module Types + module Tree + class BlobType < BaseObject + implements Types::Tree::EntryType + + present_using BlobPresenter + + graphql_name 'Blob' + + field :web_url, GraphQL::STRING_TYPE, null: true + end + end +end diff --git a/app/graphql/types/tree/entry_type.rb b/app/graphql/types/tree/entry_type.rb new file mode 100644 index 00000000000..d8e8642ddb8 --- /dev/null +++ b/app/graphql/types/tree/entry_type.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true +module Types + module Tree + module EntryType + include Types::BaseInterface + + field :id, GraphQL::ID_TYPE, null: false + field :name, GraphQL::STRING_TYPE, null: false + field :type, Tree::TypeEnum, null: false + field :path, GraphQL::STRING_TYPE, null: false + field :flat_path, GraphQL::STRING_TYPE, null: false + end + end +end diff --git a/app/graphql/types/tree/submodule_type.rb b/app/graphql/types/tree/submodule_type.rb new file mode 100644 index 00000000000..cea76dbfd2a --- /dev/null +++ b/app/graphql/types/tree/submodule_type.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +module Types + module Tree + class SubmoduleType < BaseObject + implements Types::Tree::EntryType + + graphql_name 'Submodule' + end + end +end diff --git a/app/graphql/types/tree/tree_entry_type.rb b/app/graphql/types/tree/tree_entry_type.rb new file mode 100644 index 00000000000..23ec2ef0ec2 --- /dev/null +++ b/app/graphql/types/tree/tree_entry_type.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +module Types + module Tree + class TreeEntryType < BaseObject + implements Types::Tree::EntryType + + present_using TreeEntryPresenter + + graphql_name 'TreeEntry' + description 'Represents a directory' + + field :web_url, GraphQL::STRING_TYPE, null: true + end + end +end diff --git a/app/graphql/types/tree/tree_type.rb b/app/graphql/types/tree/tree_type.rb new file mode 100644 index 00000000000..1ee93ed9542 --- /dev/null +++ b/app/graphql/types/tree/tree_type.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +module Types + module Tree + class TreeType < BaseObject + graphql_name 'Tree' + + field :trees, Types::Tree::TreeEntryType.connection_type, null: false, resolve: -> (obj, args, ctx) do + Gitlab::Graphql::Representation::TreeEntry.decorate(obj.trees, obj.repository) + end + + field :submodules, Types::Tree::SubmoduleType.connection_type, null: false + + field :blobs, Types::Tree::BlobType.connection_type, null: false, resolve: -> (obj, args, ctx) do + Gitlab::Graphql::Representation::TreeEntry.decorate(obj.blobs, obj.repository) + end + end + end +end diff --git a/app/graphql/types/tree/type_enum.rb b/app/graphql/types/tree/type_enum.rb new file mode 100644 index 00000000000..6560d91e9e5 --- /dev/null +++ b/app/graphql/types/tree/type_enum.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Types + module Tree + class TypeEnum < BaseEnum + graphql_name 'EntryType' + description 'Type of a tree entry' + + value 'tree', value: :tree + value 'blob', value: :blob + value 'commit', value: :commit + end + end +end diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb index a13e65207df..6b53554314b 100644 --- a/app/graphql/types/user_type.rb +++ b/app/graphql/types/user_type.rb @@ -4,6 +4,8 @@ module Types class UserType < BaseObject graphql_name 'User' + authorize :read_user + present_using UserPresenter field :name, GraphQL::STRING_TYPE, null: false |