Commit e5f98f8e authored by Sean McGivern's avatar Sean McGivern Committed by Jan Provaznik

Add cop to check GraphQL field/argument description

- Fix typo
- Remove reference to outdated files
- Restrict directories to `app/graphql` and `ee/app/graphql` via
`.rubocop.yml`
- Correct all missing descriptions

Add a comment to disable to the cop for every missing GraphQL
description. When folks backfill the description to satisfy the cop,
they can remove the line.

Since we are now including arguments, and (probably) enums,
this is just called GraphQL Descriptions unless it proves
to be confusing.
parent 14d1a057
......@@ -275,8 +275,15 @@ RSpec/BeSuccessMatcher:
- 'ee/spec/support/shared_examples/controllers/**/*'
- 'spec/support/controllers/**/*'
- 'ee/spec/support/controllers/**/*'
Scalability/FileUploads:
Enabled: true
Include:
- 'lib/api/**/*.rb'
- 'ee/lib/api/**/*.rb'
Graphql/Descriptions:
Enabled: true
Include:
- 'app/graphql/**/*'
- 'ee/app/graphql/**/*'
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2019-05-04 16:01:00 +0000 using RuboCop version 0.68.1.
# on 2019-09-06 13:54:58 +1200 using RuboCop version 0.69.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
......@@ -878,3 +878,7 @@ Style/UnneededSort:
Exclude:
- 'app/models/concerns/resolvable_discussion.rb'
- 'lib/gitlab/highlight.rb'
# Offense count: 197
Graphql/Descriptions:
Enabled: false
......@@ -2,7 +2,7 @@
module Resolvers
class EchoResolver < BaseResolver
argument :text, GraphQL::STRING_TYPE, required: true
argument :text, GraphQL::STRING_TYPE, required: true # rubocop:disable Graphql/Descriptions
description 'Testing endpoint to validate the API with'
def resolve(**args)
......
......@@ -33,9 +33,9 @@ module Resolvers
argument :closed_after, Types::TimeType,
required: false,
description: "Issues closed after this date"
argument :search, GraphQL::STRING_TYPE,
argument :search, GraphQL::STRING_TYPE, # rubocop:disable Graphql/Descriptions
required: false
argument :sort, Types::Sort,
argument :sort, Types::Sort, # rubocop:disable Graphql/Descriptions
required: false,
default_value: 'created_desc'
......
......@@ -6,14 +6,14 @@ module Types
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
field :group, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :icon, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :favicon, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :details_path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :has_details, GraphQL::BOOLEAN_TYPE, null: false, method: :has_details? # rubocop:disable Graphql/Descriptions
field :label, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :text, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :tooltip, GraphQL::STRING_TYPE, null: false, method: :status_tooltip # rubocop:disable Graphql/Descriptions
end
# rubocop: enable Graphql/AuthorizeTypes
end
......
......@@ -9,13 +9,13 @@ module Types
expose_permissions Types::PermissionTypes::Ci::Pipeline
field :id, GraphQL::ID_TYPE, null: false
field :iid, GraphQL::STRING_TYPE, null: false
field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :iid, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :sha, GraphQL::STRING_TYPE, null: false
field :before_sha, GraphQL::STRING_TYPE, null: true
field :status, PipelineStatusEnum, null: false
field :detailed_status,
field :sha, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :before_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :status, PipelineStatusEnum, null: false # rubocop:disable Graphql/Descriptions
field :detailed_status, # rubocop:disable Graphql/Descriptions
Types::Ci::DetailedStatusType,
null: false,
resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) }
......@@ -27,11 +27,11 @@ module Types
GraphQL::FLOAT_TYPE,
null: true,
description: "Coverage percentage"
field :created_at, Types::TimeType, null: false
field :updated_at, Types::TimeType, null: false
field :started_at, Types::TimeType, null: true
field :finished_at, Types::TimeType, null: true
field :committed_at, Types::TimeType, null: true
field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
field :started_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
field :finished_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
field :committed_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
# TODO: Add triggering user as a type
end
......
......@@ -8,16 +8,16 @@ module Types
present_using CommitPresenter
field :id, type: GraphQL::ID_TYPE, null: false
field :sha, type: GraphQL::STRING_TYPE, null: false
field :title, type: GraphQL::STRING_TYPE, null: true
field :description, type: GraphQL::STRING_TYPE, null: true
field :message, type: GraphQL::STRING_TYPE, null: true
field :authored_date, type: Types::TimeType, null: true
field :web_url, type: GraphQL::STRING_TYPE, null: false
field :id, type: GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :sha, type: GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :title, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :description, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :message, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :authored_date, type: Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
field :web_url, type: GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
# models/commit lazy loads the author by email
field :author, type: Types::UserType, null: true
field :author, type: Types::UserType, null: true # rubocop:disable Graphql/Descriptions
field :latest_pipeline,
type: Types::Ci::PipelineType,
......
......@@ -8,13 +8,13 @@ module Types
expose_permissions Types::PermissionTypes::Group
field :web_url, GraphQL::STRING_TYPE, null: false
field :web_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :avatar_url, GraphQL::STRING_TYPE, null: true, resolve: -> (group, args, ctx) do
field :avatar_url, GraphQL::STRING_TYPE, null: true, resolve: -> (group, args, ctx) do # rubocop:disable Graphql/Descriptions
group.avatar_url(only_path: false)
end
field :parent, GroupType,
field :parent, GroupType, # rubocop:disable Graphql/Descriptions
null: true,
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.parent_id).find }
end
......
......@@ -12,49 +12,49 @@ module Types
present_using IssuePresenter
field :iid, GraphQL::ID_TYPE, null: false
field :title, GraphQL::STRING_TYPE, null: false
field :iid, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
markdown_field :title_html, null: true
field :description, GraphQL::STRING_TYPE, null: true
field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
markdown_field :description_html, null: true
field :state, IssueStateEnum, null: false
field :state, IssueStateEnum, null: false # rubocop:disable Graphql/Descriptions
field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference do
argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false
field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference do # rubocop:disable Graphql/Descriptions
argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false # rubocop:disable Graphql/Descriptions
end
field :author, Types::UserType,
field :author, Types::UserType, # rubocop:disable Graphql/Descriptions
null: false,
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.author_id).find }
# Remove complexity when BatchLoader is used
field :assignees, Types::UserType.connection_type, null: true, complexity: 5
field :assignees, Types::UserType.connection_type, null: true, complexity: 5 # rubocop:disable Graphql/Descriptions
# Remove complexity when BatchLoader is used
field :labels, Types::LabelType.connection_type, null: true, complexity: 5
field :milestone, Types::MilestoneType,
field :labels, Types::LabelType.connection_type, null: true, complexity: 5 # rubocop:disable Graphql/Descriptions
field :milestone, Types::MilestoneType, # rubocop:disable Graphql/Descriptions
null: true,
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
field :discussion_locked, GraphQL::BOOLEAN_TYPE,
field :due_date, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
field :confidential, GraphQL::BOOLEAN_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :discussion_locked, GraphQL::BOOLEAN_TYPE, # rubocop:disable Graphql/Descriptions
null: false,
resolve: -> (obj, _args, _ctx) { !!obj.discussion_locked }
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 :upvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :downvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :user_notes_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :web_path, GraphQL::STRING_TYPE, null: false, method: :issue_path # rubocop:disable Graphql/Descriptions
field :web_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :relative_position, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :closed_at, Types::TimeType, null: true
field :closed_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
field :created_at, Types::TimeType, null: false
field :updated_at, Types::TimeType, null: false
field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
field :task_completion_status, Types::TaskCompletionStatus, null: false
field :task_completion_status, Types::TaskCompletionStatus, null: false # rubocop:disable Graphql/Descriptions
end
end
......
......@@ -6,10 +6,10 @@ module Types
authorize :read_label
field :description, GraphQL::STRING_TYPE, null: true
field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
markdown_field :description_html, null: true
field :title, GraphQL::STRING_TYPE, null: false
field :color, GraphQL::STRING_TYPE, null: false
field :text_color, GraphQL::STRING_TYPE, null: false
field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :color, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :text_color, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
end
end
......@@ -12,53 +12,55 @@ module Types
present_using MergeRequestPresenter
field :id, GraphQL::ID_TYPE, null: false
field :iid, GraphQL::STRING_TYPE, null: false
field :title, GraphQL::STRING_TYPE, null: false
field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :iid, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
markdown_field :title_html, null: true
field :description, GraphQL::STRING_TYPE, null: true
field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
markdown_field :description_html, null: true
field :state, MergeRequestStateEnum, null: false
field :created_at, Types::TimeType, null: false
field :updated_at, Types::TimeType, null: false
field :source_project, Types::ProjectType, null: true
field :target_project, Types::ProjectType, null: false
field :diff_refs, Types::DiffRefsType, null: true
field :state, MergeRequestStateEnum, null: false # rubocop:disable Graphql/Descriptions
field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
field :source_project, Types::ProjectType, null: true # rubocop:disable Graphql/Descriptions
field :target_project, Types::ProjectType, null: false # rubocop:disable Graphql/Descriptions
field :diff_refs, Types::DiffRefsType, null: true # rubocop:disable Graphql/Descriptions
# Alias for target_project
field :project, Types::ProjectType, null: false
field :project_id, GraphQL::INT_TYPE, null: false, method: :target_project_id
field :source_project_id, GraphQL::INT_TYPE, null: true
field :target_project_id, GraphQL::INT_TYPE, null: false
field :source_branch, GraphQL::STRING_TYPE, null: false
field :target_branch, GraphQL::STRING_TYPE, null: false
field :work_in_progress, GraphQL::BOOLEAN_TYPE, method: :work_in_progress?, null: false
field :merge_when_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true
field :diff_head_sha, GraphQL::STRING_TYPE, null: true
field :merge_commit_sha, GraphQL::STRING_TYPE, null: true
field :user_notes_count, GraphQL::INT_TYPE, null: true
field :should_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :should_remove_source_branch?, null: true
field :force_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :force_remove_source_branch?, null: true
field :merge_status, GraphQL::STRING_TYPE, null: true
field :in_progress_merge_commit_sha, GraphQL::STRING_TYPE, null: true
field :merge_error, GraphQL::STRING_TYPE, null: true
field :allow_collaboration, GraphQL::BOOLEAN_TYPE, null: true
field :should_be_rebased, GraphQL::BOOLEAN_TYPE, method: :should_be_rebased?, null: false
field :rebase_commit_sha, GraphQL::STRING_TYPE, null: true
field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true
field :project, Types::ProjectType, null: false # rubocop:disable Graphql/Descriptions
field :project_id, GraphQL::INT_TYPE, null: false, method: :target_project_id # rubocop:disable Graphql/Descriptions
field :source_project_id, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :target_project_id, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :source_branch, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :target_branch, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :work_in_progress, GraphQL::BOOLEAN_TYPE, method: :work_in_progress?, null: false # rubocop:disable Graphql/Descriptions
field :merge_when_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :diff_head_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :merge_commit_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :user_notes_count, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :should_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :should_remove_source_branch?, null: true # rubocop:disable Graphql/Descriptions
field :force_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :force_remove_source_branch?, null: true # rubocop:disable Graphql/Descriptions
field :merge_status, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :in_progress_merge_commit_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :merge_error, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :allow_collaboration, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :should_be_rebased, GraphQL::BOOLEAN_TYPE, method: :should_be_rebased?, null: false # rubocop:disable Graphql/Descriptions
field :rebase_commit_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true # rubocop:disable Graphql/Descriptions
# rubocop:disable Graphql/Descriptions
field :merge_commit_message, GraphQL::STRING_TYPE, method: :default_merge_commit_message, null: true, deprecation_reason: "Renamed to defaultMergeCommitMessage"
field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true
field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false
field :source_branch_exists, GraphQL::BOOLEAN_TYPE, method: :source_branch_exists?, null: false
field :mergeable_discussions_state, GraphQL::BOOLEAN_TYPE, null: true
field :web_url, GraphQL::STRING_TYPE, null: true
field :upvotes, GraphQL::INT_TYPE, null: false
field :downvotes, GraphQL::INT_TYPE, null: false
field :subscribed, GraphQL::BOOLEAN_TYPE, method: :subscribed?, null: false
# rubocop:enable Graphql/Descriptions
field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false # rubocop:disable Graphql/Descriptions
field :source_branch_exists, GraphQL::BOOLEAN_TYPE, method: :source_branch_exists?, null: false # rubocop:disable Graphql/Descriptions
field :mergeable_discussions_state, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :web_url, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :upvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :downvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :subscribed, GraphQL::BOOLEAN_TYPE, method: :subscribed?, null: false # rubocop:disable Graphql/Descriptions
field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline
field :pipelines, Types::Ci::PipelineType.connection_type,
field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline # rubocop:disable Graphql/Descriptions
field :pipelines, Types::Ci::PipelineType.connection_type, # rubocop:disable Graphql/Descriptions
resolver: Resolvers::MergeRequestPipelinesResolver
field :task_completion_status, Types::TaskCompletionStatus, null: false
field :task_completion_status, Types::TaskCompletionStatus, null: false # rubocop:disable Graphql/Descriptions
end
end
......@@ -6,7 +6,7 @@ module Types
authorize :read_instance_metadata
field :version, GraphQL::STRING_TYPE, null: false
field :revision, GraphQL::STRING_TYPE, null: false
field :version, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :revision, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
end
end
......@@ -6,14 +6,14 @@ module Types
authorize :read_milestone
field :description, GraphQL::STRING_TYPE, null: true
field :title, GraphQL::STRING_TYPE, null: false
field :state, GraphQL::STRING_TYPE, null: false
field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :state, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :due_date, Types::TimeType, null: true
field :start_date, Types::TimeType, null: true
field :due_date, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
field :start_date, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
field :created_at, Types::TimeType, null: false
field :updated_at, Types::TimeType, null: false
field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
end
end
......@@ -6,25 +6,25 @@ module Types
authorize :read_namespace
field :id, GraphQL::ID_TYPE, null: false
field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
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 :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :full_name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :full_path, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :description, GraphQL::STRING_TYPE, null: true
field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
markdown_field :description_html, 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 :visibility, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true, method: :lfs_enabled? # rubocop:disable Graphql/Descriptions
field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :root_storage_statistics, Types::RootStorageStatisticsType,
null: true,
description: 'The aggregated storage statistics. Only available for root namespaces',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchRootStorageStatisticsLoader.new(obj.id).find }
field :projects,
field :projects, # rubocop:disable Graphql/Descriptions
Types::ProjectType.connection_type,
null: false,
resolver: ::Resolvers::NamespaceProjectsResolver
......
......@@ -7,7 +7,7 @@ module Types
class DiffPositionType < BaseObject
graphql_name 'DiffPosition'
field :diff_refs, Types::DiffRefsType, null: false
field :diff_refs, Types::DiffRefsType, null: false # rubocop:disable Graphql/Descriptions
field :file_path, GraphQL::STRING_TYPE, null: false,
description: "The path of the file that was changed"
......@@ -15,7 +15,7 @@ module Types
description: "The path of the file on the start sha."
field :new_path, GraphQL::STRING_TYPE, null: true,
description: "The path of the file on the head sha."
field :position_type, Types::Notes::PositionTypeEnum, null: false
field :position_type, Types::Notes::PositionTypeEnum, null: false # rubocop:disable Graphql/Descriptions
# Fields for text positions
field :old_line, GraphQL::INT_TYPE, null: true,
......
......@@ -7,9 +7,9 @@ module Types
authorize :read_note
field :id, GraphQL::ID_TYPE, null: false
field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :reply_id, GraphQL::ID_TYPE, null: false, description: 'The ID used to reply to this discussion'
field :created_at, Types::TimeType, null: false
field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
field :notes, Types::Notes::NoteType.connection_type, null: false, description: "All notes in the discussion"
# The gem we use to generate Global IDs is hard-coded to work with
......
......@@ -9,7 +9,7 @@ module Types
expose_permissions Types::PermissionTypes::Note
field :id, GraphQL::ID_TYPE, null: false
field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :project, Types::ProjectType,
null: true,
......@@ -37,10 +37,10 @@ module Types
markdown_field :body_html, null: true, method: :note
field :created_at, Types::TimeType, null: false
field :updated_at, Types::TimeType, null: false
field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
field :discussion, Types::Notes::DiscussionType, null: true, description: "The discussion this note is a part of"
field :resolvable, GraphQL::BOOLEAN_TYPE, null: false, method: :resolvable?
field :resolvable, GraphQL::BOOLEAN_TYPE, null: false, method: :resolvable? # rubocop:disable Graphql/Descriptions
field :resolved_at, Types::TimeType, null: true, description: "The time the discussion was resolved"
field :position, Types::Notes::DiffPositionType, null: true, description: "The position of this note on a diff"
end
......
......@@ -28,7 +28,7 @@ module Types
description: "Whether or not a user can perform `#{name}` on this resource",
null: false)
field(**kword_args)
field(**kword_args) # rubocop:disable Graphql/Descriptions
end
def self.resolving_keywords?(arguments)
......
......@@ -6,13 +6,13 @@ module Types
authorize :read_statistics
field :commit_count, GraphQL::INT_TYPE, null: false
field :commit_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
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
field :storage_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :repository_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :lfs_objects_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :build_artifacts_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :packages_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :wiki_size, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions
end
end
......@@ -8,95 +8,95 @@ module Types
expose_permissions Types::PermissionTypes::Project
field :id, GraphQL::ID_TYPE, null: false
field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :full_path, GraphQL::ID_TYPE, null: false
field :path, GraphQL::STRING_TYPE, null: false
field :full_path, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :name_with_namespace, GraphQL::STRING_TYPE, null: false
field :name, GraphQL::STRING_TYPE, null: false
field :name_with_namespace, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :description, GraphQL::STRING_TYPE, null: true
field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
markdown_field :description_html, null: true
field :tag_list, GraphQL::STRING_TYPE, null: true
field :tag_list, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :ssh_url_to_repo, GraphQL::STRING_TYPE, null: true
field :http_url_to_repo, GraphQL::STRING_TYPE, null: true
field :web_url, GraphQL::STRING_TYPE, null: true
field :ssh_url_to_repo, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :http_url_to_repo, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :web_url, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :star_count, GraphQL::INT_TYPE, null: false
field :forks_count, GraphQL::INT_TYPE, null: false, calls_gitaly: true # 4 times
field :star_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :forks_count, GraphQL::INT_TYPE, null: false, calls_gitaly: true # 4 times # rubocop:disable Graphql/Descriptions
field :created_at, Types::TimeType, null: true
field :last_activity_at, Types::TimeType, null: true
field :created_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
field :last_activity_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
field :archived, GraphQL::BOOLEAN_TYPE, null: true
field :archived, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :visibility, GraphQL::STRING_TYPE, null: true
field :visibility, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :container_registry_enabled, GraphQL::BOOLEAN_TYPE, null: true
field :shared_runners_enabled, GraphQL::BOOLEAN_TYPE, null: true
field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true
field :merge_requests_ff_only_enabled, GraphQL::BOOLEAN_TYPE, null: true
field :container_registry_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :shared_runners_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :merge_requests_ff_only_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :avatar_url, GraphQL::STRING_TYPE, null: true, calls_gitaly: true, resolve: -> (project, args, ctx) do
field :avatar_url, GraphQL::STRING_TYPE, null: true, calls_gitaly: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions
project.avatar_url(only_path: false)
end
%i[issues merge_requests wiki snippets].each do |feature|
field "#{feature}_enabled", GraphQL::BOOLEAN_TYPE, null: true, resolve: -> (project, args, ctx) do
field "#{feature}_enabled", GraphQL::BOOLEAN_TYPE, null: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions
project.feature_available?(feature, ctx[:current_user])
end
end
field :jobs_enabled, GraphQL::BOOLEAN_TYPE, null: true, resolve: -> (project, args, ctx) do
field :jobs_enabled, GraphQL::BOOLEAN_TYPE, null: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions
project.feature_available?(:builds, ctx[:current_user])
end
field :public_jobs, GraphQL::BOOLEAN_TYPE, method: :public_builds, null: true
field :public_jobs, GraphQL::BOOLEAN_TYPE, method: :public_builds, null: true # rubocop:disable Graphql/Descriptions
field :open_issues_count, GraphQL::INT_TYPE, null: true, resolve: -> (project, args, ctx) do
field :open_issues_count, GraphQL::INT_TYPE, null: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions
project.open_issues_count if project.feature_available?(:issues, ctx[:current_user])
end
field :import_status, GraphQL::STRING_TYPE, null: true
field :import_status, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
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 :only_allow_merge_if_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :printing_merge_request_link_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :namespace, Types::NamespaceType, null: true
field :group, Types::GroupType, null: true
field :namespace, Types::NamespaceType, null: true # rubocop:disable Graphql/Descriptions
field :group, Types::GroupType, null: true # rubocop:disable Graphql/Descriptions
field :statistics, Types::ProjectStatisticsType,
field :statistics, Types::ProjectStatisticsType, # rubocop:disable Graphql/Descriptions
null: true,
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchProjectStatisticsLoader.new(obj.id).find }
field :repository, Types::RepositoryType, null: true
field :repository, Types::RepositoryType, null: true # rubocop:disable Graphql/Descriptions
field :merge_requests,
field :merge_requests, # rubocop:disable Graphql/Descriptions
Types::MergeRequestType.connection_type,
null: true,
resolver: Resolvers::MergeRequestsResolver
field :merge_request,
field :merge_request, # rubocop:disable Graphql/Descriptions
Types::MergeRequestType,
null: true,
resolver: Resolvers::MergeRequestsResolver.single
field :issues,
field :issues, # rubocop:disable Graphql/Descriptions
Types::IssueType.connection_type,
null: true,
resolver: Resolvers::IssuesResolver
field :issue,
field :issue, # rubocop:disable Graphql/Descriptions
Types::IssueType,
null: true,
resolver: Resolvers::IssuesResolver.single
field :pipelines,
field :pipelines, # rubocop:disable Graphql/Descriptions
Types::Ci::PipelineType.connection_type,
null: true,
resolver: Resolvers::ProjectPipelinesResolver
......
......@@ -24,6 +24,6 @@ module Types
resolver: Resolvers::MetadataResolver,
description: 'Metadata about GitLab'
field :echo, GraphQL::STRING_TYPE, null: false, resolver: Resolvers::EchoResolver
field :echo, GraphQL::STRING_TYPE, null: false, resolver: Resolvers::EchoResolver # rubocop:disable Graphql/Descriptions
end
end
......@@ -6,9 +6,9 @@ module Types
authorize :download_code
field :root_ref, GraphQL::STRING_TYPE, null: true, calls_gitaly: true
field :empty, GraphQL::BOOLEAN_TYPE, null: false, method: :empty?, calls_gitaly: true
field :exists, GraphQL::BOOLEAN_TYPE, null: false, method: :exists?
field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver, calls_gitaly: true
field :root_ref, GraphQL::STRING_TYPE, null: true, calls_gitaly: true # rubocop:disable Graphql/Descriptions
field :empty, GraphQL::BOOLEAN_TYPE, null: false, method: :empty?, calls_gitaly: true # rubocop:disable Graphql/Descriptions
field :exists, GraphQL::BOOLEAN_TYPE, null: false, method: :exists? # rubocop:disable Graphql/Descriptions
field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver, calls_gitaly: true # rubocop:disable Graphql/Descriptions
end
end
......@@ -8,8 +8,8 @@ module Types
graphql_name 'TaskCompletionStatus'
description 'Completion status of tasks'
field :count, GraphQL::INT_TYPE, null: false
field :completed_count, GraphQL::INT_TYPE, null: false
field :count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :completed_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
end
# rubocop: enable Graphql/AuthorizeTypes
end
......@@ -10,8 +10,8 @@ module Types
graphql_name 'Blob'
field :web_url, GraphQL::STRING_TYPE, null: true
field :lfs_oid, GraphQL::STRING_TYPE, null: true, resolve: -> (blob, args, ctx) do
field :web_url, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :lfs_oid, GraphQL::STRING_TYPE, null: true, resolve: -> (blob, args, ctx) do # rubocop:disable Graphql/Descriptions
Gitlab::Graphql::Loaders::BatchLfsOidLoader.new(blob.repository, blob.id).find
end
# rubocop: enable Graphql/AuthorizeTypes
......
......@@ -4,11 +4,11 @@ module Types
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
field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :type, Tree::TypeEnum, null: false # rubocop:disable Graphql/Descriptions
field :path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :flat_path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
end
end
end
......@@ -8,8 +8,8 @@ module Types
graphql_name 'Submodule'
field :web_url, type: GraphQL::STRING_TYPE, null: true
field :tree_url, type: GraphQL::STRING_TYPE, null: true
field :web_url, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :tree_url, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
end
# rubocop: enable Graphql/AuthorizeTypes
end
......
......@@ -11,7 +11,7 @@ module Types
graphql_name 'TreeEntry'
description 'Represents a directory'
field :web_url, GraphQL::STRING_TYPE, null: true
field :web_url, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
end
# rubocop: enable Graphql/AuthorizeTypes
end
......
......@@ -7,19 +7,21 @@ module Types
graphql_name 'Tree'
# Complexity 10 as it triggers a Gitaly call on each render
field :last_commit, Types::CommitType, null: true, complexity: 10, calls_gitaly: true, resolve: -> (tree, args, ctx) do
field :last_commit, Types::CommitType, null: true, complexity: 10, calls_gitaly: true, resolve: -> (tree, args, ctx) do # rubocop:disable Graphql/Descriptions
tree.repository.last_commit_for_path(tree.sha, tree.path)
end
field :trees, Types::Tree::TreeEntryType.connection_type, null: false, resolve: -> (obj, args, ctx) do
field :trees, Types::Tree::TreeEntryType.connection_type, null: false, resolve: -> (obj, args, ctx) do # rubocop:disable Graphql/Descriptions
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.trees, obj.repository)
end
# rubocop:disable Graphql/Descriptions
field :submodules, Types::Tree::SubmoduleType.connection_type, null: false, calls_gitaly: true, resolve: -> (obj, args, ctx) do
Gitlab::Graphql::Representation::SubmoduleTreeEntry.decorate(obj.submodules, obj)
end
# rubocop:enable Graphql/Descriptions
field :blobs, Types::Tree::BlobType.connection_type, null: false, calls_gitaly: true, resolve: -> (obj, args, ctx) do
field :blobs, Types::Tree::BlobType.connection_type, null: false, calls_gitaly: true, resolve: -> (obj, args, ctx) do # rubocop:disable Graphql/Descriptions
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.blobs, obj.repository)
end
# rubocop: enable Graphql/AuthorizeTypes
......
......@@ -8,9 +8,9 @@ module Types
present_using UserPresenter
field :name, GraphQL::STRING_TYPE, null: false
field :username, GraphQL::STRING_TYPE, null: false
field :avatar_url, GraphQL::STRING_TYPE, null: false
field :web_url, GraphQL::STRING_TYPE, null: false
field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :username, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :avatar_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :web_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
end
end
......@@ -7,12 +7,12 @@ module RuboCop
MSG = 'Add an `authorize :ability` call to the type: '\
'https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#type-authorization'
TYPES_DIR = 'app/graphql/types'
# We want to exclude our own basetypes and scalars
WHITELISTED_TYPES = %w[BaseEnum BaseScalar BasePermissionType MutationType
QueryType GraphQL::Schema BaseUnion].freeze
TYPES_DIR = 'app/graphql/types'
def_node_search :authorize?, <<~PATTERN
(send nil? :authorize ...)
PATTERN
......@@ -44,7 +44,7 @@ module RuboCop
end
def superclass_constant(class_node)
# First one is the class name itself, second is it's superclass
# First one is the class name itself, second is its superclass
_class_constant, *others = class_node.descendants
others.find { |node| node.const_type? && node&.const_name != 'Types' }
......
# frozen_string_literal: true
# This cop checks for missing GraphQL field descriptions.
#
# @example
#
# # bad
# class AwfulClass
# field :some_field, GraphQL::STRING_TYPE
# end
#
# class TerribleClass
# argument :some_argument, GraphQL::STRING_TYPE
# end
#
# # good
# class GreatClass
# argument :some_field,
# GraphQL::STRING_TYPE,
# description: "Well described - a superb description"
#
# field :some_field,
# GraphQL::STRING_TYPE,
# description: "A thorough and compelling description"
# end
module RuboCop
module Cop
module Graphql
class Descriptions < RuboCop::Cop::Cop
MSG = 'Please add a `description` property.'
# ability_field and permission_field set a default description.
def_node_matcher :fields, <<~PATTERN
(send nil? :field $...)
PATTERN
def_node_matcher :arguments, <<~PATTERN
(send nil? :argument $...)
PATTERN
def_node_matcher :has_description?, <<~PATTERN
(hash <(pair (sym :description) _) ...>)
PATTERN
def on_send(node)
matches = fields(node) || arguments(node)
return if matches.nil?
add_offense(node, location: :expression) unless has_description?(matches.last)
end
end
end
end
end
# frozen_string_literal: true
module RuboCop
module GraphqlHelpers
TYPES_DIR = 'app/graphql/types'
def in_type?(node)
path = node.location.expression.source_buffer.name
path.include?(TYPES_DIR)
end
end
end
......@@ -49,3 +49,4 @@ require_relative 'cop/code_reuse/active_record'
require_relative 'cop/group_public_or_visible_to_user'
require_relative 'cop/inject_enterprise_edition_module'
require_relative 'cop/graphql/authorize_types'
require_relative 'cop/graphql/descriptions'
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop'
require 'rubocop/rspec/support'
require_relative '../../../../rubocop/cop/graphql/descriptions'
describe RuboCop::Cop::Graphql::Descriptions do
include RuboCop::RSpec::ExpectOffense
include CopHelper
subject(:cop) { described_class.new }
context 'fields' do
it 'adds an offense when there is no field description' do
inspect_source(<<~TYPE)
module Types
class FakeType < BaseObject
field :a_thing,
GraphQL::STRING_TYPE,
null: false
end
end
TYPE
expect(cop.offenses.size).to eq 1
end
it 'does not add an offense for fields with a description' do
expect_no_offenses(<<~TYPE.strip)
module Types
class FakeType < BaseObject
graphql_name 'FakeTypeName'
argument :a_thing,
GraphQL::STRING_TYPE,
null: false,
description: 'A descriptive description'
end
end
TYPE
end
end
context 'arguments' do
it 'adds an offense when there is no argument description' do
inspect_source(<<~TYPE)
module Types
class FakeType < BaseObject
argument :a_thing,
GraphQL::STRING_TYPE,
null: false
end
end
TYPE
expect(cop.offenses.size).to eq 1
end
it 'does not add an offense for arguments with a description' do
expect_no_offenses(<<~TYPE.strip)
module Types
class FakeType < BaseObject
graphql_name 'FakeTypeName'
argument :a_thing,
GraphQL::STRING_TYPE,
null: false,
description: 'Behold! A description'
end
end
TYPE
end
end
end
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